회고를 돕는 AI 매니저 ‘기록모아 구르미’ 슬랙봇이 만들어지기까지

“여러분의 회고는 항상 좋은 경험이었나요?”

‘지나간 일을 돌이켜 생각함’이라는 회고의 간단한 사전 뜻과 달리 가끔은 돌이켜 생각하는 것부터 막막할 때가 있습니다. 3주마다 스프린트 회고가 다가오면, “회고록 채워주세요”라는 슬랙 메시지를 보며 “아, 저번에 말하려고 했던 게 있는데…”라고 생각만 하다가 결국, 기억해 내지 못한 이야기를 채우지 못한 적이 한두 번이 아닙니다.

저희 팀 레전드 트리오는 사내 해커톤 9oormthon RAID Winter(이하 구름톤 레이드)를 기회로 삼아 이러한 회고의 막막함을 다양한 기술을 활용해 풀어내 보았습니다. 

회고에 대한 소소한 고민이 어떻게 ‘기록모아 구르미’라는 슬랙 봇을 탄생시켰는지 그 이야기를 지금부터 들려드리겠습니다.

written by Roah, Wynter, Dominik
edited by snow, somma


레전드 트리오팀 3인

로아_ 안녕하세요. 구름 SRE 스쿼드에서 인프라 엔지니어로 근무 중인 로아Roah입니다. 지난 여름 첫 사내 해커톤인 구름톤 레이드 참여 경험이 너무 좋았어서 두 번째 해커톤에도 고민 없이 개발자로 참여했습니다. 이번 구름톤 레이드에서도 생성형 AI를 잘 활용해 구르미들이 평소 어렵게 생각하던 부분을 해소할 만한 제품을 만들어보고 싶어 참여했습니다.

윈터_ 안녕하세요. 저는 21년에 IDE SQD에 ICT 인턴으로 입사해 현재는 만 2년차 풀스택 개발자가 된 윈터Wynter입니다. 에스파 윈터 님과는 철자가 다릅니다. 언젠가 한 번쯤 해커톤에 나가고 싶었는데, 좋은 기회가 있어 기쁜 마음으로 참가했습니다. 이번 구름톤 레이드에서 슬랙봇 백엔드 개발 조금, Node.js 개발 조금, 파이썬 개발 조금씩 세 다리를 걸쳐봤습니다.

도미닉_ 안녕하세요, 저는 구름톤 인 제주9oormthon in Jeju 7기 참가자로 구름을 처음 만나 3개월째 즐겁게 인턴 생활 중인 도미닉Dominik입니다. 구름톤 인 제주 말고도 구름톤 레이드에서도 좋은 결과를 얻어 너무너무 행복합니다. 이번 구름톤 레이드에서는 기획, 파이썬 개발을 조금씩(?) 담당했습니다.

▲(왼쪽부터) 윈터(Wynter), 도미닉(Dominick), 로아(Roah)

구름에는 회고 문화가 잘 정착되어 있습니다. 회고에서 스프린트 기간 동안 구성원이 어떤 역할을 했는지, 잘한 점은 무엇이고 개선할 부분은 어디인지 함께 모여 머리를 맞대는 것으로도 생산성 향상뿐만 아니라 구르미들이 ‘우리’로 거듭날 수 있는 소중한 시간이 되고 있습니다.

회고를 회고하다

하지만 회고는 쉽지 않습니다. 우리 모두 여러 어려움을 겪고 있죠. 저희 팀이 회고 주제 선정 과정에서 분석한 문제점 중 하나는 시간에 따른 편향성입니다. 명확한 기록이 아니라 그때그때의 기억에 의존해 회고 주제를 떠올리다보니, 비교적 최근에 일어난 일에만 더욱 집중하여 훑어보는 경향이 있었습니다.

또한 회고 관련 문서 작성이 번거롭다는 점도 페인 포인트pain point였습니다. 아무리 회고 문화가 좋다고 하더라도, 이 문화가 번거로운 추가 업무로 이어지게 된다면 이를 유지하기는 어려울 것입니다. 조직이 수행한 업무를 복기하면서 문서를 작성하는 과정이 귀찮지 않도록, 이를 도와줄 수 있는 똑똑한 도우미가 필요했습니다.

마지막으로 구성원이 아닌 관리자 입장에서도 조직이 수행한 과업을 마치 대시보드와 같이 한눈에 파악할 수 있는 도구가 필요했습니다. 지금까지는 각 구성원에게 스프린트 기간 동안 진행한 업무를 요약 정리해 달라고 요청해야 했습니다. 그러나 현실적으로 업무가 바빠 유의미한 문서로 정리하기 힘들었습니다. 이러한 요구 또한 이번에 함께 해결하고 싶었습니다.

이러한 여러 문제를 해결하기 위해서는, 회고의 편리성을 제고시켜 회고 문화 정착을 도울 슬랙봇이 필요하다는 데 팀의 의견이 모아졌습니다. 시간에 따른 편향성은 스프린트 기간 전체에 걸쳐 이루어진 슬랙 대화를 훑어보는 방식으로, 회고 관련 문서 작성 및 요약 정리는 생성형 AI를 활용하면 해결할 수 있어 보였습니다.

회고를 도와주는 회고 매니저를 만들다

이런 고민을 담아 만든 서비스가 ‘기록모아 구르미’입니다. 기록모아 구르미는 회고를 도와주는 회고 매니저로, 슬랙 채널에서 스프린트 기간 동안의 기록들을 바탕으로 최다 빈출(자주 나오는) 키워드와 대화 내역을 분석해 3개의 회고 주제를 추천해줍니다. 회고가 더 생산적이 되도록 기록모아 구르미가 돕는거죠.

사용법은 간단합니다. 슬랙 채널에서 /기록을모아주세요 를 입력하고 잠깐 기다리면 AI가 추천한 회고 주제를 받을 수 있습니다.

▲ 기록모아 구르미 동작 모습

동작 방식은 이렇습니다

기록모아 구르미는 Express.js와 플라스크Flask 두 서버로 동작합니다. 

가장 처음 사용자 /명령어slash commands를 받은 Express 서버는 채널 정보와 함께 플라스크 서버에 데이터 처리를 요청합니다. 이와 동시에 슬랙의 메시지 타임아웃Timeout 오류를 방지하기 위해 사용자에게 잠깐의 시간이 소요된다는 응답값을 전송합니다.

▲기록모아 구르미 다이어그램

플라스크 서버는 채널 정보를 바탕으로 슬랙 API를 사용해 현재 스프린트의 전체 메시지 데이터를 받아옵니다. 받아온 메시지에서 자연어 처리 함수로 명사를 추출하고 이어서 최다 빈출 단어와 해당 단어가 포함된 문장을 추출합니다. 추출한 데이터는 슬랙 채널, 스프린트 정보와 함께 MongoDB 데이터베이스에 적재합니다.

데이터 처리 완료 응답을 받은 Express.js 서버는 데이터베이스에서 최다 빈출 단어와 문장을 조회합니다. 조회한 데이터를 기반으로 GPT 프롬프트를 작성하고 회고 주제 추천을 요청합니다.

마지막으로 GPT 요청 결과를 다시 슬랙 채널로 전송하면 모든 동작이 완료됩니다.

어떤 점에 신경 썼냐고요?

  1. 데이터 전처리

슬랙에서 주고받은 대화는 한 조직이 스프린트 기간 내에 어떠한 과업을 중점적으로 수행했는지를 가늠할 수 있는 지표가 될 수 있습니다. 가령, A라는 키워드가 스프린트 기간 내에 자주 언급되었다면 A와 관련된 주제가 회고 안건으로 적절하다고 볼 수 있을 것입니다.

그러기 위해서는 슬랙 채널 내의 스레드뿐 아니라 댓글이 많이 달린 스레드의 경우 답글까지, 최대한 많은 문장을 추출해야 했습니다. 아쉽게도 여러 가지 제약조건으로 인해 모든 스레드와 모든 답글을 확인할 수는 없었습니다. 짧은 해커톤 기간 내에 최소 기능 제품Minimum Viable Product, MVP 구현을 위해서 불가피한 선택이었습니다.

추출한 데이터는 KoNLPy의 Okt를 활용해 품사를 태깅한 후, 명사만 따로 추출했습니다. 문장형 데이터의 경우 가공이 쉽지 않아서 필요한 데이터만을 추출하는 검색 키로 활용하기 위함이었습니다.

이후 추출한 명사를 빈도순으로 나열한 뒤, 빈도가 높은 명사부터 차례대로 다시 해당 명사를 포함하는 문장들을 거슬러 올라가 탐색했습니다. 가령, 어떤 채널에서 ‘크레딧’이라는 키워드가 특징적으로 빈출됐다면 이를 포함하는 모든 문장을 저장했습니다.

def user_freq_extract(messages_json2):
   extract_raw = json_data(messages_json2)
   user_list = list(extract_raw.keys())


   user_freq_dict = {}
   okt = Okt()


   for user in user_list:
       user_freq_dict[user] = Counter() 


       for POS_sentence in extract_raw[user]:
           words = okt.nouns(POS_sentence)
           word_frequencies = Counter(words)


           user_freq_dict[user] += word_frequencies


   return user_freq_dict

▲ Okt를 활용한 품사 태깅, 단어 빈도수 구하기 예시 코드

2. 데이터 to GPT to 슬랙

이러한 과정을 거쳐 확보한 문장 데이터는 GPT로 보냅니다. GPT에게는 ‘회고 매니저’라는 가상의 페르소나Persona를 설정했습니다. 입력받은 문장에서 유의미한 회고 주제를 추천하도록 프롬프트 엔지니어링을 진행했습니다.

영문도 모르고 연동이 안 되는 OpenAI의 GPT API, 대놓고 쓰여진 프롬프트를 무시하는 GPT의 추태 등 저희 팀의 속을 박박 긁어놓는 어려움도 있었습니다. 이 과정에서 GPT 프롬프트의 중요성을 크게 느꼈습니다. 

처음에는 단순히 최다 빈출 키워드와 연관된 대화 내용을 분석해서 회고 내용을 작성해 달라고 프롬프트를 작성했습니다. 이렇게 추상적으로 프롬프트를 작성하니 GPT 답변이 들쑥날쑥하고, 분석용으로 제공한 키워드, 대화를 다시 답변하는 등 불필요한 데이터가 포함되었습니다. 

이에 대한 해결책으로 프롬프트를 조금씩 단계적으로 구체화하고, GPT에게 구름의 회고 매니저라는 역할role을 부여했습니다. 

exports.getSystemRoleTemplate = () => `
    너는 이제부터 우리 팀의 회고를 도와  회고 매니저야
    주어지는 슬랙 대화 내용과 키워드를 분석해서 회고 주제를 만들어주는 역할이야
`;

exports.getMessageTemplate = (keyword, sentences) =>`
    ... 중략
    이제 아래 나온 최다 빈출 키워드 리스트와 키워드가 언급된 문장 리스트를 종합해서 회고 주제 3개를 정하고 출력 템플릿에 맞게 작성해줘

    최다 빈출 키워드 리스트: ${keyword}
    키워드가 언급된 문장 리스트: ${sentences}
    // 출력 형태를 직접 지정해줌
    <출력 형태 템플릿> 
    회고 주제: ''
    회고 주제에 대한 설명: ''
    
    출력 결과는  템플릿에 맞게  형태로만 3 보내줘야해
    최다 빈출 키워드 리스트와 키워드가 언급된 문장 리스트는 절대 다시 보내주지마 // 불필요한 데이터 제거 요청
`;

▲ 템플릿 예시 코드

이처럼 GPT에게 맥락 설명을 위해 자세한 역할을 부여했고, GPT가 출력해야 할 템플릿을 직접 지정한 끝에 답변이 들쑥날쑥했던 문제를 해결할 수 있었습니다.

또한, 이렇게 직접 출력 템플릿을 지정해주니 슬랙에 답변 결과를 전송할 때 크게 포맷을 변경하지 않고 바로 전송할 수 있었습니다.

우리의 해커톤은 아직 끝나지 않았다

일주일간의 사내 테스트 기간 동안 기록모아 구르미를 사용한 동료들이 여러 평가를 보내주셨습니다. 긍정적인 평가뿐 아니라 개선할 점이나 우려되는 지점 등의 다양한 의견을 줘서 앞으로 나아갈 방향을 정하는 데 큰 도움이 되었습니다.

“실제로 회고 때마다 어떤 이야기를 꺼내야 할 지 어려웠는데 대화 내용을 기반으로 필요한 주제를 추천해줘서 좋아요.”

“한 스프린트에 생각보다 많은 내용이 오고가서 실제 회고 때 기억나지 않아 놓치는 부분이 많은데 이런 경우 도움이 될 것 같습니다.”

“단어와 짧은 문장이지만 슬랙 대화 내용을 공개된 AI에 보내는 것이 보안적으로 위험하지는 않을까 걱정되기도 합니다.” 

“회고 주제를 좀 더 많이 추천해주면 좋겠어요. 세 가지는 적은 것 같아요.”

사내 해커톤은 끝났지만, 우리의 해커톤은 지금도 계속되고 있습니다. 애정 어린 피드백과 MVP로 구현하며 부족했던 부분을 틈틈이 개선해 나가고 있거든요. 언젠가 전사적으로 기록모아 구르미를 회고에 사용하는 문화가 정착되기까지, 기록모아 구르미의 변화를 지켜봐주세요. ☁️


로아_ 항상 해커톤에 참여하고 나면 앞으로 더 다양한 것에 도전하고 싶은 동기를 얻어가는 것 같습니다. 처음 아이디어 회의 때 나온 회고 봇 아이디어를 듣고 핵심 기능인 대화 내용 추출, 키워드 분석이 기술적으로 무박 2일 내에 완성하기에는 스케일이 너무 크지 않나 생각했습니다. 솔직히 키워드를 분석하는 파이썬과 슬랙, GPT 등을 연결하는 Node.js를 함께 써야하는 것도 부담이었어요.

걱정과 달리 크게 다뤄보지 않은 파이썬과 플라스크flask로 뚝딱 서버를 만들고, 키워드 분석 기능을 만드는 팀원들을 보며 도전하는 자의 아름다움을 느꼈습니다. 시작도 전에 ‘어렵지 않을까’라고 지레 짐작한 제 모습이 부끄럽기도 했어요. 이번 해커톤을 기점으로 걱정할 바엔 멋지게 도전하자!는 마음가짐을 다시 한번 배울 수 있었습니다.

윈터_  저는 해커톤 참여를 결심하기까지 걱정이 참 많았습니다. 체력, 실력, 환경 등 해커톤에 참여한다는 것이 제게는 일종의 도전이었어요. 실제로 걱정했던 부분이 난관으로 다가오기도 했습니다. 그래도 도전하는 과정에서 개발에 대한 흥미를 다시 느낄 수 있었습니다. 개발을 처음 배울 때처럼, 새로운 언어를 사용할 때의 막막함을 느끼기도 하고, 잘 동작하는 결과물을 볼 때의 ‘즐거움’을 다시 깨달았거든요. 앞으로의 개발 생활을 이어가는 데 원동력을 얻은 게 가장 큰 성과가 아닐까 스스로 생각해 봅니다.

도미닉_ 구름톤 도장 깨기를 달성한 걸까요? 구름톤 인 제주 7기 참가자였던 2022년만 해도 구름에서 인턴을 할 줄도, 사내 해커톤 ‘구름톤’에 다시 참가하게 될 줄은 몰랐습니다. 사람 일은 한 치 앞도 알 수 없다는 말이 실감되네요.

원대한 야망을 가지고 기획자로 나섰지만, 시간 내에 이걸 다 구현할 수 있을지 걱정이 이만저만이 아니었습니다. 로아, 윈터 같은 뛰어난 동료가 없었다면 MVP도 구현하지 못했을 겁니다. 욕심 가득한 기획안을 실제로 구현해준 두 분께 이 자리를 빌어 인사 전합니다. 감사합니다

Posted by
roah.chae

끊임없는 의심을 통해 유연하고 생산성 있는 코드를 만들어가고자 노력하는 개발자입니다.