Orchestration Patterns
Why Multi-Agent Orchestration Matters
The Problem: Complex tasks often exceed a single agent's capabilities. You need multiple specialized agents working together, but coordinating them introduces challenges around communication, state sharing, and conflict resolution.
The Solution: Orchestration patterns provide proven architectures for coordinating multiple agents -- from simple supervisor hierarchies to dynamic swarm topologies with peer-to-peer communication.
Real Impact: Companies like Salesforce and Microsoft use multi-agent orchestration to power enterprise automation workflows that handle thousands of concurrent tasks.
Real-World Analogy
Think of multi-agent orchestration like an orchestra performance:
- Supervisor Pattern = Conductor directing each section when to play
- Peer-to-Peer = Jazz ensemble where musicians listen and respond to each other
- Shared State = The musical score that all musicians reference
- Message Passing = Musical cues passed between sections
- Conflict Resolution = The conductor resolving when two sections clash
Key Orchestration Patterns
Supervisor Pattern
A central manager agent delegates tasks, reviews outputs, and coordinates the workflow. Best for structured, hierarchical processes.
Swarm Architecture
Agents self-organize and dynamically hand off tasks based on capability matching. Best for flexible, emergent workflows.
Pipeline Pattern
Agents are arranged in a linear chain where each agent transforms and passes data to the next. Best for sequential processing.
Broadcast Pattern
One message is sent to all agents simultaneously, and results are aggregated. Best for parallel analysis from multiple perspectives.
Supervisor Pattern
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated, Literal
import operator
class OrchestratorState(TypedDict):
messages: Annotated[list, operator.add]
next_agent: str
results: dict
def supervisor(state: OrchestratorState):
"""Central supervisor that routes tasks to agents."""
llm = ChatOpenAI(model="gpt-4")
response = llm.invoke(
f"""You are a supervisor managing agents: researcher, writer, reviewer.
Based on the current state, decide which agent should act next.
Respond with just the agent name or 'FINISH' if done.
Current results: {state['results']}"""
)
return {"next_agent": response.content.strip()}
def researcher_agent(state):
# Research logic here
return {"results": {"research": "findings..."}}
def writer_agent(state):
# Writing logic here
return {"results": {"draft": "content..."}}
# Build orchestration graph
graph = StateGraph(OrchestratorState)
graph.add_node("supervisor", supervisor)
graph.add_node("researcher", researcher_agent)
graph.add_node("writer", writer_agent)
graph.set_entry_point("supervisor")
graph.add_conditional_edges("supervisor", lambda s: s["next_agent"], {
"researcher": "researcher",
"writer": "writer",
"FINISH": END,
})
graph.add_edge("researcher", "supervisor")
graph.add_edge("writer", "supervisor")
Swarm Architecture
Swarm vs Supervisor
- Swarm: Agents hand off to each other based on capability. No central coordinator. More flexible but harder to debug.
- Supervisor: One agent controls the flow. Predictable but can become a bottleneck.
- Hybrid: Supervisor for high-level routing, swarm within sub-teams for flexibility.
Communication Protocols
# Shared state approach
class SharedState(TypedDict):
task_queue: list[str]
completed: list[dict]
agent_status: dict[str, str]
# Message passing approach
class AgentMessage:
sender: str
receiver: str
content: str
message_type: str # "request", "response", "handoff"
# Task routing based on capability
def route_task(task: str, agents: list) -> str:
"""Route task to the most capable agent."""
capabilities = {
"researcher": ["search", "analyze", "summarize"],
"coder": ["code", "debug", "test"],
"writer": ["write", "edit", "format"],
}
for agent, skills in capabilities.items():
if any(s in task.lower() for s in skills):
return agent
return "researcher" # default
Conflict Resolution
Common Pitfall
Problem: Agents produce contradictory outputs or get stuck in delegation loops.
Solution: Implement a maximum delegation depth, use a voting mechanism for conflicting outputs, and add a timeout that escalates to the supervisor when agents cannot reach agreement.
Quick Reference
| Pattern | Best For | Trade-offs |
|---|---|---|
| Supervisor | Structured workflows | Predictable but single point of failure |
| Swarm | Dynamic tasks | Flexible but harder to debug |
| Pipeline | Sequential processing | Simple but no parallelism |
| Broadcast | Parallel analysis | Fast but expensive (N agents) |
| Hybrid | Complex systems | Best of both but more complexity |
| Shared State | Tight coordination | Easy data access but race conditions |
| Message Passing | Loose coupling | Clean interfaces but more overhead |