관심봇 개발 이야기

소소한 슬랙봇 개발 이야기: 새 업무 프로세스의 단점을 보완하기 위하여

관심봇 개발 이야기
Photo by Edi Libedinsky / Unsplash

개발 취지

회사에서 업무 커뮤니케이션 도구로 슬랙을 사용하고 있다. 채널 구성은 기본적으로 팀 단위로이며 소수의 공용 채널로 운영하고 있었다. 이 방식은 팀 단위 커뮤니케이션에는 좋지만, 기능 단위 커뮤니케이션에는 불리하다. 소수의 공용 채널에 모든 기능의 스레드가 생기니 보아야하는 스레드를 놓치는 일이 비일비재하게 발생한다.

기능 단위 커뮤니케이션을 강화하기 위해 기능 단위로 채널을 운영하는 것을 실험해보기로 하였다. 이 방식은 특정 기능에 대한 커뮤니케이션에는 유리하다. 하지만 관리자가 너무 많은 채널에 들어가있어야하는 문제가 있고, 스레드가 노출되면서 발생하는 게임디자이너(≒기획자) 간 자연스러운 논의가 축소되는 문제가 있다.

이 문제를 슬랙봇으로 해결하여 기능 단위 채널 구성의 단점을 보완해보고자 하였다.

요구조건 설정

이 문제를 해결하는 핵심은 각 기능 채널의 중요 스레드를 특정 공용 채널에 전파하는 것이다. '중요 스레드' 를 정의하는 방식은 일반적인 구분으로부터 시작해보있다.

첫째, New 에 해당하는 스레드. 모든 새로운 스레드가 공유되면 곤란하므로 어느 정도 필터링이 필요했다. 스레드가 생긴 직후 답글이 빠르게 달리는 것을 기준으로 하기로 했다. 이를 '싹트는 스레드' 라고 이름지었다.

둘째, Hot 에 해당하는 스레드. 스레드 생성 시점과 무관하게 답글이 급격히 추가되는 핫한 스레드에 해당한다. 이를 '불타는 스레드' 라고 이름지었다.

셋째, 재개되는 스레드. 작업자는 보통 스레드를 북마크해두고 논의를 이어간다. 논의가 다음날로 넘어가면 다른 사람들이 해당 이슈가 아직 진행되고 있음을 모를 수 있다. 이를 보완하기 위해 마지막 대화로부터 일정 시간 지난 스레드에 새 답글이 올라오면 외부로 알려주기로 했다. 이를 '재개된 스레드' 라고 이름지었다.

기왕 텍스트를 읽는 김에 평소에 있으면 좋겠다고 생각한 기능도 시도해보기로 했다. 바로 특정 커맨드를 치면 해당 시점까지의 스레드 내용을 요약해주는 것. 이 기능은 반드시 필요한 기능은 아니니 가볍게 시도해보기로 했다.

구현

기존에는 Real Time Messaging API 로 봇을 만들었는데, 현재는 Event API 사용을 권장하고 있으므로 새로운 방식을 학습해야했다. Slack API 문서를 보며 Jupyter Notebook 으로 필요한 API들을 테스트했다. 슬랙 Event Subscription 은 이벤트를 받을 Request URL이 필요하여 개인 서버에 도메인 세팅하고 Flask로 간단한 앱을 만들어 기능을 실험했다.

한편 스레드를 요약하는 기능도 실험을 해보았다. 여기에도 기존에 문서 요약 성능을 충분히 확인했던 카카오브레인의 PORORO를 써보기로 했다. 하지만 일반 문서와 달리 슬랙의 스레드는 요약이 효과적으로 되지 않았다. 문서는 일관된 내용으로 정리하지만, 스레드는 각자 서로 다른 의견을 내는 경우가 많기 때문. 개인 단위로 요약하는 시도를 해도, 논의하며 각자의 생각이 서로 바뀌기에 일관되게 요약되지 않았다. 스레드 요약 기능은 핵심 기능은 아니기에 나중에 재도전하기로 하고 포기했다.

개별 기능의 테스트를 마친 후, 그 내용으로 데이터 구조와 클래스를 설계하고 구현했다. 빠르게 구현한 이후 이터레이션이 필요한 부분들을 파라미터로 빼내는 식으로 작업했다.

런칭

처음 런칭하여 봇이 채널에 처음 등장했을 때 다들 신기해하셨다. 개발 취지와 작동 방식을 설명드리고 피드백을 받기 시작했다.

관심봇 초기버전

반영한 피드백

별로 핫하지 않은데 불타는 스레드라는 피드백이 있었다. 초기 파라미터를 슬랙을 보며 잡긴 했지만 실제와 다른 부분이 있었고, 매일 조금씩 수정하며 적절한 값을 찾아나갔다.

싹트는 스레드와 불타는 스레드가 역할이 겹친다는 의견이 있었다. 'm분 안에 n개의 답글'라는 동일한 조건에 숫자만 달랐기에 실제로 겹치는 부분이 많았다. 스레드들을 관찰하여 초반에 활발한 스레드는 금방 불타는 스레드의 조건에 도달하는 것을 확인할 수 있었다. 결과적으로 싹트는 스레드를 제거했다.

싹트는 스레드를 제거하는 작당 스레드

'사우론봇' 이라는 이름이 감시받는 느낌을 주어 부정적이라는 피드백이 있었다. 우리끼리는 스레드 마다 빠르게 나타나는 사람을 '사우론' 이라고 칭하는 것에서 따온 이름이기는 했다. 하지만 시스템이 스레드를 강제로 끌어올리는 개념인만큼 부정적으로 보일 수 있겠다 생각했다.

사우론봇 캐릭터에 대한 부정적 피드백

그리하여 어떤 컨셉으로 잡을까 하다가 '관심봇' 이라는 캐릭터를 부여했다. "놀라울 만큼, 그 누구도 관심을 주지 않는" 스레드가 생기지 않도록 하는 것이 이 봇의 역할이었기 때문.

출처: <개그만화 보기 좋은 날>

한편 불타는 스레드는 순간의 집중도가 높은 스레드를 찾아내기에 꾸준히 길게 논의되는 스레드를 찾지 못한다는 한계가 있었다. 그리하여 스레드의 댓글 개수가 100개 단위가 될 때 마다 알려주도록 하였다.

반영하지 않은 피드백

'ㅋ' 개수로 재미있는 이야기가 나온 스레드를 보여주자는 의견이 있었다. 업무에 있어 적절한 잡담이 중요한 것은 사실이다. 하지만 중요한 업무 정보가 흐르게 하는 것이 주요 취지인 만큼 이 기능을 구현하지는 않았다.

이벤트 발생 기준을 답글 수가 아니라 글자 수로 하면 어떻겠냐는 의견이 있었다. 런칭 초반에 불타는 스레드가 잦은 빈도로 발생했기 때문. 하지만 말을 끊어쓰는 경우가 그렇게 많지는 않았고, 불타는 스레드의 이벤트 발생 답글 개수를 늘리는 것으로 충분히 해결되어 적용하지는 않았다.

인터페이스

구상한 것을 간략히 스케치하고 Block Kit Builder 에서 테스트해보았다. 실제 사용 환경에서 공간을 너무 많이 차지하지 않도록 줄여나가는 작업을 해야했다. 긴 스레드 주소 영역을 링크로 줄이고, 스레드의 프리뷰도 제거했다.

이벤트 발생 시 보여주는 n개의 답글은 이벤트 앞부분을 보여줄지 마지막 부분을 보여줄지 고민했다. 스레드를 클릭하면 가장 먼저 보이는 것은 최신 글이므로 앞부분을 보여주는 것이 처음 생각이었다. 하지만 이벤트에 보여지는 텍스트가 궁금하여 클릭했는데 막상 전혀 다른 내용이 있으면 사용자의 기대에 반할 것이라 생각하여 후킹 텍스트와 최신 텍스트가 일치하도록 하였다.

마무리

  • 업무 방식을 변경하면 그에 맞는 도구를 빠르게 개발하는 것이 중요하다.
  • 완벽한 기획과 설계 보다는 빠르게 만들어 피드백을 받는 것이 훨씬 나음을 다시 확인했다.