해커톤 우승작을 실시간 콜봇으로: 하네스 엔지니어링

일시
2026.10.28 15:50-16:30
트랙
트랙 B
연사
김영남, 김동화

#AI/ML#CS

세션 소개

해커톤 우승작을 실시간 콜봇으로 만든 과정입니다. 파트 1(김동화)은 고객과 가게 두 통화를 오가는 음성 에이전트를 코드 가드레일로 안정화한 사례, 파트 2(김영남)는 그 콜봇을 만든 하네스를 실제 서비스에 맞게 고쳐 온 과정을 다룹니다.

핵심 내용

파트 1. 콜봇 구조와 두 통화에서 놓친 맥락

앞단 음성 모델이 통화를 응대하고, 뒷단 분류 에이전트가 고객 의도를 판단해 담당 에이전트(주문 조회, 가게 발신 툴 사용)에게 넘기는 구조입니다. 에이전트 하나가 고객·가게 두 통화를 실시간으로 오가면서 맥락을 놓쳤고, 이 문제를 다섯 가지 요인으로 세분화했습니다.

  • 사례: 메뉴 누락 문의 → 업주가 재발송 약속 → 에이전트가 결과를 전하지 않고 고객에게 "가게에 연락해 볼게요"라고 처음부터 다시 응대

가드레일 다섯 가지

다섯 요인 모두 프롬프트 대신 코드로 막았습니다. 프롬프트는 확률적으로, 코드는 확정적으로 동작하기 때문입니다.

가드레일문제해결
통화두 통화가 동시에 열려 꼬임말하는 통화는 하나만. 고객 통화를 대기로 두고 발신, 그 사이 다른 통화 시도는 실행 전 차단
연결전화 걸기·초대·재초대·전환 등 도구가 많아 성능 저하에이전트는 대화 상대만 지정, 대기 통화 전환이나 신규 발신은 시스템이 판단
기록통화가 바뀌면 맥락 단절상담 ID 하나에 고객·업주 대화를 함께 저장하고 에이전트가 이 기록을 읽음
게이트문의 유형 오분류, 잘못된 보상 처리오분류는 재시도 후 반복 실패 시 상담사 이관. 보상은 정책 확인 게이트 통과 후 발급
평가정답지를 본 에이전트가 정답을 말해 버림답변 근거가 대화·조회 툴에서 왔는지 출처를 확인해 허용·차단하는 자동 평가
  • 배치: 앞단 음성 계층에 통화·연결, 뒷단에 게이트·기록·평가
  • 모두 에이전트 밖의 코드라 에이전트가 틀려도 상담 유지

결과와 다음 과제

첫 응답 0.8초 이내로 통화가 끊기는 느낌이 거의 없고, 기존 상담사보다 많은 상담을 처리(?)할 수 있게 됐습니다.

  • 다음 과제: 소음 환경의 음성 인식 오류. 검토 중인 방안은 노이즈 캔슬링, 도메인 용어 기반 교정, 음성 인식 모델 학습

파트 2. 하네스를 직접 만든 이유

superpowers, ralph-loop, oh-my-opencode는 범용 설계라 사내 환경과 맞지 않고, 정해진 워크플로를 따라야 하며, 내부 동작을 몰라 고치기 어려웠습니다. 그래서 사내 환경과 작업 방식에 맞춘 하네스를 직접 만들었습니다.

  • 해커톤 이후 실제 서비스에 쓰면서 기억, 비용, 제어, 목표, 협업 다섯 축의 문제를 만남
  • 협업 축은 발표 자료에 내용 없음

기억: 잊어버리는 루프 → 루프 안의 위키

새 세션마다 에이전트가 예전 입력을 잊고 같은 질문과 실수를 반복했습니다. 공개된 LLM 위키 중 에이전틱 루프와 통합된 것이 없어, 단계마다 읽고 쓸 문서를 스킬로 정하고 루프 산출물과 위키를 분리했습니다.

  • 원인: 루프와 위키가 따로 동작, 문서를 읽고 쓰는 시점이 없음, 사람의 입력이 루프 종료와 함께 휘발
  • 루프 순서: 요구사항 → 계획 → 구현 → 검증 → 정리 → MR/PR
  • 정리 단계에서 반복 실수, 아키텍처상 중요한 결정만 골라 위키로 distill
구분위치성격내용
루프 산출물loops/많고 일시적, MR 머지 후 삭제실패 로그, 판정 결과, 리뷰 메모, 재시도 기록, 사용자 입력, 검증 결과
LLM 위키docs/적고 지속적, 다음 루프의 계획·구현 단계에서 읽음knowledge/pitfalls, knowledge/decisions, rules/(사용자 확인 후 규칙화)
  • 결과: 한 번 입력한 결정은 다시 묻지 않고, 실패 경험을 기억해 같은 실수 방지

비용: 서브에이전트 27개 → 8개

오케스트레이터는 루프 제어만 맡고 계획·구현·리뷰·테스트·문서 다섯 영역을 서브에이전트 27개에 위임했더니 토큰 사용량이 급증했습니다. 계획·구현을 메인 에이전트로 옮기고 서브에이전트는 검증·문서에만 남겨, 결과물 품질은 유지한 채 토큰 사용량을 10분의 1 정도로 줄였습니다.

  • 원인: Claude Code 서브에이전트는 fire-and-forget 방식이라 결과만 반환하고 종료되어 피드백을 이어 줄 수 없음
  • 새 작업마다 CLAUDE.md, PRD(제품 요구사항 문서), 설계, 위키, 코드를 처음부터 다시 읽음
  • 피드백 3회차부터 MAX 주간 한도 초과, 주간 사용량을 하루 만에 소진
구분메인 에이전트서브에이전트
전루프 제어만27개: 계획, 구현, 검증, 문서
후루프 제어, 계획, 구현(스킬로 수행)8개: 검증, 문서 갱신

제어: 꼬이는 루프 → 스킬 정리와 그래프

메인 에이전트의 일이 늘자 의도와 다른 스킬을 호출하거나 검증 단계를 건너뛰는 문제가 생겼습니다. 스킬을 라우트 구조로 묶고, 스킬 사이 이동을 그래프로 검사해 막았습니다.

스킬 정리: 흩어져 있던 구현·빠른 수정·디버그·스파이크·리뷰 대응·마무리를 work 스킬 아래 라우트(pull, push, fastrack, debug, spike, revise, close)로 통합했습니다. 전체 스킬 6개(init, plan, work, status, review, llm-wiki), 라우트 39개입니다.

skills/work/
├── SKILL.md          라우팅·검증·재진입
├── references/       라우트별 절차 (pull.md, revise.md, close.md …)
└── shared/           공유 절차
  • 실행 순서: SKILL.md 라우팅 표로 라우트 선택 → references/<라우트>.md 절차 실행 → 라우트별 체크리스트로 검증 → 재진입 판정(같은 스킬의 다른 라우트, 다른 스킬, 다음 단계 중 선택)
  • SKILL.md부터 읽는 점진적 공개 방식

그래프 제어: 노드는 스킬:라우트, 엣지는 이동 경로와 조건입니다. hook과 로컬 MCP 서버가 엣지와 조건을 검사합니다.

{ "from": "work:push", "to": "plan:architecture", "kind": "call", "when": ["user_choice"] }
  • kind: call(호출 후 출발 노드로 복귀), transition(다른 스킬로 이동)
  • when: steps_complete(절차 완료), user_choice(사용자 선택), reason(에이전트가 사유 기록)
  • 위 엣지: 작업 중 아키텍처를 고치고 돌아오려면 사용자 승인 필요
경로전이결과
작업 종료 → MR 리뷰 대응work:close → work:revise · user_choice통과
리뷰 반영 → 검증 → 종료work:revise → work:close · steps_complete통과
MR 리뷰 대응 → 계획 세우기work:revise → plan:charter · 엣지 없음차단
검증 생략 후 종료work:revise → work:close · 조건 미충족차단

목표: 바텀업 요청 → 목표를 아는 에이전트

요구사항을 하나씩 처리하는 바텀업 방식에서는 에이전트가 최종 목적을 몰라, 새 요청마다 이전 구현이 레거시가 되고 목표에 지그재그로 다가갔습니다. 사람이 목표를 정하고 에이전트가 작업으로 분해하는 탑다운 경로를 만들고, 바텀업 경로에는 목표 검사를 넣었습니다.

  • 예: 메모 저장(한 사람 기준) → 친구와 공유(복사본 전송) → 함께 편집(복사본으로 불가, 저장 구조 재설계)
계층담당내용
Decision layer (목표 설정)사람charter(정의·규칙·목표·원칙), 아키텍처, 마일스톤
Delivery layer (계획)에이전트마일스톤에서 요구사항·성공 조건·갭·작업 도출
작업 루프사람 요청 후 에이전트역할·우선순위에 맞는 작업 할당 → 구현 → 검증 → MR
  • 작업 결과를 현재 상태에 반영하고, 작업 시작마다 현재 상태와 비교해 갭을 다시 측정
  • 바텀업 경로는 모든 경우를 탑다운으로 풀 수 없어 유지하고 목표 검사 추가: 목표와 상충하면 요청자가 요구사항이나 목표를 고친 뒤 작업, 충돌이 없으면 기존 흐름대로 작업