Multi-Agent Systems
Coordination patterns, communication protocols, and architectures for building systems of multiple collaborating AI agents.
What Are Multi-Agent Systems?
Multi-Agent Systems (MAS) are architectures where two or more LLM-powered agents — each with distinct roles, tools, or instructions — collaborate, coordinate, or compete to accomplish tasks that would be difficult or impossible for a single agent. Each agent is typically an LLM instance wrapped with a system prompt defining its role, access to specific tools, memory capabilities, and decision-making logic.
"Start with the simplest solution. Use a single LLM call if possible, then a single agent with tools, and only then consider multi-agent when single-agent complexity becomes unmanageable."
Specialization
Expert agents per domain
Parallelism
Concurrent execution
Checks & Balances
Agents verify each other
Scalability
Add agents, not complexity
Architecture Patterns
Hierarchical (Supervisor / Manager)
A supervisor agent receives the user request, decomposes it into subtasks, and delegates to specialized worker agents. The supervisor collects results, synthesizes them, and may re-delegate if quality is insufficient.
┌─────────────┐
│ Supervisor │
└──────┬───────┘
┌───────┼───────┐
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Research│ │ Coder │ │Reviewer│
└────────┘ └────────┘ └────────┘
Pipeline / Sequential
Agents arranged in a fixed linear chain. Each agent transforms or enriches the output before passing it downstream. Simple, predictable, and easy to test each stage independently.
┌──────┐ ┌─────────┐ ┌──────────┐ ┌──────┐
│Search│ ──▶│ Extract │ ──▶│Summarize │ ──▶│ Edit │
└──────┘ └─────────┘ └──────────┘ └──────┘
Peer-to-Peer / Collaborative
Agents communicate directly with each other without a central coordinator. Each agent decides when to pass work to another agent based on its own assessment. More flexible but harder to debug; risk of infinite loops or circular delegation.
Debate / Adversarial
Two or more agents argue opposing positions or critique each other's outputs. A judge agent (or the user) decides the final answer. Reduces hallucination and surfaces edge cases, but is expensive since it requires multiple full reasoning passes.
Swarm
Inspired by biological swarms. Large numbers of lightweight agents each follow simple rules; complex behavior emerges from interactions. Agents are defined minimally with instructions and tools, and handoffs are simply tool calls that return another agent.
Core Design Patterns
Based on Anthropic's "Building Effective Agents" guide and real-world production systems:
Orchestrator-Worker
An orchestrator actively plans and adapts, delegating to workers and synthesizing results. Differs from a simple supervisor by its ability to re-plan dynamically.
Evaluator-Optimizer
One agent generates output, another evaluates it. If evaluation fails, feedback loops back for revision. Ideal for code gen + review or writing + editing.
Fan-Out / Fan-In
Split a task into independent subtasks that run concurrently (fan-out), then aggregate results (fan-in). Critical for latency reduction.
Routing
A router agent classifies the input and directs it to the appropriate specialized agent. Can be LLM-based or rule-based. Common in customer service triage.
Handoff Patterns
How agents transfer control and context to each other is critical for both system reliability and user experience:
| Pattern | Description | Used By |
|---|---|---|
| Hard Handoff | Control transfers completely; the original agent exits | OpenAI Swarm, Claude Agent SDK |
| Soft Handoff | Original agent delegates but remains in the loop and can intervene | LangGraph Supervisor |
| Context Transfer | Full history, summary, or structured handoff object passed between agents | All frameworks |
Best Practice: Careful handoff design directly impacts user experience. In conversational settings, the user should not notice the agent switch. Use structured handoff objects (JSON schemas) rather than passing full conversation history to reduce cost and ambiguity.
Communication Protocols
Message Passing
Agents exchange natural-language messages or structured JSON through a shared message bus. Used by AutoGen's GroupChat and LangGraph's state channels. Simple and human-readable, but token-expensive at scale.
Shared Memory / State
Agents read and write to a common state object (TypedDict, Pydantic model, Redis, or vector store). Efficient for structured data and avoids repeating information, but requires careful schema design and handling of race conditions in parallel execution.
Tool-Based Coordination
Agents coordinate by calling shared tools — e.g., a
delegate_to_researcher
tool that invokes another agent. Both OpenAI Swarm and
Claude Agent SDK use this pattern: a handoff is literally a function call.
A2A Protocol (Google)
An open protocol for agent interoperability across frameworks and vendors. Uses Agent Cards (JSON metadata describing capabilities), structured Tasks as work units, and supports streaming via SSE and push notifications.
A2A vs MCP: A2A handles agent-to-agent communication, while MCP (Model Context Protocol by Anthropic) handles agent-to-tool communication. They are complementary, not competing standards.
Frameworks Comparison
| Framework | By | Approach | Best For |
|---|---|---|---|
| LangGraph | LangChain | Graph-based orchestration with cyclic flows | Production complex workflows |
| AutoGen v0.4 | Microsoft | Event-driven, actor-based architecture | Conversational multi-agent setups |
| CrewAI | CrewAI | Role-based agent teams with tasks | Fast prototyping, intuitive API |
| Claude Agent SDK | Anthropic | Tool-based handoffs, minimal abstraction | Simple, reliable agent chains |
| OpenAI Swarm | OpenAI | Lightweight handoff-based swarm | Learning, experimental |
| Google ADK | Hierarchical agents with A2A support | Google Cloud / Gemini integration | |
| Mastra | Mastra | TypeScript-first with built-in RAG | Node.js / TypeScript teams |
Implementation Examples
LangGraph — Supervisor Pattern
from langgraph.graph import StateGraph, MessagesState
from langgraph.prebuilt import create_react_agent
# Define specialized worker agents
research_agent = create_react_agent(model, tools=[search, wiki])
code_agent = create_react_agent(model, tools=[python_repl, file_write])
def supervisor(state: MessagesState):
"""Route to the right specialist based on the task."""
response = model.invoke([
SystemMessage("You are a supervisor. Route tasks to: researcher or coder."),
*state["messages"]
])
return {"next": response.content}
# Build the multi-agent graph
graph = StateGraph(MessagesState)
graph.add_node("supervisor", supervisor)
graph.add_node("researcher", research_agent)
graph.add_node("coder", code_agent)
graph.add_conditional_edges("supervisor", route_fn)
graph.set_entry_point("supervisor")
app = graph.compile()
CrewAI — Role-Based Team
from crewai import Agent, Task, Crew, Process
researcher = Agent(
role="Senior Researcher",
goal="Find accurate and up-to-date information",
tools=[search_tool, scrape_tool]
)
writer = Agent(
role="Technical Writer",
goal="Create clear, engaging technical content",
tools=[file_tool]
)
research_task = Task(description="Research multi-agent systems trends", agent=researcher)
write_task = Task(description="Write a report from findings", agent=writer)
crew = Crew(
agents=[researcher, writer],
tasks=[research_task, write_task],
process=Process.sequential # or Process.hierarchical
)
result = crew.kickoff()
OpenAI Swarm — Handoff Pattern
from swarm import Swarm, Agent
client = Swarm()
def transfer_to_sales():
"""Hand off to the sales agent."""
return sales_agent
triage_agent = Agent(
name="Triage",
instructions="Route customer to the right department.",
functions=[transfer_to_sales, transfer_to_support]
)
sales_agent = Agent(
name="Sales",
instructions="Help customers with purchases and pricing."
)
response = client.run(agent=triage_agent, messages=[{"role": "user", "content": "I want to buy"}])
Key Challenges
State Management
Agents must share relevant context without exceeding token limits. State consistency across parallel agents requires centralized stores and checkpointing.
Error Propagation
One agent failure can cascade. Use retry with backoff, fallback agents, circuit breakers, and human-in-the-loop escalation for resilience.
Cost Multiplication
N agents × M turns × token costs. Mitigate with smaller models for simple tasks, caching, recursion limits, and structured outputs to reduce token waste.
Debugging & Observability
Non-determinism and complex interaction paths make debugging hard. Trace visualization, token tracking, and replay/time-travel capabilities are essential.
Security & Trust Boundaries
Prompt injection can propagate between agents. Define clear trust boundaries, use least-privilege tool access, sanitize inputs at agent boundaries, and audit all inter-agent communication. Sandbox agents with access to dangerous tools (code execution, file system, network).
Real-World Use Cases
Software Development Teams
Coding agent writes code, review agent checks for bugs and security issues, testing agent generates tests, DevOps agent handles deployment. The reviewer catching the coder's mistakes significantly improves output quality.
Research Assistants
Search agent queries multiple sources, analysis agent extracts key findings, synthesis agent combines into a coherent report, fact-check agent verifies claims.
Customer Service Escalation
Triage agent classifies incoming requests, FAQ agent handles common questions, specialist agents tackle domain-specific issues (billing, technical, returns), escalation agent brings in humans when needed.
Data Analysis Pipelines
Ingestion agent connects to data sources, SQL agent writes queries, visualization agent creates charts, insight agent identifies trends, report agent generates natural-language summaries.
When to Use Multi-Agent vs Single Agent
Use Multi-Agent When
- Task requires distinct expertise areas
- You need parallel execution for latency
- Checks and balances improve quality
- Different security boundaries per stage
- Clear handoff points between roles
Stick With Single Agent When
- Task fits in one system prompt
- Latency is critical (each agent adds delay)
- Budget is constrained (multi-agent = higher cost)
- No benefit from separation of concerns
- Simplicity is the priority
Best Practices
Single Responsibility per Agent
Each agent should do one thing well. A separate "code" and "review" agent is better than a single "code_and_review" agent.
Minimal Context per Agent
Give each agent only the context it needs. Summarize, don't relay full conversation history. Use structured JSON schemas for inter-agent communication.
Right Model for the Job
Not every agent needs the most capable model. Use smaller/cheaper models for routing and classification, reserve expensive models for complex reasoning.
Set Recursion Limits
Always limit maximum turns and recursion depth to prevent runaway loops and unbounded costs. Prune conversation history periodically in group chat scenarios.
Independent Testability
Each agent should be independently testable with known inputs and expected outputs. Test agents in isolation before testing the full system.