Multi-Agent 오케스트레이션
언제 멀티 에이전트가 필요한가?
섹션 제목: “언제 멀티 에이전트가 필요한가?”단일 에이전트는 컨텍스트 윈도우 한계, 도구 다양성 한계, 단일 실행 스레드 한계를 가집니다. 다음 상황에서 멀티 에이전트가 필요합니다:
- 태스크가 단일 컨텍스트 윈도우를 초과하는 경우
- 전문화된 에이전트가 각 도메인을 더 잘 처리하는 경우
- 독립적 태스크를 병렬로 실행해야 하는 경우
- 검증을 별도 에이전트가 독립적으로 수행해야 하는 경우
패턴 1: Supervisor (중앙 집중 조율)
섹션 제목: “패턴 1: Supervisor (중앙 집중 조율)”Supervisor 패턴에서는 중앙 에이전트(Supervisor)가 하위 에이전트들에게 태스크를 배분하고 결과를 통합합니다.
┌─────────────┐ │ Supervisor │ ← 사용자 요청 └──────┬──────┘ ┌───────────┼───────────┐ ↓ ↓ ↓┌───────┐ ┌───────┐ ┌───────┐│Agent A│ │Agent B│ │Agent C││(코드) │ │(테스트)│ │(문서) │└───────┘ └───────┘ └───────┘ └───────────┴───────────┘ ↓ 결과 통합 및 반환class SupervisorAgent:
def run(self, goal: str) -> str: # 태스크 분해 subtasks = self.llm.decompose(goal)
results = {} for subtask in subtasks: # 적합한 하위 에이전트 선택 agent = self.route_to_agent(subtask) results[subtask.id] = agent.run(subtask.description)
# 결과 통합 return self.llm.synthesize(goal, results)
def route_to_agent(self, subtask: Subtask) -> Agent: routing = { "code": self.code_agent, "test": self.test_agent, "docs": self.docs_agent, } return routing[subtask.type]적합한 상황:
- 태스크 유형이 명확히 구분되는 경우
- 중앙 조율이 필요한 복잡한 워크플로우
- 결과를 통합해야 하는 경우
주의사항: Supervisor가 단일 장애점(SPOF)이 됩니다. Supervisor 자체의 품질이 전체 시스템을 결정합니다.
패턴 2: Peer-to-Peer (직접 핸드오프)
섹션 제목: “패턴 2: Peer-to-Peer (직접 핸드오프)”P2P 패턴에서는 에이전트들이 서로 직접 핸드오프합니다. 중앙 조율자가 없고 각 에이전트가 다음 에이전트를 결정합니다.
Agent A → (핸드오프) → Agent B → (핸드오프) → Agent C ↑ │ └─────────────── (피드백 루프) ─────────────────┘@dataclassclass HandoffMessage: from_agent: str to_agent: str content: str metadata: dict
class PeerAgent: def run(self, message: HandoffMessage) -> HandoffMessage | None: result = self.process(message.content)
# 다음 에이전트 결정 next_agent = self.determine_next(result) if next_agent is None: return None # 파이프라인 종료
return HandoffMessage( from_agent=self.name, to_agent=next_agent, content=result, metadata={"previous": message.metadata}, )적합한 상황:
- 선형 파이프라인 (A → B → C)
- 각 단계의 책임이 명확한 경우
- 에이전트 추가/제거가 자주 필요한 경우
패턴 3: Hierarchical (계층 구조)
섹션 제목: “패턴 3: Hierarchical (계층 구조)”Hierarchical 패턴은 트리 구조로 에이전트를 조직합니다. 상위 에이전트가 하위 에이전트를 관리하고, 하위 에이전트는 다시 더 하위 에이전트를 가질 수 있습니다.
┌──────────────┐ │ Coordinator │ Level 0 └──────┬───────┘ ┌─────────┴─────────┐ ↓ ↓ ┌──────────┐ ┌──────────┐ │ Manager A│ │ Manager B│ Level 1 └────┬─────┘ └────┬─────┘ ┌────┴────┐ ┌────┴────┐ ↓ ↓ ↓ ↓Worker1 Worker2 Worker3 Worker4 Level 2적합한 상황:
- 대규모 복잡 태스크 (대형 코드베이스 전체 리팩토링)
- 도메인별 전문화가 필요한 경우
- 병렬 실행과 조율이 동시에 필요한 경우
패턴 비교
섹션 제목: “패턴 비교”| 기준 | Supervisor | Peer-to-Peer | Hierarchical |
|---|---|---|---|
| 복잡도 | 중간 | 낮음 | 높음 |
| 확장성 | 제한적 | 높음 | 매우 높음 |
| 디버깅 용이성 | 중간 | 높음 | 낮음 |
| 병렬 실행 | 가능 | 제한적 | 매우 용이 |
| 단일 장애점 | 있음 | 없음 | 있음 (각 레벨) |
| 적합 규모 | 중소형 | 소형 | 대형 |
멀티 에이전트 설계 원칙
섹션 제목: “멀티 에이전트 설계 원칙”1. 최소 에이전트 원칙
섹션 제목: “1. 최소 에이전트 원칙”필요 이상으로 에이전트를 추가하지 마세요. 에이전트가 늘어날수록 오케스트레이션 복잡도가 기하급수적으로 증가합니다.
2. 명확한 인터페이스
섹션 제목: “2. 명확한 인터페이스”에이전트 간 통신은 구조화된 형태로 정의하세요.
@dataclassclass AgentMessage: task_id: str content: str context: dict expected_output_format: str # 출력 형식 명시3. 격리와 독립성
섹션 제목: “3. 격리와 독립성”각 에이전트는 가능한 한 독립적으로 작동해야 합니다. 공유 상태를 최소화하고, 각 에이전트가 자체 완결적인 컨텍스트를 갖도록 설계하세요.
# 나쁜 패턴: 공유 전역 상태shared_state = {}
# 좋은 패턴: 메시지 패싱def agent_b(message_from_a: AgentMessage) -> AgentMessage: # message_from_a에만 의존, 전역 상태 없음 result = process(message_from_a.content) return AgentMessage(task_id=message_from_a.task_id, content=result)Multi-Agent 오케스트레이션은 Supervisor(중앙 조율), P2P(직접 핸드오프), Hierarchical(계층 구조) 세 가지 핵심 패턴으로 구성됩니다. 패턴 선택은 태스크 규모, 병렬화 필요성, 디버깅 용이성을 기준으로 합니다. 최소 에이전트 원칙을 지키고 명확한 인터페이스를 설계하는 것이 안정적인 멀티 에이전트 시스템의 기반입니다.
Section 02 학습을 완료했습니다. 다음 Section 03에서는 세 축 중 첫 번째인 Context Engineering을 심화 학습합니다.