---
id: ai-multi-agent-coordination
title: Multi-Agent Coordination — orchestrator / handoff
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [ai, agents, vibe-coding]
tech_stack: { language: "TS / Python", applicable_to: ["AI"] }
applied_in: []
aliases: [multi-agent, agent orchestration, handoff, swarm, supervisor agent, AutoGen, CrewAI]
---

# Multi-Agent Coordination

> 1 agent ≠ all problems. **Orchestrator + specialist agents (search, code, write, review)**. Handoff / swarm / supervisor 패턴. CrewAI / AutoGen / LangGraph.

## 📖 핵심 개념
- 1 agent = jack of all trades.
- 다 agent = 전문화 + parallel.
- Coordination cost (handoff overhead).
- Communication = explicit message.

## 💻 코드 패턴

### Orchestrator (supervisor)
```ts
class Orchestrator {
  agents = {
    search: new SearchAgent(),
    code: new CodeAgent(),
    write: new WriterAgent(),
  };
  
  async run(task: string) {
    // LLM 가 routing 결정
    const plan = await this.plan(task);
    // → ['search', 'code', 'write']
    
    let context = task;
    for (const step of plan) {
      context = await this.agents[step].run(context);
    }
    return context;
  }
}
```

### Handoff (sequential)
```
User → Orchestrator → Agent A → Agent B → Agent C → User

Agent A 가 끝나면 결과 = Agent B 입력.
명시적.
```

### Swarm (peer-to-peer)
```
User → Agent A
Agent A 가 결정: "B 한테 handoff"
Agent B 가 결정: "C 한테"

→ 매 agent 가 다음 agent 결정.
OpenAI Swarm 의 idea.
```

### OpenAI Swarm 식
```python
from swarm import Agent, Swarm

triage_agent = Agent(
    name='Triage',
    instructions='Determine which agent should handle: support / sales / billing',
    functions=[transfer_to_support, transfer_to_sales, transfer_to_billing],
)

support_agent = Agent(name='Support', instructions='...')

def transfer_to_support():
    return support_agent

client = Swarm()
response = client.run(agent=triage_agent, messages=[...])
```

→ Function 가 다른 agent 반환 → handoff.

### CrewAI
```python
from crewai import Agent, Task, Crew

researcher = Agent(
    role='Senior Researcher',
    goal='Find latest tech news',
    backstory='...',
    tools=[search_tool],
)

writer = Agent(
    role='Tech Writer',
    goal='Write engaging summary',
    tools=[],
)

task1 = Task(description='Research AI news', agent=researcher)
task2 = Task(description='Write article', agent=writer, context=[task1])

crew = Crew(agents=[researcher, writer], tasks=[task1, task2])
result = crew.kickoff()
```

→ Sequential workflow.

### LangGraph
```python
from langgraph.graph import StateGraph

class State(TypedDict):
    messages: list
    next: str

def supervisor(state):
    # LLM 가 다음 agent 결정
    next_agent = llm.complete('Which agent? ' + state['messages'])
    return {'next': next_agent}

def search_agent(state): ...
def code_agent(state): ...

graph = StateGraph(State)
graph.add_node('supervisor', supervisor)
graph.add_node('search', search_agent)
graph.add_node('code', code_agent)

graph.add_edge('search', 'supervisor')
graph.add_edge('code', 'supervisor')

graph.add_conditional_edges(
    'supervisor',
    lambda s: s['next'],
    {'search': 'search', 'code': 'code', 'END': END},
)

graph.set_entry_point('supervisor')
app = graph.compile()
```

→ State machine + LLM-driven routing.

### Parallel (independent)
```ts
const [research, code] = await Promise.all([
  researchAgent.run(query),
  codeAgent.run(query),
]);

// 합치기
const final = await summarizer.run({ research, code });
```

→ 독립 task = parallel.

### Critic / reviewer
```ts
async function withCritic(agent, criticAgent, task, maxRounds = 3) {
  let solution = await agent.run(task);
  
  for (let i = 0; i < maxRounds; i++) {
    const review = await criticAgent.run({ task, solution });
    if (review.approved) return solution;
    solution = await agent.run({ task, feedback: review.feedback });
  }
  
  return solution;
}
```

→ Self-review loop.

### Roles 설계
```
- Researcher: search + summary
- Coder: write code
- Reviewer: critique
- Writer: prose
- Planner: decompose
- Executor: run tools
- QA: test

→ 매 = 명시적 prompt + tools.
```

### AutoGen
```python
from autogen import AssistantAgent, UserProxyAgent, GroupChat

assistant = AssistantAgent(name='Assistant', llm_config={...})
user_proxy = UserProxyAgent(name='User', code_execution_config={...})
critic = AssistantAgent(name='Critic')

groupchat = GroupChat(agents=[user_proxy, assistant, critic], messages=[])
manager = GroupChatManager(groupchat=groupchat)

user_proxy.initiate_chat(manager, message='Build a chess game')
```

→ Microsoft 의 multi-agent framework.

### Tool sharing vs isolation
```
공유: 모든 agent 가 모든 tool.
격리: agent 별 specific tool.

격리 = 안전 (search agent 가 file write 안 함).
공유 = simple.
```

### Memory
```ts
// Shared memory
const memory = new Memory();

agent1.memory = memory;
agent2.memory = memory;

→ 둘 다 같은 context.

// 또는 별 memory
agent1.memory = new Memory();  // 자기 노트
```

### 결정: when multi-agent?
```
✓ 다른 specialty (search vs code vs write)
✓ Parallelizable
✓ Iterate / review loop
✓ Long task (decompose)

✗ 작은 task (1 LLM 가 빠름)
✗ Cost sensitive (여러 agent = 여러 call $)
```

### Cost
```
1 task → 1 LLM call: $0.05
1 task → multi-agent (5 step): $0.25-1.00

→ 5x+ cost. Quality 가 가치 가져야.
```

### Latency
```
Sequential: 매 agent 가 시간 더.
Parallel: max(agent times).

→ Multi-agent 가 sequential 만 = 느림.
```

### Handoff message format
```ts
interface Handoff {
  from: AgentName;
  to: AgentName;
  task: string;
  context: any;
  attachments?: { type: 'file' | 'url'; path: string }[];
}
```

→ 명시적 schema. Debugging.

### Error handling
```ts
async function safeRun(agent, task) {
  try {
    return await agent.run(task);
  } catch (e) {
    return { error: e.message, agent: agent.name };
  }
}

// Orchestrator 가 error 처리
const result = await safeRun(searchAgent, q);
if (result.error) {
  return await fallbackAgent.run(q);
}
```

### Debug / trace
```ts
// LangSmith / Langfuse / OpenLLMetry
@trace
class Agent {
  run(task) {
    // 자동 record: input, output, tokens, latency
  }
}
```

→ 다 agent 의 path 시각화.

### Communication overhead
```
Agent A → context → Agent B.
Context 가 클수록 = 매 LLM 가 큰 token.

→ Compress (summarize) before handoff.
또는 reference (file path) only.
```

### Hierarchical (nested)
```
Project Manager Agent
├─ Research Manager
│   ├─ Web Search Agent
│   └─ Document Search Agent
├─ Engineering Manager
│   ├─ Frontend Agent
│   └─ Backend Agent
└─ QA Manager
```

→ Big org chart simulation.

### Voting / consensus
```ts
const answers = await Promise.all([
  agent1.run(q),
  agent2.run(q),
  agent3.run(q),
]);

const final = mostCommon(answers);
// 또는 reducer agent 가 합침
```

→ Hallucination 줄임. 비싼.

### 함정
```
- 너무 많은 agent: communication overhead > value
- Loop: A → B → A → B (infinite)
- 모든 agent 가 같은 LLM: 결과 같음
- Coordination 없는 swarm: chaos
- Tool 격리 없음: agent 가 all access
```

### Anthropic 의 권장
```
"단일 강한 LLM + tool 가 보통 multi-agent 보다 simple + 효과."

→ Multi-agent = 복잡 task 만 (parallel, review).
```

### Real-world
- **Devin** (Cognition): code agent + planner + reviewer.
- **AutoGPT**: 자기 분해 + 실행.
- **MetaGPT**: software dev role (PM, eng, QA).
- **Customer support**: triage + specialist + escalation.

## 🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| 작은 task | 1 agent |
| 다른 specialty | Multi-agent |
| Parallel work | Async multi-agent |
| Review loop | Agent + critic |
| Decompose | Planner + executor |
| Routing | Supervisor / triage |
| Production | Tracing + error handling |

## ❌ 안티패턴
- **모든 거 multi-agent**: 비싼 + 느린.
- **Loop 가능**: A → B → A 무한.
- **Tool 격리 없음**: agent 가 too much power.
- **Handoff 큰 context**: 매 token $$.
- **No tracing**: debug 불가.
- **Single LLM 가 모두 같음**: voting 의미 없음.
- **Critic 없이 single shot**: error.

## 🤖 LLM 활용 힌트
- 1 agent + tools 가 default. Multi 는 last resort.
- Supervisor / handoff 가 canonical pattern.
- LangGraph 가 state machine 식.
- Tracing (LangSmith / Langfuse) 필수.

## 🔗 관련 문서
- [[AI_Agentic_Patterns]]
- [[AI_LangGraph_Agent_Frameworks]]
- [[AI_Tool_Composition_Deep]]
