↑ Contents Chapter 9 of 12

Chapter 9: Multi-Agent Systems

Rosa's bookshop has grown. The agent now handles inventory searches, policy questions, order calculations, and customer emails β€” all in one loop. It works, but it's getting tangled. The system prompt is three paragraphs long. The tool list has nine tools. Sometimes the agent calls search_books when the customer asked about shipping. Sometimes it drafts an email when it should have just answered a question. "It's trying to do everything," TomΓ‘s says, "and it's doing nothing well." Priya looks at the mess and says the thing TomΓ‘s didn't want to hear: "You don't need a bigger agent. You need more agents. Split the work. One that knows books. One that knows policy. One that writes emails. Let them hand tasks to each other." "Like a team?" "Like a team. You're the manager now, not the agent."

Why This Matters

By the end of this chapter, you'll understand why a single agent with too many tools gets worse, not better. You'll build a multi-agent system where specialised agents hand work to each other β€” a researcher, a writer, a reviewer β€” and you'll see how the agent loop from Chapter 3 scales up to a team. You'll also know when multi-agent is the right answer and when it's overkill.

The Problem: One Agent, Too Many Hats

Here's a pattern you'll hit eventually: you keep adding tools to your agent, and at some point it gets worse. Not because the tools are bad, but because the LLM has to reason over more and more tool descriptions to decide which to use. Nine tools means nine descriptions to read every turn. The model gets confused. It calls the wrong tool. It forgets which task it's on.

One agent, too many tools β†’ confusion One Agent 9 tools, 3-paragraph prompt search_books calculate search_docs send_email + 5 more tools "Which tool do I use??"
More tools isn't always better. The LLM has to reason over every description, every turn.

This isn't a failure of the model β€” it's a design problem. A human generalist who tries to do accounting, marketing, customer service, and IT support will be worse at each than four specialists. Agents are the same. Specialisation makes each agent better at its job.

The Solution: Split the Work

Instead of one agent with nine tools, build several agents, each with a focused job and a small tool set. Then let them hand work to each other.

A team of specialists Manager Agent routes tasks, no tools of its own Inventory Agent search_books, calculate Policy Agent search_documents (RAG) Email Agent send_email, draft_reply The manager reads the request and hands it to the right specialist.
Each agent has a focused job and a small tool set. The manager routes.

How Agents Hand Off Work

Here's the key question: how does one agent call another? The answer is beautiful in its simplicity: one agent is another agent's tool. The manager agent has a tool called ask_inventory_agent, and when it calls that tool, it runs the inventory agent's loop and returns the result.

# The manager's "tools" are actually other agents def ask_inventory_agent(question: str) -> str: """Ask the inventory specialist about books, stock, or prices.""" # Run the inventory agent's loop with this question return inventory_agent.run(question) def ask_policy_agent(question: str) -> str: """Ask the policy specialist about returns, shipping, or membership.""" return policy_agent.run(question) def ask_email_agent(task: str) -> str: """Ask the email specialist to draft or send emails.""" return email_agent.run(task)
// Each specialist agent is wrapped as a tool. The manager calls them like any other function.

The manager agent has no tools of its own β€” it only has the three "ask_*" tools. Its job is to read the user's request and decide which specialist to route it to. It's a router, not a doer.

# The manager's system prompt MANAGER_PROMPT = """You are the manager of a bookshop agent team. You don't answer questions yourself. Instead, you route each request to the right specialist: - ask_inventory_agent: for questions about books, stock, or prices - ask_policy_agent: for questions about returns, shipping, or membership - ask_email_agent: for drafting or sending emails Read the user's request, decide which specialist handles it, and call that tool. If a request needs multiple specialists, call them in order and combine their answers."""
// The manager doesn't do the work β€” it decides who should. Routing, not doing.

Watching the Team Work

Let's trace a request that needs two specialists:

User: "Do you have Le Guin's latest book, and what's your return policy?" # Manager agent loop THINK "Two questions here. Books β†’ inventory agent. Policy β†’ policy agent. I'll call both." ACT ask_inventory_agent("Do you have Le Guin's latest book?") # ↓ this runs the inventory agent's own loop # inventory agent calls search_books, gets results OBSERVE "Yes: 'The Telling' by Le Guin, €14, 2 in stock." ACT ask_policy_agent("What's the return policy?") # ↓ this runs the policy agent's own loop # policy agent calls search_documents (RAG), gets passage OBSERVE "Items may be refunded within 30 days with receipt." THINK "I have both answers. Combine and respond." Manager: "Yes, we have 'The Telling' by Le Guin (€14, 2 in stock). Our return policy: items can be refunded within 30 days with receipt."
// The manager routed to two specialists, each ran their own loop, and the manager combined the results.

Each specialist is a full agent β€” its own loop, its own tools, its own system prompt. The manager doesn't know how they work inside; it just knows what they're for. This is encapsulation, the same idea from software engineering: each agent is a module with a clear interface.

Note The handoff pattern is just the tool pattern from Chapter 4, one level up. A tool is a function the agent calls. An agent-as-tool is a function that runs another agent's loop. The manager doesn't know or care what's inside β€” it just calls the function and gets a string back. Same interface, deeper capability.

Patterns for Multi-Agent Systems

There are a few common ways to arrange multiple agents. Each fits different problems:

Pattern 1: Router (Manager + Specialists)

What we just built. A manager routes requests to specialists. Good for customer service, help desks, any system with distinct domains.

Pattern 2: Pipeline (Sequential)

Agents in a line, each handing its output to the next. A researcher gathers facts, a writer drafts from those facts, an editor polishes. Good for content creation, report generation, any multi-stage process.

Researcher gathers facts Writer drafts article Editor polishes
Pipeline: each agent's output feeds the next. Sequential, stage by stage.

Pattern 3: Debate (Critics)

One agent produces an answer, another critiques it, the first revises. Good for tasks where quality matters and a single pass isn't enough β€” code review, fact-checking, argument refinement.

Writer drafts answer Critic finds problems draft feedback
Debate: writer drafts, critic reviews, writer revises. Loop until good.
Geek Bits These patterns map to frameworks. LangChain's create_react_agent handles single agents. LangGraph (from the LangChain team) is designed for multi-agent workflows β€” it models agents as nodes in a graph, with edges defining how control passes between them. CrewAI and AutoGen take different approaches: CrewAI focuses on "crews" of role-based agents, AutoGen on conversational agents that talk to each other. The patterns here are framework-agnostic; the frameworks are implementations of them.
There Are No Dumb Questions
Q: How many agents is too many?
A: There's no hard limit, but each agent adds complexity and cost. Every handoff is a full LLM call. A 10-agent pipeline means 10 LLM calls per request. Start with the fewest agents that solve the problem. If one agent can do the job with 3 tools, don't split it into 3 agents. Split when specialisation genuinely improves quality β€” not because it sounds cool.
Q: Can agents call each other in a loop? What if agent A calls B, B calls A?
A: Yes, and this is a real danger. Circular handoffs β€” A calls B, B calls A β€” can loop forever, each agent delegating to the other. The fix is the same as always: set a max depth or max turns on the outer loop. In LangGraph, you set recursion limits. In hand-rolled code, track the call depth and bail out. We'll cover this more in Chapter 10 (Guardrails).
Q: Do all agents need to be the same LLM?
A: No. A common optimisation: use a cheap, fast model for the manager (it just routes) and a smarter model for the specialists (they do the real work). Or use a fast model for simple specialists and a powerful one for complex reasoning. Mixing models per role is a great way to balance cost and quality.

Where People Come Unstuck

Mistake #1: Splitting too early

Multi-agent systems are harder to build and debug than single agents. Don't split until you've hit the wall β€” too many tools, confused routing, degrading quality. Start with one agent. Split when it genuinely gets worse. Premature multi-agent is premature complexity.

Mistake #2: No clear boundaries

If the inventory agent and the policy agent both try to answer customer questions, the manager can't route cleanly. Each agent needs a clear, non-overlapping job. If you can't describe what an agent does in one sentence, its boundary is too fuzzy.

Mistake #3: Forgetting that handoffs cost tokens

Every agent-to-agent handoff is a full LLM call. A 5-agent pipeline costs 5Γ— the tokens of a single agent. For high-volume systems, this adds up. Multi-agent is a quality play, not a cost play β€” use it when the quality gain justifies the cost.

Brain Power

Imagine a "research report" system: a user asks "Write me a 2-page report on the state of AI agents in 2024." You could do this with one agent β€” but it might be better with a team.

Sketch a multi-agent design. What specialists would you create? Would you use a router, a pipeline, or a debate pattern? What does each agent do, and what tools does it need? Where are the handoffs? How would you prevent the system from being too expensive to run?

There's no single right answer. The point is to start thinking in agent teams β€” who does what, and how they hand off.

Chapter Summary

  • A single agent with too many tools gets worse, not better β€” the LLM has to reason over every tool description every turn, and routing gets confused.
  • The fix is specialisation: split into multiple agents, each with a focused job and a small tool set.
  • Agents hand off work by treating one agent as another's tool. The manager calls ask_inventory_agent(question), which runs the inventory agent's loop and returns the result.
  • Three common patterns: router (manager + specialists), pipeline (sequential stages), debate (writer + critic loop).
  • Each agent is a full agent β€” its own loop, tools, and prompt. The manager doesn't know how they work inside; it just knows what they're for. Encapsulation.
  • Multi-agent adds complexity and cost (each handoff is an LLM call). Split when specialisation genuinely improves quality β€” not because it sounds cool.
  • Frameworks: LangGraph for graph-based multi-agent workflows, CrewAI for role-based crews, AutoGen for conversational agents. The patterns are framework-agnostic.
Chapter Challenge

The Research Team. Build a 3-agent pipeline for writing a short research brief:

1. Researcher agent β€” has a web_search tool (fake it). Gathers 3 facts on a topic.
2. Writer agent β€” takes the researcher's facts and drafts a 1-paragraph brief. No tools, just writing.
3. Editor agent β€” takes the draft and polishes it: checks clarity, trims fluff, returns the final version.

Wire them as a pipeline: researcher β†’ writer β†’ editor. Run it with "Write a brief on the impact of AI on small businesses." Watch each agent do its specialised job and hand off to the next. Then try the debate pattern: add a critic that reviews the editor's output and sends it back if it's not good enough. You've just built a team.

← Previous Next β†’