
MTG가 끝나면 AI가 Next Action을 자동으로 실행하도록 만들었습니다
요약
회의 종료 후 발생하는 Next Action을 자동으로 Notion에 기록하고, 실행 가능한 분석 업무를 AI 에이전트가 수행하도록 하는 파이프라인 구축 사례를 소개합니다. Circleback의 webhook을 활용하여 Slack 인터페이스를 통해 클릭 한 번으로 데이터 분석 및 리포팅을 자동화합니다.
핵심 포인트
- Circleback의 webhook을 활용한 미팅 액션 아이템 추출 및 연동
- Notion과 Slack을 결합한 업무 자동화 워크플로우 구축
- 데이터 분석 및 요인 분석 등 복잡한 태스크의 자동 실행 구현
- 업무 흐름을 방해하지 않는 '컷인 업무'의 효율적 처리
서론
7garden에서 DX 책임자를 맡고 있는 daiki입니다.
저희 회사는 호텔 기획·개발·운영을 수행하는 회사로, 저는 최근 마케팅 팀의 리드를 맡으면서 병행하여 엔지니어로서 AI 추진 및 개발을 하고 있습니다. 그 과정에서 건물 수 확대를 고려한 생산성 향상을 실현하기 위해, "마케짱"이라는 AI 에이전트 개발을 진행하고 있습니다.

이것이 마케짱의 아이콘입니다. 지금까지 Slack이나 Notion과 같은 인터페이스를 중심으로, 복잡한 데이터 분석이나 리포팅 자동화와 같은 기능을 추가해 왔습니다. 이번에는 이 마케짱의 확장으로서, "MTG가 끝나면, Next Action(다음 조치)이 자동으로 Notion에 기표되고, 실행 가능한 것은 수치 확인이나 요인 분석까지 (노력 면에서) 거의 0코스트로 자동 실행되는" 상태를 목표로 한 파이프라인을 구축한 이야기를 쓰고자 합니다.
배경
저희 마케팅 팀에서는 매주 정기 MTG에서 다수의 "Next Action (이하 NA)"이 논의됩니다. 모든 운영 시설이 논의 범위가 되기 때문에 절대적인 양이 많은 한편, 논의 흐름 속에서 나오는 "살아있는" 논점이 많습니다. 예를 들어 "어떤 시설에서 가격 변경 후 예약이 늘어나기 시작했는데, 이것이 가격 변경의 효과인지 계절적 요인인지 구분하여 분석한다", "다른 시설에서 한국인 게스트가 줄고 대만·일본인이 늘고 있는데, 이것이 자사의 프로모션施策(시책) 영향인지 시장 측의 변화인지 분석한다"와 같이, 그 자리의 문맥에 강하게 결부된 "즉시 움직이고 싶은" 종류의 것들입니다.
호텔 마케팅은 미래의 예약까지 항상 숫자가 계속 움직이는 성질상, 이러한 NA는 신선도를 유지하며 실행하여 팀에 공유하고, 다음 대응책까지 연결하는 것을 세트로 진행하는 것이 중요합니다. 판단이 1~2일 늦어지는 것만으로도 대상 기간의 숫자나 대응책의 효과가 달라질 수 있습니다.
한편, NA의 수행은 멤버들에게 명확한 **「컷인 업무 (Cut-in Task)」**이기도 합니다. 당초 예정했던 태스크 수행을 압박하기 때문에, 방치하면 PDCA는 멈추고, 그 자리에서 전부 처리하면 예정된 태스크가 밀려나는 딜레마가 일상적으로 발생하고 있었습니다. "논의에서 나온다 → Notion에 기표한다 → 실시한다 → 결과를 팀에 공유한다"의 사이클을, 손을 최대한 멈추지 않으면서 높은 신선도로 돌리고 싶다는 갈등이 있었습니다.
전제로 하나 더 말씀드리면, 저희 회사는 AI 회의록 서비스인 Circleback을 도입하고 있습니다. 미팅은 Google Meet을 사용하고 있지만, Circleback은 온라인 MTG에 대해 회의록이나 Action Item을 자동으로 추출해 주는 도구로, 추출 결과를 webhook으로 외부 시스템에 전송할 수 있습니다. 이번 파이프라인은 이 webhook을 기점으로 구축했습니다.
마케팅 팀의 경험
이상적인 모습은 단순합니다. MTG가 끝나고 자리로 돌아올 때쯤에는, 회의록에서 생성된 티켓이 Notion에 나열되어 있고, 자동 실행에 적합한 것은 Slack에 "자동 실행 후보"로 도착해 있는 상태입니다. 멤버는 그 Slack 메시지의 버튼을 클릭 한 번 하는 것만으로 실행이 시작되며, 결과는 스레드 답장으로 돌아옵니다.
▼ MTG 종료 후 도착하는 메시지 예시

실제 시설명이나 수치를 포함하고 있어 일부 마스킹 처리했습니다.
멤버에게 보이는 흐름을 시계열로 나열하면 다음과 같습니다.
| 타이밍 | 일어나는 일 |
|---|---|
| MTG 종료 직후 | Circleback이 회의록에서 NA를 추출하여 webhook으로 전송 |
| ... |
체감상으로는 『Slack을 확인하면 자동 실행 가능한 NA가 나열되어 있고, 「실행」 버튼을 클릭한 것만 돌아간다』는 이미지입니다.
서두에 "거의 0코스트"라고 적은 것은 멤버의 손이 거의 가지 않는다는 의미입니다. 지금까지 수작업이었던 "티켓을 기표한다", "수치를 확인·분석한다", "결과를 팀에 공유한다"라는 일련의 공정이 버튼 클릭 한 번으로 대체됩니다. 팀 공유도 결과 메시지의 스레드에서 공유하고 싶은 상대를 멘션하는 것만으로 끝나는데, 이는 사소하지만 효과적인 포인트입니다.
나아가, 실행 결과 스레드 내에서 마케짱을 멘션하면, 해당 티켓의 문맥을 유지한 채 추가 분석이나 궤도 수정을 요청할 수 있습니다. "자동 실행으로 나온 결과 중, 궁금한 관점만 그대로 심층 분석한다"라는 움직임도 동일한 스레드 상에서 완결됩니다.
처음에는 버튼이 없는 완전 자동 파이프라인이었다
여기까지 읽으셨다면 "굳이 사람이 버튼을 누르게 할 필요 없이, 티켓 생성부터 실행까지 한 번에 자동화하면 되지 않을까?"라고 생각하실지도 모르겠습니다. 사실 초기 구현 단계에서는 이 버튼이 존재하지 않았습니다. 생성된 티켓을 그대로 실행까지 흘려보내는 완전 자동 파이프라인으로 만들기 시작했습니다.
당시에는 토큰 비용(Token Cost) 관점을 고려하고 있었습니다. 생성된 티켓을 전부 실행으로 돌리면, 한 번의 MTG(회의)당 수십 개의 분석 에이전트(Analysis Agent)가 돌아가게 되어 비용 측면에서 현실적이지 않기 때문입니다. 그래서 "자동 실행 우선순위"를 LLM이 판단하게 하여, 우선순위가 높은 것들만 실행으로 넘기는 설계를 했습니다. 여기까지는 순조로워 보였습니다.
하지만 실제 MTG에서 시운전을 해보니 위화감이 느껴졌습니다. 이 MTG에는 저 자신이 퍼실리테이터(Facilitator)로 참여하는데, "이번 주는 이 테마에 집중하고 싶다"라거나 "이 수치가 궁금하다"라는 식의 온도감이 남아있는 상태에서 자동 실행된 결과물을 보면, "어라, 방금 자동 실행되길 바랐던 건 이게 아닌데"라고 느껴지는 순간이 있었습니다. LLM이 "우선순위가 높다"라고 선택하는 티켓과, 논의를 거친 팀이 "이것을 실행해 주길" 바라는 티켓이 맞물리지 않았던 것입니다. Circleback에서 추출된 회의록 텍스트만으로는 논의의 온도감이나 "이번 주는 여기가 승부처다"와 같은 팀의 맥락(Context)까지 담기지 않기 때문입니다.
이 괴리를 바탕으로 내린 결론이, 판정은 "실행 후보의 필터링"으로 역할을 한정하고, 최종 트리거(Trigger)는 인간의 Slack 버튼에 맡긴다는 현재의 형태입니다. Slack 알림은 마케팅 팀이 일상적으로 확인하는 채널로 흐르기 때문에, 버튼을 한 번 클릭하는 수고는 거의 신경 쓰이지 않을 것이라는 사전 논의도 있었습니다. 게다가 실제로 만들어 보니, "어떤 티켓을 누가 실행시켰는가"라는 정보 자체가 팀 내의 맥락으로서 공유되는 부수적인 효과도 있었습니다. 스레드를 살펴보면 "누가, 어떤 의도로, 어떤 티켓을 실행했는지"를 알 수 있기 때문에, 최종적인 시책 의사결정에 이르는 논의도 진행하기 쉽다는 장점을 느끼고 있습니다.
전체 아키텍처
위의 재설계를 거쳐 최종적으로 구축한 파이프라인의 전체 모습입니다.

주요 기술 스택은 다음과 같습니다.
| 항목 | 내용 |
|---|---|
| LLM | Claude Haiku 4.5 (분류·판정) / Claude Sonnet 4.6 (심층 분석) |
| ... |
"회의록 추출 → 티켓 생성 → 실행 여부 판정 → 실행"의 각 단계를 EventBridge로 연결하고, "실행 여부 판정"과 "실행" 사이에 Slack 상에서 Human in the Loop (이하 HITL)를 끼워 넣도록 구성했습니다.
판정과 실행을 별도의 EventBridge와 별도의 핸들러(Handler)로 나눈 이유는 두 가지가 독립된 스테이지이기 때문입니다. 느슨한 결합(Loosely Coupled) 상태로 두면 재실행이나 처리 삽입을 통한 확장성도 높아진다는 의도입니다. 앞 장에서 언급한 HITL도 바로 이 "나누어져 있는 사이"에 끼워 넣은 형태입니다. 구현 측면에서는 판정은 Claude Haiku 4.5를 한 번의 턴(Turn)으로 저렴하게 구동하고, 실행은 Claude Sonnet 4.6으로 여러 도구(Tool)를 호출하는 무거운 처리로 실행하고 있습니다.
여담이지만, Circleback에는 "Insights"라고 불리는 기능이 있어, MTG 종료 시의 회의록 추출 과정에서 커스텀 프롬프트(Custom Prompt)나 구조화된 출력(Structured Output)을 지정할 수 있습니다. 이 기능을 알았을 때 "이것은 회의록 서비스인 동시에, 모든 자동화 파이프라인의 기점으로 사용할 수 있다"라고 느낀 것이 Circleback 도입의 결정적 계기였습니다. 현재 자동 실행할 수 있는 것은 수치 확인 및 데이터 분석 범위의 티켓이지만, 향후에는 마케팅의 핵심 업무 중 하나인 판매 가격 조정(="Pricing 업무")까지 자동 실행에 포함하고 싶습니다.
지금부터는 위 그림의 파이프라인을 처리 순서대로 따라가 보겠습니다.
1. 결정론적으로 판정 대상 압축하기
첫 번째 단계는 Circleback에서 구조화된 출력으로 추출된 티켓 중 "판정을 거칠 것"을 추려내는 것입니다.
전제로, Circleback에서 추출되는 티켓은 앞서 언급한 Insights 기능의 구조화된 출력을 통해 태스크 카테고리(분석, 확인, 프로모션, 리포팅, 프라이싱 등)가 부여되도록 설정되어 있습니다. 현 단계에서는 이 태스크 카테고리 중에는 LLM 판정을 도입할 필요도 없이 실행이 불가능한 것들이 존재합니다. 그것들을 사전에 결정론적으로 제외함으로써 불필요한 토큰 비용 발생을 방지하고, 명백히 실행 불가능한 것이 실행 가능하다고 오판될 가능성을 배제하고 있습니다.
구체적으로는, Circleback 파이프라인에서 판정 이벤트를 발행하는 단계에서 다음과 같은 필터링을 적용하고 있습니다.
태스크 카테고리 필터링: 현재는 분석 (analysis) / 확인 (confirmation) / 리포팅 (reporting)의 3개 카테고리로 한정 (대응 카테고리는 향후 점진적으로 확대할 예정)
건수 상한: TICKET_JUDGE_AUTO_LIMIT=20으로 1 MTG당 판정 기동 건수에 상한을 설정
// 필터링 이미지
const eligible = createdTickets.filter(
(entry) =>
...
현재는 실행 상한 20건을 고정적으로 슬라이싱하고 있지만, 운영 과정에서 어떤 20건을 선택하게 할 것인가? 라는 LLM 판정을 넣는 방식 등도 검토하고 싶습니다.
2. 판정 처리: 실행 후보를 Slack으로 전송
필터링된 티켓에 대해 판정 처리가 실행됩니다. Notion 페이지의 제목과 속성(property)을 입력값으로 하여, 다음과 같은 스키마(schema)로 판정 결과를 반환합니다.
// 판정 시 LLM에 지정하는 zod 스키마
const judgeOutputSchema = z.object({
executable: z.boolean(), // 자동 실행 가능 여부
...
실행 유형은 「수치 확인 (numeric-check)」, 「요인 분석 (root-cause-analysis)」, 「인간 판단 필수 (manual-only)」의 3가지입니다. manual-only로 판정된 티켓(현 단계에서는 마케짱이 실행 불가능한 태스크)은 애초에 Slack에 올리면 노이즈가 되기 때문에, Notion에 기표된 티켓에 스킵 사유 메모를 기재한 후 종료합니다. 그 외에는 판정 결과를 전용 채널에 「실행 후보」 Slack 메시지로 게시합니다.

결과적으로, 이와 같이 Slack 상에 통지됩니다.
▼ Slack 메시지에 판정 결과를 임베드하여 전달
버튼이 눌린 후, 후술할 Slack Interactivity가 발화하며 준비된 API Gateway × Lambda로 HTTP 요청이 전송됩니다. 이 API 측에서는 판정 결과(어떤 실행 유형인지 / 어떤 시설·대상 월인지 등)가 즉시 필요합니다. 이러한 정보를 효율적으로 전달하기 위해, Slack의 message metadata 기능을 사용하여 판정 결과를 해당 메시지에 그대로 임베드(embed)하고 있습니다.
message metadata는 Slack 메시지에 임의의 구조화된 데이터(structured data)를 임베드할 수 있는 메커니즘입니다. 이번 후보 메시지에는 다음과 같은 형태의 객체(object)를 부여하고 있습니다.
// Slack의 각 메시지에 임베드하는 message metadata의 구조
{
event_type: "ticket_judge_result", // metadata의 종류 (수신 측의 디스패치용)
...
버튼이 눌리면 수신 측은 이 event_payload를 추출하여 실행 이벤트에 담기만 하면 판정 문맥을 그대로 이어받을 수 있습니다. 판정 결과를 DB 등에서 다시 가져올 필요도 없습니다. 완전히 여담이지만, 저는 이전에 LINE 공식 계정 API(= Messaging API)를 확장한 SaaS 개발을 했었습니다. 이 Messaging API에도 유사한 메커니즘이 있었기 때문에, Slack의 metadata 기능을 이용한 설계도 진행하기 수월했습니다.
3. 버튼 클릭 수신 (Slack Interactivity)

실행 후보 Slack 메시지가 올라온 후, 멤버가 이 버튼을 누르면 처리가 재개됩니다.
Slack에는 메시지 상의 버튼이 눌렸을 때 설정된 URL로 payload를 POST해 주는 Interactivity라는 메커니즘이 있습니다. 「누가 어떤 메시지의 어떤 버튼을 눌렀는가」와 앞서 언급한 message metadata가 HTTP 요청으로서 API 서버에 전달됩니다.
실행 후보 버튼 클릭 또한 이 경로를 통해 Interactivity 이벤트가 이번에 준비한 API 엔드포인트(endpoint)에 전달됩니다. 엔드포인트에서는 서명 검증 → metadata에서 판정 결과 추출 → 실행 이벤트 발행 → Lambda 기동이라는 흐름으로 진행됩니다.
// Lambda 상의 처리 (극히 일부)
try {
const result = await processSlackInteraction(parsed.data);
...
Slack의 Interactivity는 3초 이내에 응답을 반환하지 않으면 타임아웃(Timeout)되어 사용자 측에 에러가 노출되는 사양이지만, EventBridge로의 publish는 수백 ms 내에 완료되어 제한 시간 내에 여유롭게 들어오기 때문에, publish가 완료될 때까지 await한 후 응답을 반환하는 형태로 구현했습니다. 실패 사례는 서버 로그와 Langfuse를 통해 추적하고 있습니다.
학습한 내용으로서, 처음에는 3초 제한을 의식하여 티켓 자동 실행의 Event 발생을 fire-and-forget(반환값을 기다리지 않고 void로 버리는 방식)으로 처리했습니다. 그런데 실제 Slack 상에서 동작을 확인했을 때, 버튼을 눌러도 실행 이벤트가 발생하지 않는 경우가 있었습니다. Lambda는 HTTP 응답을 반환한 시점에 실행 환경이 동결(Freeze)되기 때문에, fire-and-forget 방식으로는 EventBridge로의 이벤트 발행이 완료되기 전에 처리가 중단되어 버리는 것이 원인이었습니다. Lambda 상에서 HTTP 서버를 구동할 때는 중요한 처리를 응답 전에 확정 짓는 것이 안전하다는 교훈을 얻었습니다.
▼ 보충 프롬프트를 붙여서 실행하기

후보 메시지에는 「▶ 그대로 실행」뿐만 아니라 「📝 보충하여 실행」 버튼도 마련되어 있습니다. 후자는 클릭하면 모달(Modal)이 열리며, 추가 프롬프트(「○○의 관점에서 봐줬으면 좋겠어」, 「△△를 고려해서」 등)를 작성하여 실행 단계로 넘길 수 있습니다. 판정 결과를 그대로 사용할 수 있는 케이스는 전자로, 의도를 조금 더 추가하고 싶은 케이스는 후자로 구분하여 사용하는 것을 상정하고 있습니다.
4. 실행 처리: 수치 확인 및 요인 분석
버튼 클릭으로 발행된 실행 이벤트를 받아 실행 처리가 돌아갑니다. 판정 결과의 executionType에 따라 두 종류의 에이전트(Agent)를 구분하여 사용합니다.
| 종류 | 용도 | 모델 |
|---|---|---|
| 수치 확인 (numeric-check) | 수치·KPI 현황 확인 계열 | Claude Haiku 4.5 |
| 요인 분석 (root-cause-analysis) | 「왜」, 「원인」을 심층 분석 | Claude Sonnet 4.6 |
실행이 완료되면 결과는 원래의 Slack 메시지에 대한 스레드(Thread) 답글로 게시됩니다. 판정 → 실행 → 결과의 문맥이 Slack 스레드 단위로 정리되므로, 나중에 되돌아볼 때 추적이 용이합니다.
또한, 실행 시의 세션 ID(Session ID)를 해당 스레드에 연결해 두었기 때문에, 나중에 스레드 내에서 마케짱(マーケちゃん)을 멘션하여 추가 분석이나 궤도 수정을 요청할 때도 티켓의 문맥을 유지한 채로 심층 분석을 이어갈 수 있도록 설계했습니다.
마치며
최종적으로 목표하는 것은 **호텔 마케팅의 「자율 주행화」**이며, 본 기능은 이를 구성하는 요소 중 하나로 보고 있습니다. 향후 과제는 기존 기능의 정밀도를 떨어뜨리지 않으면서, 자동 실행 가능한 영역을 넓혀가는 것입니다. 현재 자동 실행 대상은 분석 / 확인 / 레포팅의 3개 카테고리뿐이지만, 프로모션 / 프라이싱과 같이 전략에 직접적으로 관여하는 카테고리도 안전하게 자동화할 수 있는 범위부터 점진적으로 넓혀갈 예정입니다.
저희 회사에서는 이러한 「호텔 × AI」를 강화하기 위해 엔지니어와 마케터 동료를 적극 채용 중입니다! 조금이라도 관심이 생기신 분은 우선 캐주얼하게 이야기 나누어 보아요.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기