One agent is powerful. Multiple agents working together? That's where it gets wild.
Think about how a software company works. You don't have one person who writes code, reviews it, tests it, deploys it, and writes the documentation. You have a developer, a reviewer, a QA engineer, a DevOps person. Each one is specialized. They hand off work to each other. They argue, refine, and iterate.
Multi-agent systems work the same way. Instead of one massive prompt trying to do everything, you split the work across multiple specialized agents โ each with their own tools, prompts, and expertise. The result is often better, cheaper, and more reliable than a single agent trying to be a jack of all trades.
Why Not Just One Agent?
A single agent hits limits fast:
Context window bloat. A complex task might require a coding tool, web search, file management, database access, email sending, and calendar checking. Define 30 tools in one prompt and the model drowns in options. It starts calling the wrong tools.
Conflicting instructions. "Be creative and exploratory" for brainstorming conflicts with "Be precise and careful" for code review. One agent can't be both at the same time.
Error amplification. In a 50-step loop, one bad decision cascades. A wrong search result leads to a wrong conclusion leads to wrong code leads to a broken deployment. Multiple agents can catch each other's mistakes.
Cost. A single agent with a massive context window running for 100 steps costs a fortune. Splitting work across agents with smaller contexts can be dramatically cheaper.
The Four Orchestration Patterns
Every multi-agent system follows one of these patterns (or a combination):
- Sequential (Pipeline)
Agents run one after another, each taking the previous agent's output as input.
User Task โ [Agent A: Research] โ [Agent B: Write] โ [Agent C: Review] โ Final Output
python
Sequential pipeline
research = research_agent.run("Find latest trends in AI agents")
draft = writer_agent.run(f"Write a blog post based on this research:\n{research}")
final = editor_agent.run(f"Review and polish this draft:\n{draft}")Use when: Tasks have clear, ordered stages. Each stage is independent enough that a specialized agent does it better.
Example: Content creation pipeline โ research โ write โ review โ publish.
- Parallel (Fan-out / Fan-in)
Multiple agents work simultaneously on different parts of the task.
โโ [Agent A: Search Google] โโโUser Task โโโโโโโผโ [Agent B: Search Reddit] โโโผโ [Aggregator] โ Output
โโ [Agent C: Search Papers] โโโpython
Parallel execution
import asyncio
async def parallel_research(topic):
results = await asyncio.gather(
google_agent.run(f"Search Google for: {topic}"),
reddit_agent.run(f"Search Reddit for: {topic}"),
papers_agent.run(f"Search arXiv for: {topic}")
)
return aggregator_agent.run(
f"Synthesize these findings:\n{results}"
)Use when: Different data sources or perspectives can be gathered independently.
Example: Competitive analysis โ one agent researches each competitor, then an aggregator combines findings.
- Supervisor (Boss Pattern)
One "boss" agent coordinates others, assigning tasks and reviewing results.
User Task โ [Supervisor Agent]
โโโ assigns to โ [Agent A] โ result โ Supervisor reviews
โโโ assigns to โ [Agent B] โ result โ Supervisor reviews
โโโ decides โ Final Outputpython
Supervisor pattern
supervisor_prompt = """You are a project manager. You have these team members:- researcher: Can search the web and read pages
- coder: Can write and execute Python code
- writer: Can write polished text
Decide who should handle each part of the task.
Review their work and request revisions if needed."""
def supervisor_loop(task):
messages = [
{"role": "system", "content": supervisor_prompt},
{"role": "user", "content": task}
]while True:
decision = llm.complete(messages, tools=delegation_tools)if decision.tool_calls:
for call in decision.tool_calls:
if call.function.name == "delegate":
agent = call.function.arguments["agent"]
sub_task = call.function.arguments["task"]
result = agents[agent].run(sub_task)
messages.append(tool_result(call.id, result))
else:
return decision.content # Supervisor's final answerUse when: Tasks require dynamic decision-making about what to do next. The supervisor adapts the plan based on intermediate results.
Example: Software development โ PM agent breaks down an issue, assigns coding to a dev agent, review to a QA agent, and iterates.
- Swarm (Peer-to-Peer)
Agents hand off to each other without a central coordinator. Each agent decides when to pass control and to whom.
User โ [Agent A] โโโ handoff โโโ [Agent B] โโโ handoff โโโ [Agent C]
โ
โโโ handoff back โโโ [Agent A]python
Swarm pattern (OpenAI Swarm style)
from swarm import Swarm, Agent
sales_agent = Agent(
name="Sales",
instructions="Handle sales inquiries. Transfer to support for technical issues.",
functions=[transfer_to_support, check_inventory, create_quote])
support_agent = Agent(
name="Support",
instructions="Handle technical support. Transfer to sales for pricing questions.",
functions=[transfer_to_sales, lookup_docs, create_ticket])
The conversation flows between agents based on context
client = Swarm()
response = client.run(
agent=sales_agent,
messages=[{"role": "user", "content": "I want to buy your API, but I have a bug to report first"}])
Sales agent โ recognizes bug report โ handoff to Support agent
Use when: The task type isn't known upfront and different agents handle different kinds of requests. Common in customer service, routing, and triage.
๐ง
Pattern Comparison
Pattern Coordination Best For Complexity Cost
Sequential Fixed order Staged pipelines Low Low
Parallel Fan-out/fan-in Independent subtasks Medium Medium
Supervisor Central boss Dynamic task planning High High
Swarm Peer handoffs Routing, customer service Medium Variable
In practice, most real systems combine patterns. A supervisor might delegate to agents that run sequential pipelines. A swarm might have agents that internally run parallel searches.
๐
Handoffs: The Critical Mechanism
The most important concept in multi-agent systems is the handoff โ how one agent passes control and context to another.
A good handoff includes:
python
handoff = {
"from_agent": "researcher",
"to_agent": "writer",
"context": "Research findings on AI agents in 2025",
"data": research_results, # What was found
"instructions": "Write a blog post, 1000 words, casual tone",
"constraints": "Don't include competitor names",
"success_criteria": "Engaging, technically accurate, has code examples"}
A bad handoff just dumps everything: "Here's all my research, write something." The receiving agent drowns in context and produces generic output.
Rule of thumb: Each handoff should contain:
What was done (summary, not raw data)
What needs to be done next (specific instructions)
What "done" looks like (success criteria)
Multi-Agent Communication
How do agents actually talk to each other? Three approaches:
Shared Memory (Blackboard)
All agents read from and write to a shared state:
python
shared_state = {
"research": None,
"draft": None,
"review_comments": [],
"final": None}
Agent A writes
shared_state["research"] = research_agent.run(task)
Agent B reads A's output, writes its own
shared_state["draft"] = writer_agent.run(shared_state["research"])
Pros: Simple, agents can access any previous output.
Cons: No access control, agents can overwrite each other.
Message Passing
Agents send structured messages to each other:
python
Agent A sends a message to Agent B
message_bus.send(
from_agent="researcher",
to_agent="writer",
content={"research": findings, "instruction": "Write blog post"})
Agent B receives and processes
message = message_bus.receive("writer")
draft = writer_agent.run(message.content)Pros: Clean interfaces, agents are decoupled.
Cons: More complex to set up.
Direct Function Calls
Agents call each other like functions:
python
The simplest approach
research = research_agent("Find info on AI agents")
draft = writer_agent(f"Write based on: {research}")
review = reviewer_agent(f"Review this: {draft}")Pros: Dead simple.
Cons: Tight coupling, hard to parallelize.
Real-World Multi-Agent Examples
System Pattern Agents
| ChatGPT (internally) | Supervisor | Router โ specialist models (code, web, image) |
|---|---|---|
| Devin | Sequential + Supervisor | Planner โ Coder โ Tester โ Debugger |
| CrewAI projects | Supervisor | Researcher, Writer, Critic in a "crew" |
| Customer service bots | Swarm | Triage โ Sales / Support / Billing |
| GitHub Copilot Workspace | Sequential | Analyzer โ Planner โ Implementer โ Reviewer |
๐ฌ
The Debate Pattern
One powerful multi-agent pattern: make agents argue with each other.
python
Two agents debate, a judge decides
proposition = "We should use microservices for this project"
for_agent = Agent(instructions="Argue IN FAVOR of the proposition. Be specific.")
against_agent = Agent(instructions="Argue AGAINST the proposition. Be specific.")
judge_agent = Agent(instructions="Evaluate both arguments. Pick the stronger one.")
argument_for = for_agent.run(proposition)
argument_against = against_agent.run(proposition)
verdict = judge_agent.run(f"""Proposition: {proposition}
For: {argument_for}
Against: {argument_against}
Which argument is stronger and why?
""")
This produces more nuanced analysis than asking a single agent "should we use microservices?" because each debater tries to find the strongest version of their position.
๐ก๏ธ
Cost and Latency Considerations
Multi-agent systems multiply your costs:
Single Agent Multi-Agent (3 agents)
| 1 LLM call per step | 3+ LLM calls per step |
|---|---|
| ~$0.01 per task | ~$0.03-0.10 per task |
| 2-5 seconds latency | 5-15 seconds (sequential) |
| Simple to debug | Complex to debug |
Cost optimization tips:
Use cheaper models for simple agents (Haiku for routing, Opus for reasoning)
Run independent agents in parallel
Cache repeated tool results
Set strict token limits per agent
Use the minimum number of agents needed โ don't over-architect
๐ฆ
Practical Takeaways
Multi-agent = specialization โ each agent has focused tools, instructions, and expertise
Four patterns cover 95% of cases โ sequential, parallel, supervisor, swarm
Handoffs are the hard part โ clear context transfer makes or breaks multi-agent systems
Use different models for different agents โ expensive models for reasoning, cheap models for routing
Start with one agent, split when needed โ premature multi-agent design is worse than a good single agent
The debate pattern produces surprisingly good analysis โ make agents argue for better outputs
๐
What's Next?
Episode 33: Agent Memory โ An agent that forgets everything after each conversation is useless for real work. How do agents remember? Short-term memory (context window) vs long-term memory (vector stores). Episodic vs semantic memory. And why your AI assistant keeps asking the same questions.
โ Previous
Ep 31: ReAct Pattern
Next โ
Ep 33: Agent Memory
Next: Episode 33 โ Agent Memory
You've told ChatGPT your name ten times. It keeps asking. Here's why AI memory is so hard โ and how agents solve it.
This is part of a 98-episode series covering AI engineering from tokens to production deployment.