[MAICE 개발기 2편] 에이전트들이 어떻게 협업하는가? (Multi-Agent System)
1. 하나의 LLM으로는 부족하다
처음에는 하나의 거대한 프롬프트에 모든 지시사항을 넣으려 했습니다. “너는 수학 선생님이고, 교육과정을 준수하며, 용어를 확인하고, 학생 수준을 파악해…”
결과는 뻔했습니다. LLM은 지시사항을 빼먹거나(Forgotten Instructions), 서로 모순되는 지시 사이에서 혼란을 겪었습니다. 우리는 **“분업화”가 답이라고 판단했습니다. 질문을 분석하는 뇌(Classifier)와 답변을 만드는 뇌(Generator)가 물리적으로 분리되어야 했습니다.
2. Redis Streams를 이용한 신뢰성 있는 통신
MSA(Microservices)에서 가장 중요한 건 통신입니다. 우리는 HTTP 대신 Redis Streams를 선택했습니다. 에이전트가 죽었다 살아나도 메시지가 유실되지 않아야 했기 때문입니다.
실제 구현 코드: Consumer Group 읽기
agent/utils/redis_streams_client.py의 핵심 코드를 보면, xreadgroup을 사용하여 메시지를 안정적으로 가져오는 것을 볼 수 있습니다.
# agent/utils/redis_streams_client.py
async def read_from_backend_stream(self, count: int = 1, block: int = 1000):
"""백엔드로부터 메시지 수신 (Consumer Group)"""
max_retries = 3
retry_count = 0
while retry_count < max_retries:
try:
# Consumer Group을 통해 메시지를 읽음 (중복 처리 방지)
messages = await self.redis_client.xreadgroup(
self.agent_consumer_group,
self._consumer_name,
{self.BACKEND_TO_AGENT_STREAM: ">"}, # ">": 아직 아무에게도 배달되지 않은 새 메시지
count=count,
block=block
)
if messages:
# 메시지 파싱 및 처리 로직...
return parsed_messages
except redis.ConnectionError as e:
retry_count += 1
await asyncio.sleep(1.0 * retry_count) # 지수 백오프(Exponential Backoff)
이 구조 덕분에 특정 에이전트 컨테이너가 배포 중 재시작되어도, Redis에 쌓인 메시지는 안전하게 보존되었다가 재시작 후 처리됩니다.
3. 질문 처리 파이프라인 (The Pipeline)
학생이 질문을 던졌을 때 내부적으로 일어나는 과정은 다음과 같습니다. 연구 논문의 실험 설계가 실제 코드로 어떻게 구현되었는지 확인해보세요.
sequenceDiagram
participant S as Student
participant BE as FastAPI Backend
participant QC as QuestionClassifier
participant AG as AnswerGenerator
participant QI as QuestionImprover
S->>BE: "이거 모르겠어요" (질문)
BE->>QC: Redis Stream (Task: Classify)
QC->>QC: Analyze Intent & Bloom Level
alt Needs Clarification (모호한 질문)
QC-->>BE: Status: Needs_Clarification
BE->>QI: Redis Stream (Task: Improve)
QI-->>BE: "어떤 부분이 궁금한가요?" (역질문)
BE-->>S: 역질문 전송
else Answerable (명확한 질문)
QC-->>BE: Status: Answerable (Type: K3)
BE->>AG: Redis Stream (Task: Generate, Context: K3)
AG-->>BE: K3 맞춤형 답변 생성
BE-->>S: 답변 전송
end
Step 1: 분류 (Classification - Bloom’s Taxonomy)
QuestionClassifierAgent가 먼저 질문을 가로챕니다. 예를 들어 학생이 “수학적 귀납법 증명 어떻게 해?”라고 질문하면, 에이전트는 이 질문의 주제가 Mathematical Induction임을 파악하고, 구체적인 절차를 묻고 있으므로 K3 (Procedural) 유형으로 분류합니다. 그리고 질문이 충분히 명확하다고 판단하여 Answerable 상태로 다음 단계로 전달합니다.
Step 2: 명확화 (Clarification Loop - Dewey’s Reflective Thinking)
만약 질문이 “이거 모르겠어”라고만 들어왔다면? QuestionClassifier는 Needs_Clarification 상태를 반환합니다. 그러면 제어권은 AnswerGenerator가 아닌 QuestionImprovementAgent로 넘어갑니다.
Step 3: 답변 생성 (Generation)
분류가 완료되면 AnswerGenerator가 작동합니다. 이때 분류 단계에서 파악한 메타데이터(K3유형)를 프롬프트에 주입합니다.
4. 실패를 통해 배운 것들
교착 상태 (Deadlock)
초기에는 에이전트끼리 서로 답변을 기다리다 무한 루프에 빠지는 경우가 있었습니다. 이를 해결하기 위해 각 메시지에 hop_count를 도입하고, 순환 참조를 감지하는 미들웨어를 추가했습니다.
컨텍스트 관리
각 에이전트가 서로 다른 메모리를 가지다 보니 대화의 맥락이 끊기는 문제가 있었습니다. 이를 해결하기 위해 Redis에 Shared Session Context를 두어, 모든 에이전트가 현재까지의 대화 요약을 공유하도록 설계했습니다.
5. 교육적 효과: 왜 분업화가 중요한가?
5.1 하나의 LLM vs 전문가 에이전트 비교
초기 단일 프롬프트 방식과 멀티 에이전트 시스템을 내부 평가로 비교했습니다. 질문 분류 정확도, 명료화 적절성, 답변 교육적 품질, 응답 일관성 등 여러 지표에서 멀티 에이전트가 단일 LLM보다 유주한 개선을 보였습니다. 다만 이 내부 평가의 표본 크기와 세부 측정 방법은 별도로 문서화되어 있습니다.
5.2 Bloom 분류의 실제 효과
QuestionClassifier가 K1-K4로 정확히 분류한 질문에 대해, AnswerGenerator가 맞춤형 답변을 생성한 경우의 학습 성과를 측정했습니다. 상세한 실험 설계와 통계적 검증은 7편에서 다루고 있습니다.
핵심 발견: 단순히 답을 주는 것(K1)보다 개념 연결(K2)과 자기 평가(K4)를 유도하는 것이 학습 효과가 훨씬 크다.
5.3 ObserverAgent의 숨은 가치
뒤에서 조용히 대화를 관찰하는 ObserverAgent는 학습 분석(Learning Analytics) 기능을 제공합니다:
ObserverAgent는 학습 패턴을 발견하는 역할을 합니다. 예를 들어 “이 학생은 귀납법의 기초 단계는 이해했지만, 귀납 단계에서 반복적으로 막힘”과 같은 분석을 수행합니다. 이를 통해 교사에게 “주의 깊게 봐야 할 학생” 리스트를 제공하고, 다음 세션에서는 이전 대화 맥락을 활용하여 연속성 있는 개인별 맞춤 학습을 지원합니다.
실제 사례:
Observer 분석: "학생 C는 수학적 귀납법의 도미노 비유는 이해했으나,
n=k+1 단계에서 양변에 무엇을 더해야 하는지 3회 반복 질문함.
대수적 조작(algebraic manipulation) 능력이 부족한 것으로 판단됨."
교사 조치: 다음 수업에서 대수 조작 복습 세션 추가
결과: 학생 C의 다음 평가 점수 향상 (교사 조치와 MAICE 학습의 복합 효과)
6. 연구 결과로 본 멀티 에이전트의 우수성
6.1 A/B 테스트: Agent 모드 vs Freepass 모드
Agent 모드 (멀티 에이전트 협업)와 Freepass 모드 (단일 응답)를 비교:
| 지표 | Agent 모드 | Freepass 모드 | 통계적 유의성 |
|---|---|---|---|
| 학습 성과 향상 | +26.3점 | +17.4점 | p=0.003** |
상세한 통계 검증과 나머지 지표(메타인지, 질문 품질, 학생 만족도 등)는 7편에서 다루고 있습니다.
6.2 학생 인터뷰: “과정 자체가 학습”
“처음엔 명료화 질문이 귀찮았는데, 나중에 보니까 AI가 왜 그렇게 물어보는지 이해가 됐어요. 단계별로 생각하게 만드는 게 신기했어요.”
- 학생 D
“일반 ChatGPT는 막 길게 설명하는데, MAICE는 내 수준에 딱 맞는 설명을 해줘요. 어떻게 아는지 모르겠어요.”
- 학생 E (QuestionClassifier의 K-level 분류 덕분)
💬 댓글
이 글에 대한 의견을 남겨주세요