카카오톡에서 헤르메스+오픈클로 Bot to Bot 구현하기 사례

같은 LLM 베이스에서 갈라져 나온 두 카카오 봇을 한 단톡방에서 토론시키고, 그 결과를 엑셀 보고서로 자동 정리해 다시 카톡에 쏘기까지.

2026-06-06, 맥미니 로컬 환경에서 하루 만에 구현·검증한 기록.


📝 한줄 요약

카카오톡 단톡방에 @토론 [주제]라고 치면 → 회계사 봇과 세무사 봇이 3턴 주고받으며 토론하고 → 토론이 끝나면 [쟁점 | 회계 관점 | 세무 관점 | 통합 결론] 비교표 엑셀 보고서가 자동으로 단톡방에 업로드됩니다.

겉보기엔 "두 AI가 카톡방에서 토론하고 보고서까지 써준다"지만, 실제 구조는 그렇게 단순하지 않습니다. 카카오의 기술적 제약 때문에 우회 설계가 필요했기 때문입니다.

실제 업무에 활용하고 있는 에이전트이기 때문에 부득이하게 정보지운점 감안해주시면 감사하겠습니다.^^

바쁘시면 이것만:

  • 카카오는 Bot-to-Bot이 안 됨 → 사회자 릴레이 + 카카오는 출력구만

  • 무한 루프는 author_id 가드 + 사회자 호출 + router 분리로 구조 차단

  • 회계·세무 기존 answer.py 재사용 → 토론 끝나면 엑셀 2시트 자동 업로드


🎯 이런 분들께 도움돼요

  • 카카오톡(LOCO)으로 멀티봇·자동화를 붙이려는 분

  • "봇끼리 대화"가 무한 루프·계정 정지로 이어질 수 있다는 걸 알고 우회 설계가 필요한 분

  • 이미 돌아가는 1:1 봇 두뇌를 단톡방 토론·보고서 파이프라인에 재사용하고 싶은 분

  • 실제 접근성 때문에 업무에서 슬랙이나 디스코드 말고 카카오톡을 써야할것 같은 분


😫 문제 상황 (Before)

LOCO 프로토콜의 벽

카카오톡은 일반 오픈 API가 아니라 LOCO라는 자체 바이너리 프로토콜로 동작합니다. 텔레그램·디스코드처럼 "봇이 다른 봇의 메시지를 이벤트로 받는" 구조가 공식적으로 열려 있지 않기 때문입니다.

그래서 처음 떠올린 순진한 그림 — "단톡방에 봇 둘을 넣고 서로 메시지에 자동응답하게 한다" — 은 절대 가면 안 되는 길이었습니다:

회계사 답변 → 세무사가 그걸 메시지로 받음 → 세무사 답변
   → 회계사가 그걸 받음 → 회계사 답변 → 세무사가 받음 → ...  (무한 루프)

무한 핑퐁 + 카카오의 자동 응답 패턴 탐지 = 두 계정 모두 정지 위험.

해결 아이디어 — 카카오는 "출력 채널"로만 쓴다

핵심 발상의 전환:

대화 로직(두뇌)은 카카오 밖에서 돌리고, 카카오는 완성된 메시지를 발사하는 출력구로만 쓴다.

즉 봇끼리 직접 대화하게 두지 않고, 별도의 '사회자(moderator)' 프로세스가 중간에서:

  1. 회계사 두뇌를 호출해 답을 받고 → 회계사 계정으로 카톡에 발사

  2. 그 답을 세무사 두뇌에 입력으로 넘겨 답을 받고 → 세무사 계정으로 카톡에 발사

  3. 다시 회계사에게… (정해진 턴 수만큼)

두 봇은 서로의 메시지를 보지 않습니다. 다음 발화자를 항상 사회자가 호출하므로, 봇끼리 서로를 트리거하는 일이 구조적으로 불가능합니다. → 무한 루프 원천 차단.

즉 단톡방에 토론주제를 던지면

  1. 회계사가 해당 내용을 확인합니다.

  2. 회계사가 메인오케스트레이션(헤르메스)한테 토론주제를 던집니다.

  3. 확인한 헤르메스는 하위 애들인 회계사(오픈클로), 세무사(오픈클로) 한테 오픈클로 내에서 토론을 시킵니다. 즉 핑퐁핑퐁

  4. 내용들을 순차적으로 카카오 loco로 각 에이전트들이 발신해서 띄웁니다.


🛠️ 사용한 도구

항목

내용

환경

맥미니 로컬, OpenClaw 멀티봇, Hermes(오케스트레이션)

카카오 연동

agent-messenger kakaotalk 모듈 (2.19.1+)

회계 두뇌

accountant_yuseong_answer.py (K-IFRS·KASB 옵시디언 LLM Wiki)

세무 두뇌

tax_yuseong_answer.py (세법조문·판례 옵시디언 LLM Wiki)

사회자

debate_moderator.py (launchd ai.openclaw.debate-moderator, poll 15s)

보고서

debate_report.py + openpyxl, LLM anthropic/claude-sonnet-4-6

상시 서비스

회계 1:1 router + 세무 1:1 router + debate-moderator (3개 동시 가동)


🏗️ 아키텍처 (전체 구조)

한눈에 보기 — 3층 구조

역할

핵심 파일·프로세스

① 카카오 (출력·입력)

단톡방 UI, 메시지 송수신

chat_id 470828588411727, 회계·세무 계정 각각 send

② 사회자 (오케스트레이션)

트리거 감지, 턴 릴레이, 보고서 호출

debate_moderator.py

③ 두뇌 + 보고서 (로직)

RAG 답변 생성, 엑셀 정리

accountant_* / tax_* / debate_report.py

설계 원칙: 봇끼리는 직접 대화하지 않음. 카카오는 완성 메시지 발사만. 토론 순서는 사회자만 제어.


데이터 흐름 (Mermaid)

flowchart TB
    subgraph KAKAO["① 카카오톡 단톡방 (토론방)"]
        U["👤 이용자\n@토론 [주제]"]
        OUT1["💬 회계사 발화"]
        OUT2["💬 세무사 발화"]
        OUT3["💬 회계사 발화"]
        XLS["📊 엑셀 보고서"]
    end

    subgraph MOD["② 사회자 — debate_moderator.py"]
        POLL["polling 15s\n(단톡방만)"]
        GUARD["author_id 가드\n(봇 메시지 무시)"]
        LOOP["턴 루프 TURNS=3\n회계 ↔ 세무 릴레이"]
        CALL["debate_report.py 호출"]
    end

    subgraph BRAIN["③ 두뇌 (기존 answer.py 재사용)"]
        ACC["accountant_answer.py\nK-IFRS·KASB 옵시디언 LLM WIKI"]
        TAX["tax_answer.py\n세법조문·판례 옵시디언 LLM WIKI"]
    end

    subgraph RPT["③ 보고서 — debate_report.py"]
        LLM["LLM 비교정리\nJSON 4필드"]
        XL["openpyxl 2시트"]
    end

    subgraph ROUTER["※ 1:1 router (단톡방 미관여)"]
        R1["accountant-router"]
        R2["tax-router"]
    end

    U -->|새 메시지| POLL
    POLL --> GUARD --> LOOP
    LOOP -->|호출| ACC
    LOOP -->|호출| TAX
    ACC -->|send 회계사 계정| OUT1
    TAX -->|send 세무사 계정| OUT2
    LOOP -->|3턴 후| CALL
    CALL --> LLM --> XL -->|upload| XLS
    LOOP --> OUT3

    R1 -.->|allowlist 1:1만| KAKAO
    R2 -.->|allowlist 1:1만| KAKAO

상세 ASCII 다이어그램

┌──────────────────── 카카오톡 "토론방" (chat_id) ────────────────────┐
│  이용자: "@토론 [주제]"  →  회계사 발화  →  세무사 발화  →  회계사 발화  →  📊 엑셀  │
└────▲──────────────▲─────────────────▲─────────────────▲───────────▲──┘
     │ polling      │ send(회계)       │ send(세무)       │ send(회계) │ upload
     │              │                  │                  │            │
┌────┴──────────────┴──────────────────┴──────────────────┴────────────┴────────┐
│                    debate_moderator.py  (사회자)                               │
│  ① 단톡방만 polling → 이용자 @토론 감지 (봇 author_id 트리거 제외)                │
│  ② 턴 루프: 회계 두뇌 ↔ 세무 두뇌 번갈아 호출, 상대 답을 다음 입력으로 전달         │
│  ③ 종료 → debate_report.py → 엑셀 생성 → 카카오 업로드                           │
└────┬─────────────────────┬────────────────────────┬───────────────────────────┘
     │                     │                        │
┌────▼─────────────┐ ┌─────▼──────────────┐ ┌──────▼─────────────────┐
│ accountant_      │ │ tax_               │ │ debate_report.py       │
│ answer           │ │ answer             │ │ LLM 비교정리 → openpyxl │
│ (회계 두뇌)       │ │ (세무 두뇌)         │ │ → 2시트 엑셀           │
│ K-IFRS·KASB      │ │ 세법조문·판례       │ │                        │
└──────────────────┘ └────────────────────┘ └────────────────────────┘

※ 회계사·세무사 1:1 router → 이 단톡방 chat_id를 절대 polling하지 않음 (§ 무한 루프 방지)

컴포넌트 역할표

컴포넌트

입력

출력

카카오와의 관계

이용자

@토론 [주제]

유일한 토론 트리거

debate_moderator

단톡방 새 메시지

두뇌 호출 + send + report 호출

유일한 단톡방 polling 주체

accountant_answer

질문 문자열

draft_answer JSON

회계사 계정으로 발사만

tax_answer

--q 질문

answer JSON

세무사 계정으로 발사만 (격리 config)

debate_report

발화 전문

xlsx 2시트

파일 upload

1:1 router ×2

allowlist 1:1 chat

1:1 자동응답

단톡방 미참여

핵심: 기존 두뇌(answer.py)를 재사용합니다. 새 토론 엔진을 만들지 않았습니다. 회계사·세무사의 지식이 업데이트되면 토론 품질도 자동으로 따라 올라갑니다.


▲ 단톡방 "토론방"에서 @토론으로 시작된 실제 토론. 회계사 → 세무사로 발화가 이어집니다.


🔧 작업 과정

1. 사전 검증 — 진짜 되는지부터 실측

추측으로 설계하지 않고, 불확실한 지점을 먼저 실제로 찔러봤습니다.

카카오가 단톡방을 다룰 수 있나?

사용 중인 CLI 도구(agent-messenger의 kakaotalk 모듈)에 단톡방 지원이 있는지 확인:

  • chat list --resolve-titles --search → 단톡방(MultiChat) 명시적 지원 확인

  • message list <chat-id> / message send <chat-id> → 1:1이든 단톡방이든 chat_id 하나로 동일하게 동작

  • member list <chat-id> → 방 멤버 조회 가능

두 봇이 같은 방에 공존하나? (결정적 검증)

카톡 앱에서 단톡방 "회계세무토론방"을 직접 만들고 봇 둘을 초대한 뒤, 양쪽 계정으로 같은 방을 조회했더니:

chat_id: 사용자아이디  (type: MultiChat)
active_members: 3  →  사용자(00000000) + 회계사(0000000) + 세무사(00000000)

*사정상 뒤 아이디는 가립니다.

  • 두 봇이 같은 chat_id를 동시에 인식

  • member list로 세 user_id 전부 확인 ✓

  • 흥미로운 디테일: 세무사 눈엔 "회계사", 회계사 눈엔 "세무사"로 서로를 멤버로 정확히 인식

⚠️ 함정 하나: 카카오 LOCO는 메시지가 한 번도 안 오간 방은 chat list 스냅샷에 안 잡힙니다. 방만 만들고 가만히 두면 빈 배열이 나옵니다. 아무 메시지나 한 줄 쳐야 방이 잡힙니다.


2. 무한 루프를 막은 3중 안전장치

이 프로젝트의 진짜 핵심은 "토론을 시키는 것"이 아니라 "봇 둘을 안 꼬이게 만드는 것"이었습니다.

#

장치

내용

5.1

트리거는 사람만

사회자는 author_id가 이용자(00000000)이고 @토론으로 시작하는 것만 인식. 봇 author_id 메시지 무시 → 봇 발화가 또 토론을 부르는 일 불가능

5.2

발화자는 사회자 호출

봇은 "상대 메시지를 보고 반응"하지 않음. for i in range(TURNS) 루프에서 사회자가 다음 발화자 직접 호출

5.3

1:1 router 분리

회계·세무 router는 allowlistChatIds만 polling. 단톡방 chat_id를 절대 넣지 않음 → 1:1처럼 자동응답하는 사고 차단

검증 (최악 시나리오 테스트)

state를 토론 직전으로 되돌려 봇 메시지 5개가 전부 "새 메시지"로 보이게 만든 뒤 사회자를 폴링시켰습니다 → 토론 재시작 0건. author_id 가드가 완벽히 작동함을 실측.


3. 까다로웠던 디테일 — 두 두뇌의 인터페이스가 다르다

회계사와 세무사 두뇌(answer.py)는 따로 만들어져서 호출 규약이 서로 달랐습니다. 사회자가 이걸 구분해서 호출하지 않으면 답이 빈 문자열로 나오거나 엉뚱한 계정으로 발사됩니다.

항목

회계사

세무사

질문 인자

positional "<질문>"

--q "<질문>"

JSON 답변 키

draft_answer

answer

카톡 발신 방식

기본 디렉토리 + --account 00000000

환경변수 AGENT_MESSENGER_CONFIG_DIR=~/.config/agent-messenger-tax

두 봇이 안 꼬이고 공존하는 비결: 카카오 config 디렉토리를 환경변수로 완전 격리 + 디바이스 타입 분리(tablet/desktop) + agent-messenger 2.19.1 이상.


4. 토론 품질 설계 — "동의합니다" 빈말 방지

같은 LLM 베이스라 그냥 두면 둘 다 "맞습니다, 동의합니다"만 반복할 위험이 있었습니다. 각 턴마다 역할을 명시한 프롬프트로 강제했습니다:

발화자

프롬프트 요지

1

회계사

주제를 회계(K-IFRS) 관점에서 핵심 쟁점·결론 제시

2

세무사

회계사 답 수신 → "세무 리스크·빠진 세법 쟁점만. 동의는 한 줄로."

3

회계사

세무사 답 수신 → "회계처리상 보완·수정 결론만. 동의는 한 줄로."

마지막 발화(회계사 3턴)가 앞 내용을 종합하므로 자연스럽게 통합 결론 역할을 합니다. 별도의 '사회자 멘트' 계정 없이 마지막 턴이 결론이 되게 설계.


▲ 빈말 방지가 실제로 작동한 장면. 세무사는 "동의"를 한 줄로 끝내고 곧바로 세법 쟁점(손금불가 판례 3건, 소득세법 §20, 조특법 §16의2)을 짚습니다.

턴 수는 3으로 시작 (변수로 분리)

정밀도를 위해 5턴도 고려했지만, 검증 안 된 파이프라인에 비용을 키우지 않기 위해 TURNS 변수로 빼고 3턴으로 시작했습니다. "제시→반박→정리" 한 사이클이면 충분. 필요하면 숫자 하나만 5로 바꾸면 승급.


5. 토론 → 엑셀 보고서 자동화

토론 내용을 사례 자료로 보존하려면 카톡 메시지로 흩어두기보다 문서가 났습니다. 토론이 끝나면 사회자가 debate_report.py를 호출합니다.

3단계 파이프라인

토론 발화 전문
    │
    ▼
① LLM 비교정리 (anthropic/claude-sonnet-4-6)
   → {쟁점, 회계 관점, 세무 관점, 통합 결론} JSON
   ※ "토론에 실제 나온 내용만" 프롬프트로 환각 차단
    │
    ▼
② openpyxl 엑셀 (2시트)
   · 비교정리: 쟁점 | 회계 | 세무 | 통합 결론 표
   · 발화전문: 턴별 원문 전체
    │
    ▼
③ 카카오 업로드
   message upload --as file --account 00000000 <chat_id> <xlsx>


▲ 토론 종료 → "보고서로 정리하고 있어요" 안내 → 엑셀 파일 자동 업로드까지 한 화면에. 상단의 "멤버 3"도 두 봇 + 이용자의 공존을 보여줍니다.

환각 차단이 실제로 작동한 증거

가업승계 주제 토론에서 회계사가 다루지 않은 쟁점에 대해, 보고서는 "회계 관점에서 직접적으로 다뤄지지 않았다"고 정직하게 적었습니다. 없는 내용을 억지로 채우지 않습니다.

완성된 보고서 (2시트)


▲ 시트1 「비교정리」 — 쟁점별로 회계·세무 관점과 통합 결론을 한눈에 비교.


▲ 시트2 「발화전문」 — 턴별 원문 전체를 그대로 보존(검증·재인용용).


6. 트러블슈팅 메모

이슈

해결

Unknown model

openclaw infer 모델명에 provider 접두어 필수. claude-sonnet-4-6(❌) → anthropic/claude-sonnet-4-6(✓)

LLM 인증 실패

answer.py와 동일하게 _infer_env()ANTHROPIC_API_KEY(= ~/.hermes/.envANTHROPIC_TOKEN) 주입

과거 트리거 재실행

서비스 최초 등록·재시작 전 --prime-state로 과거 @토론 무시(high-water mark). 안 하면 옛 메시지로 토론 또 돔

엑셀 추가기능 컴파일 에러(ufrmMsg)

생성 파일 문제 아님 — 여는 쪽 엑셀 깨진 add-in. unzip -lvbaProject.bin 0개 확인. 엑셀 옵션 → 추가기능 해제

macOS엔 timeout 없음

폴링 테스트는 --max-loops로 self-terminate


✅ 결과 (After)

사용법

단톡방에 한 줄:

@토론 임직원 스톡옵션 부여·행사 시 회계처리와 세무처리 차이

→ 회계사·세무사가 3턴 토론 → 비교정리 엑셀 보고서 자동 업로드.

Before vs After

항목

Before

After

Bot-to-Bot

카카오 LOCO상 불가, 무한 루프 위험

사회자 릴레이로 구조적 우회

토론 결과

카톡 메시지에 흩어짐

엑셀 2시트 자동 업로드

두뇌

1:1 전용

기존 answer.py 재사용 + 단톡방 전용 사회자

가동

router 2 + moderator 3프로세스 동시 running

가동 상태 (실측, 2026-06-06)

accountant-router: state = running   (회계사 1:1)
taxg-router:       state = running   (세무사 1:1)
debate-moderator:  state = running   (토론 사회자)

세 프로세스가 충돌 없이 동시 가동.


📦 구성 요소 정리

구분

경로 / 식별자

사회자 스크립트

~/.openclaw/workspace/scripts/debate_moderator.py (424줄)

보고서 모듈

~/.openclaw/workspace/scripts/debate_report.py (318줄)

회계사 두뇌

~/.openclaw/workspace/scripts/accountant_answer.py

세무사 두뇌

~/.openclaw/workspace/scripts/tax_answer.py

사회자 상시 서비스

launchd ai.openclaw.debate-moderator (poll 15s)

단톡방

"토론방" chat_id 0000000000 (멤버 3)

사회자 state

~/.openclaw/workspace/data/debate/moderator_state.json

보고서 산출물

~/.openclaw/workspace/data/debate/reports/토론보고서_<주제>_<날짜>.xlsx

회계사 계정

00000000 (cpa_agent, 기본 config 디렉토리)

세무사 계정

00000000 (cta_agent, 격리 config 디렉토리)


💬 이 과정에서 배운 AI 활용 팁

효과적이었던 것

  1. 제약을 인정하고 우회. "카카오는 Bot-to-Bot이 안 된다"를 부정하지 않고, "카카오를 출력구로만 쓴다"로 발상을 틀었습니다. 겉보기엔 봇끼리 토론하지만 실제론 릴레이가 됩니다.

  2. 안전을 '조심'이 아니라 '구조'로. author_id 제외 + 사회자 호출 + router 분리했습니다. 사람이 실수해도 무한 루프가 발생할 수 없는 구조입니다.

  3. 기존 부품 재사용. 새 두뇌를 만들지 않고 회계사·세무사 answer.py를 릴레이로 엮었습니다. 변경 최소, 품질은 기존 지식에 자동 연동됩니다.

  4. 추측 대신 실측. 단톡방 공존, 무한루프 차단, 풀 파이프라인을 전부 실제로 돌려 확인하고 완료라고 말했습니다.

  5. 실제 토론 내용과 결과물 스크린샷

이렇게 하면 안 돼요

  1. 단톡방에 봇 둘을 넣고 서로 메시지에 자동응답하게 두기 (무한 루프 + 계정 정지)

  2. 1:1 router의 polling 대상에 단톡방 chat_id 포함 (이중 응답·꼬임)

  3. 검증 전에 턴 수·비용만 키우기 (TURNS=3으로 시작한 이유)

한 줄로: "카카오의 Bot-to-Bot 불가를, 사회자 릴레이 + 출력구 전략으로 우회해 두 AI 봇의 토론과 자동 보고서화를 안전하게 구현했습니다."


📋 재사용 가능한 프롬프트

토론 시작 (카톡 단톡방)

@토론 [여기에 회계·세무 쟁점 주제]

턴별 역할 강제 (사회자 내부 프롬프트 요지)

1턴(회계): K-IFRS 관점 핵심 쟁점·결론 제시
2턴(세무): 세무 리스크·빠진 세법 쟁점만. 동의는 한 줄
3턴(회계): 회계처리 보완·수정 결론만. 동의는 한 줄

보고서 LLM (환각 차단)

토론 발화 전문만 근거로 {쟁점, 회계 관점, 세무 관점, 통합 결론} JSON 정리.
토론에 나오지 않은 내용은 "다뤄지지 않았다"고 명시. 지어내지 마라.


5
2개의 답글

뉴스레터 무료 구독