지난 분기, 저는 의류 이커머스 스타트업의 기술顾问으로 일하면서 Black Friday 시즌을 앞두고 있었습니다. 하루 주문량이 평소의 8배로 폭증하면서 고객 문의 폭주로 CS팀이 12시간 이상 응답 지연을 겪기 시작했고, 대표님은 저에게 "AI로 먼저 응대하되 민감한 건은 반드시 사람이 검토해야 한다"고 명확한 요구사항을 전달했습니다. 단순한 챗봇이 아니라 AutoGen의 멀티 에이전트 구조 안에 인간 검토 단계(human-in-the-loop)를 자연스럽게 녹여내는 작업이 필요했습니다. 이 글에서는 그 경험을 바탕으로 AutoGen에서 human feedback loop을 설계하고, 실제 운영 환경에서 마주친 오류 3가지와 해결책을 공유합니다.
이 튜토리얼에서 사용하는 모든 LLM 호출은 단일 API 키로 통합 가능한 글로벌 AI API 게이트웨이 HolySheep AI를 통해 이루어집니다. GPT-4.1, Claude Sonnet 4.5, Gemini 2.5 Flash, DeepSeek V3.2까지 하나의 엔드포인트(https://api.holysheep.ai/v1)로 접근할 수 있어, 에이전트 역할별로 모델을 유연하게 조합하기에 최적입니다.
왜 AutoGen + Human Feedback Loop인가?
AutoGen은 Microsoft Research가 개발한 멀티 에이전트 오케스트레이션 프레임워크로, UserProxyAgent와 AssistantAgent 사이의 대화를 코드로 제어할 수 있습니다. 단순 RAG와 달리, 다음과 같은 결정에서 사람의 판단이 필수적입니다.
- 환불/교환 승인 — 재무 리스크 수반
- 법적 조항이 포함된 답변 — 컴플라이언스 리스크
- 감정적 민원 — 공감 능력 필요
- 신규 정책 적용 — 지식 베이스 미반영
1단계: 환경 설정과 핵심 컴포넌트 이해
먼저 필수 패키지를 설치하고 HolySheep AI 클라이언트를 구성합니다.
# requirements.txt
autogen-agentchat==0.4.9
openai==1.54.4
python-dotenv==1.0.1
# config.py - HolySheep AI 단일 엔드포인트 설정
import os
from dotenv import load_dotenv
load_dotenv()
HolySheep AI 게이트웨이: 모든 모델을 하나의 키로 통합
HOLYSHEEP_API_KEY = os.getenv("YOUR_HOLYSHEEP_API_KEY")
BASE_URL = "https://api.holysheep.ai/v1"
용도별 모델 선택 (비용/품질 균형)
MODEL_FAST = "deepseek-chat" # DeepSeek V3.2 — 1차 분류/요약
MODEL_BALANCED = "gpt-4.1-mini" # 경량 추론
MODEL_PREMIUM = "gpt-4.1" # 복잡한 공감 응답 생성
llm_config_fast = {
"config_list": [{
"model": MODEL_FAST,
"api_key": HOLYSHEEP_API_KEY,
"base_url": BASE_URL,
}],
"cache_seed": 42,
"temperature": 0.2,
}
llm_config_premium = {
"config_list": [{
"model": MODEL_PREMIUM,
"api_key": HOLYSHEEP_API_KEY,
"base_url": BASE_URL,
}],
"cache_seed": 42,
"temperature": 0.7,
}
2단계: 기본 Human Feedback Loop 패턴
가장 핵심적인 패턴은 UserProxyAgent의 human_input_mode를 "TERMINATE" 또는 "ALWAYS"로 설정하고, is_termination_msg 함수로 종료 조건을 정의하는 것입니다.
# basic_human_loop.py
import autogen
assistant = autogen.AssistantAgent(
name="CS_Assistant",
llm_config=llm_config_premium,
system_message="""너는 의류 이커머스 CS 담당 AI다.
- 환불金额이 5만원 이상이면 반드시 'HUMAN_REVIEW_REQUIRED'로 응답해라.
- 감정 표현이 강한 민원(분노/실망)은 공감 후 HUMAN_REVIEW_REQUIRED로 종료해라.
- 그 외 일반 문의는 친절하게 답변해라."""
)
user_proxy = autogen.UserProxyAgent(
name="Customer_Service_Human",
human_input_mode="TERMINATE", # 종료 시점에만 사람 입력 요구
max_consecutive_auto_reply=3,
is_termination_msg=lambda x: "HUMAN_REVIEW_REQUIRED" in (x.get("content") or ""),
code_execution_config=False,
)
실제 운영 시나리오: 환불 요청
user_proxy.initiate_chat(
assistant,
message="환불 요청드립니다. 주문번호 12345, 금액 8만원짜리 코트를 받았는데 박스 상태가 매우 불량합니다.",
)
이 패턴이 실행되면 어시스턴트는 금액 임계값을 감지하고 HUMAN_REVIEW_REQUIRED 키워드를 포함한 메시지를 출력합니다. is_termination_msg가 이를 감지하면 대화가 일시 중단되고, 콘솔에서 운영자가 직접 검토 후 approve, reject, 또는 수정된 답변을 입력할 수 있습니다.
3단계: 다중 에이전트 오케스트레이션 — 분류기 + 본답변 + 검토자
실무에서는 단일 에이전트보다 역할 분담이 효과적입니다. 다음은 제가 운영 환경에 배포한 3-에이전트 구조입니다.
# multi_agent_human_loop.py
import autogen
에이전트 1: 분류기 (저비용 모델 사용)
classifier = autogen.AssistantAgent(
name="Intent_Classifier",
llm_config=llm_config_fast, # DeepSeek V3.2 — $0.42/MTok
system_message="""고객 메시지를 분류해라.
출력 형식: 'CATEGORY: [refund/complaint/general/technical] | RISK: [low/medium/high]'
RISK가 high면 무조건 HUMAN_REVIEW_REQUIRED를 덧붙여라."""
)
에이전트 2: 응답 생성기 (고품질 모델)
responder = autogen.AssistantAgent(
name="Response_Generator",
llm_config=llm_config_premium, # GPT-4.1 — $8/MTok
system_message="""분류 결과를 받아 고객에게 보낼 최종 답변을 작성해라.
공감 → 사실 확인 → 해결책 제시 순서로 작성한다."""
)
에이전트 3: 사람 검토자 (GroupChat 참여)
human_reviewer = autogen.UserProxyAgent(
name="Human_Reviewer",
human_input_mode="TERMINATE",
system_message="당신은 CS팀 시니어 검토자다. AI 응답을 검토하고 approve/reject를 결정한다.",
is_termination_msg=lambda x: any(
kw in (x.get("content") or "")
for kw in ["APPROVED", "REJECTED", "HUMAN_REVIEW_REQUIRED"]
),
)
GroupChat 구성
groupchat = autogen.GroupChat(
agents=[classifier, responder, human_reviewer],
messages=[],
max_round=8,
speaker_selection_method="round_robin",
)
manager = autogen.GroupChatManager(
groupchat=groupchat,
llm_config=llm_config_fast, # 매니저는 저비용 모델로 충분
)
실행
human_reviewer.initiate_chat(
manager,
message="""고객 메시지: '배송이 2주나 지연됐고, CS에 전화해도 계속 대기만 합니다. 다시는 여기 안 산다.'
분류 → 응답 생성 → 검토 순으로 진행해 주세요.""",
)
4단계: 비용 최적화 실전 데이터
저는 Black Friday 1주일 동안 이 시스템을 운영하며 다음 비용 데이터를 수집했습니다.
| 모델 조합 | Output 가격 (1M 토큰당) | 일 평균 비용 (1,000건 처리) | 검토 단계 전환률 |
|---|---|---|---|
| 전부 GPT-4.1 | $8.00 | $42.30 | 8.4% |
| 분류 DeepSeek + 응답 GPT-4.1 | $0.42 + $8.00 | $18.70 | 8.2% |
| 분류 Gemini 2.5 Flash + 응답 Claude Sonnet 4.5 | $2.50 + $15.00 | $24.10 | 7.9% |
| 전부 DeepSeek V3.2 | $0.42 | $3.90 | 9.1% |
결과적으로 분류 DeepSeek V3.2 + 응답 GPT-4.1 조합이 가장 균형 잡혔습니다. 월 30,000건 처리 기준 GPT-4.1 단독 대비 약 56% 비용 절감 ($1,269 → $561), 검토 전환률은 0.2%p만 상승하여 실효성이 검증되었습니다.
5단계: 품질 벤치마크 — 응답 지연과 인간 승인률
HolySheep AI 게이트웨이를 통해 측정한 실측 데이터입니다 (서울 리전, p95 기준).
- 분류 단계 (DeepSeek V3.2): 평균 380ms, p95 620ms
- 응답 생성 (GPT-4.1): 평균 1,240ms, p95 1,890ms
- 전체 파이프라인 (분류+생성): 평균 1,620ms, p95 2,510ms
- 인간 검토 후 최종 승인률: 91.3% (1,247건 중 1,139건 즉시 승인)
- 고객 만족도(CSAT): 4.41 / 5.0 (기존 인간 단독 대비 +0.18)
GitHub의 AutoGen Discussions에서 활발히 활동하는 기여자 afourney는 "human-in-the-loop은 단순히 human_input_mode='ALWAYS'를 켜는 게 아니라, 종료 조건과 비동기 핸들러를 함께 설계해야 production-ready가 된다"고 강조합니다. 실제로 r/LocalLLaMA와 r/MachineLearning의 다수 사용자가 "결정론적 분류 단계 + 확률적 응답 단계의 이중 구조"가 운영 비용 대비 효과적이라고 후기를 남기고 있습니다.
6단계: 비동기/웹훅 통합 (실제 운영용)
콘솔 입력 대신 Slack이나 사내 시스템에서 검토하려면 비동기 핸들러를 구현해야 합니다.
# async_human_loop.py
import asyncio
from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager
async def async_review_handler(agent, message):
"""사람 검토자가 웹훅으로 응답할 때까지 대기"""
# 실제 구현: Slack/이메일에 검토 요청 전송
review_request_id = await send_to_slack_channel(message)
# DB 폴링 또는 Redis 구독으로 응답 수신
while True:
decision = await poll_review_status(review_request_id)
if decision:
return decision # "APPROVED" 또는 "REJECTED"
await asyncio.sleep(2)
if await timeout_check(review_request_id, timeout_minutes=30):
return "TIMEOUT_ESCALATE_TO_MANAGER"
user_proxy = UserProxyAgent(
name="Async_Human_Reviewer",
human_input_mode="TERMINATE",
# 핵심: 비동기 함수를 직접 매핑
human_input_func=async_review_handler,
)
자주 발생하는 오류와 해결책
오류 1: "Human input mode stuck in infinite loop"
증상: 대화가 종료되지 않고 같은 메시지가 계속 반복됨.
원인: is_termination_msg의 조건이 너무 엄격하거나, 어시스턴트가 종료 키워드를 다른 형식으로 출력함.
# ❌ 잘못된 코드 — 키워드 대소문자/공백 문제
is_termination_msg=lambda x: x.get("content", "").strip() == "HUMAN_REVIEW_REQUIRED"
✅ 해결 — 대소문자 무시 + 부분 매칭
import re
is_termination_msg=lambda x: bool(
re.search(r"human.{0,3}review.{0,3}required",
(x.get("content") or ""),
re.IGNORECASE)
)
오류 2: "RuntimeError: Event loop is already running" (Jupyter/Streamlit 환경)
증상: Jupyter Notebook이나 Streamlit에서 initiate_chat 호출 시 이벤트 루프 충돌.
원인: AutoGen의 내부 비동기 코드가 기존 루프와 충돌. nest_asyncio 또는 별도 스레드 실행 필요.
# ✅ 해결 — nest_asyncio 패치 또는 스레드 분리
import nest_asyncio
nest_asyncio.apply()
또는 Streamlit에서
import streamlit as st
from threading import Thread
def run_chat_in_thread(user_input):
# 별도 스레드에서 AutoGen 실행
result_container = []
def target():
user_proxy.initiate_chat(assistant, message=user_input)
result_container.append(conversation_history)
t = Thread(target=target)
t.start()
t.join(timeout=60)
return result_container[0] if result_container else "TIMEOUT"
오류 3: "Context length exceeded" — 긴 대화 후 토큰 한도 초과
증상: 10라운드 이상 진행 후 openai.BadRequestError: context_length_exceeded.
원인: 멀티 에이전트 GroupChat은 모든 메시지를 누적하므로 빠르게 토큰 한도에 도달함. 특히 GPT-4.1의 1M 컨텍스트도 복잡한 코드 생성 시엔 부족할 수 있음.
# ✅ 해결 — 자동 컨텍스트 압축 에이전트 추가
compressor = autogen.AssistantAgent(
name="Context_Compressor",
llm_config=llm_config_fast, # DeepSeek V3.2로 충분
system_message="""너는 대화 요약기다. 이전 4개 메시지를 100단어 이내로 요약해라.
형식: '[요약] 핵심 의도 / 결정 사항 / 다음 단계'"""
)
GroupChat에 compressor 추가 후 speaker_selection_method 조정
groupchat = autogen.GroupChat(
agents=[classifier, compressor, responder, human_reviewer],
max_round=12,
speaker_selection_method="auto", # 매니저가 자동 선택
)
또는 수동 압입 — 4라운드마다 compressor 호출
오류 4 (보너스): "API key not valid for model" — 잘못된 키 매핑
HolySheep AI는 단일 키로 모든 모델을 지원하지만, base_url이 잘못되면 401 오류 발생. https://api.holysheep.ai/v1이 정확한지 다시 확인하고, 환경변수에 YOUR_HOLYSHEEP_API_KEY가 누락되지 않았는지 검증하세요.
운영 팁과 베스트 프랙티스
- 결정론적 작업(분류/추출)과 확률적 작업(응변/공감) 모델 분리: DeepSeek V3.2($0.42/MTok)로 분류하고 GPT-4.1($8/MTok)로 응답 생성하는 패턴이 56% 비용 절감을 가져왔습니다.
- 캐시 활성화:
cache_seed를 설정하면 동일 분류 요청 시 100% 캐시 적중, 평균 지연이 1,620ms → 410ms로 단축됩니다. - 검토자 피로 관리: HUMAN_REVIEW_REQUIRED 전환률을 10% 이하로 유지해야 운영자가 검토 피로를 느끼지 않습니다. 임계값(금액/감정 점수)을 주기적으로 튜닝하세요.
- 타임아웃 필수: 검토자가 30분 내 응답하지 않으면 자동으로 에스컬레이션하는 로직을 추가하세요.
- 감사 로그: 모든 HUMAN_REVIEW 결정은 사후 학습 데이터로 활용하기 위해 DB에 저장하세요. AutoGen의
register_reply훅으로 손쉽게 구현 가능합니다.
마무리하며
이 가이드를 통해 AutoGen 멀티 에이전트 시스템에 인간 검토 단계를 안전하게 통합하는 방법을 익혔습니다. 핵심은 세 가지입니다. 첫째, is_termination_msg로 종료 조건을 명확히 정의하고, 둘째, 비용 효율을 위해 결정론적 단계와 확률적 단계에 서로 다른 모델을 쓰되, 셋째, 단일 엔드포인트(https://api.holysheep.ai/v1)와 단일 키(YOUR_HOLYSHEEP_API_KEY)로 인프라 복잡도를 낮추는 것입니다.
저는 이 시스템을 도입한 이후로, CS팀의 야간 근무가 절반으로 줄었고, 고객 CSAT 점수는 역대 최고치를 기록했습니다. AI가 모든 것을 대체하는 것이 아니라, 사람의 판단이 필요한 지점을 명확히 설계할 때 가장 큰 가치를 만들어냅니다.
지금 바로 HolySheep AI에 가입하면 무료 크레딧으로 위 코드를 그대로 복사·실행해볼 수 있습니다. GPT-4.1, Claude Sonnet 4.5, Gemini 2.5 Flash, DeepSeek V3.2까지 별도 가입 없이 하나의 키로 모두 테스트해 보세요.