Architectures and Handoffs: The Supervisor Pattern
One agent is a graph; several agents is a graph of agents. Why you'd split into specialists, the three multi-agent topologies — supervisor, network, hierarchical — the Command primitive and handoff tools that transfer control, and a working bookshop triage system.
A single ReAct agent handles one job with one set of tools. That’s most of what you need — but past a certain complexity, one agent stops being the right shape. This chapter is about the systems that need more than one agent, and how those agents coordinate. It’s the first chapter of Act 3, where the graph you’ve mastered becomes the substrate for whole teams of agents, and it ends with a working triage system that the capstone grows from. Run against langgraph 1.2.9.
Why more than one agent
Start with the temptation to resist: cram every tool and every instruction into one giant agent and hope it copes. It won’t cope well, and the reason is the model’s attention. An agent given fifty tools chooses among them worse than an agent given five; a system prompt that tries to cover orders and refunds and recommendations pulls the model in three directions at once. The fix is specialization — several focused agents, each with a tight set of tools and a single clear job:
- an orders agent, with order-lookup tools and instructions about order status;
- a refund agent, with refund tools and the return policy;
- a recommendations agent, with catalog search and a taste for suggesting books.
Each is easy to reason about, predictable, and independently improvable. The trade you make is coordination: with several agents, something has to decide which one handles a given request, and agents sometimes need to pass work to each other. That coordination — the transfer of control from one agent to another — is a handoff, and it’s the real subject of this chapter. Multi-agent isn’t “several agents are smarter than one”; it’s “several simple agents are more reliable than one complicated one, if you get the handoffs right.”
Three topologies
Multi-agent systems differ in who decides where control goes:
- Supervisor: a central agent routes every request to a specialist, and specialists report back to the supervisor. One hub, clear control, easy to reason about and to debug (the supervisor’s decisions are all in one place). This is the default, and the one you’ll reach for most.
- Network: agents hand off to each other peer-to-peer, any-to-any, with no central router. A flight agent hands to a hotel agent hands to a car-rental agent, each taking over for its part. More flexible, and harder to keep from looping or losing the thread.
- Hierarchical: supervisors of supervisors. A top-level router delegates to team supervisors, each managing their own specialists. This is how you scale past the point where one supervisor has too many reports to route among well, the same reason human orgs grow middle management.
They’re not exclusive: a hierarchical system is supervisors nested inside supervisors, and a team inside one might be a small network. All three rest on the same mechanism — one agent transferring control to another — so learn the mechanism and you can build any of them. That mechanism is Command.
Handoff is a Command
Chapter 7 introduced Command as “update state and route in one move.” A handoff is exactly that: a node decides which specialist takes over, records the decision, and routes there. A supervisor that hands off by topic:
from typing import Literal
from langgraph.types import Command
def supervisor(state) -> Command[Literal["orders", "refund"]]:
topic = classify(state["messages"][-1])
dest = "refund" if topic == "refund" else "orders"
return Command(
update={"log": [f"route->{dest}"]}, # record the routing decision
goto=dest, # hand control to the specialist
)
Verified: routing on topic="refund" produced ['route->refund', 'refund handled'], and topic="orders" produced ['route->orders', 'orders handled'] — the supervisor updated the state and transferred control, and the chosen specialist ran. The Command[Literal[...]] return annotation tells LangGraph the set of nodes this handoff can reach, so the graph stays drawable and a typo is a compile-time error, not a 3am runtime surprise.
Why Command rather than a conditional edge? Because a handoff is a decision plus a transfer. The supervisor did the work of classifying and wants to both record that and act on it in one place; splitting it into “return a topic” and “a separate edge routes on it” scatters one thought across two constructs. With Command, the agent that decided is the agent that hands off.
A handoff tool
There’s a more agentic variant, and it’s how the prebuilt systems work. Instead of a hard-coded classify, you give the supervisor handoff tools — one per specialist — and let the model choose which to call. A handoff tool is a normal tool whose job is to emit a Command that transfers control:
from langchain_core.tools import tool
from langgraph.types import Command
def make_handoff(agent_name: str):
@tool(f"transfer_to_{agent_name}")
def handoff() -> Command:
"""Transfer the conversation to the {agent_name} specialist."""
return Command(goto=agent_name, graph=Command.PARENT)
return handoff
Now the supervisor is a model that “calls a tool” to hand off, so routing gets the model’s judgment rather than a brittle if. The graph=Command.PARENT matters: it says “route in the parent graph,” which is what lets a specialist — itself a subgraph — hand control back up to the supervisor’s level rather than trying to route within its own little graph. This is precisely the mechanism the prebuilt create_supervisor uses under the hood; the next chapter’s prebuilts are handoff tools all the way down.
A word on what a specialist sees when control transfers. By default the agents share the conversation state — the messages channel — so a specialist reads the whole conversation, including what led the supervisor to route to it. That shared context is usually what you want (the orders agent should see the customer’s question), but it’s a design choice: for agents that should work in isolation, you give them their own state, a technique the next chapter needs for parallel workers.
Building the bookshop triage
Concretely, here’s the system the capstone grows from: a supervisor routing a customer to an orders specialist or a recommendations specialist, each a real create_agent with its own tools and instructions.
from langchain.agents import create_agent
orders = create_agent(
model=model,
tools=[lookup_order, order_history],
name="orders",
system_prompt="You handle order status and history. Use tools; never invent order data.",
)
recommendations = create_agent(
model=model,
tools=[search_catalog],
name="recommendations",
system_prompt="You recommend books from the catalog based on what the customer likes.",
)
Each specialist is a compiled graph — a self-contained agent, exactly the “graph as a node” idea from the previous chapter. The supervisor looks at the incoming message and hands off to the right one, using the Command (or handoff-tool) pattern above, with orders and recommendations as the reachable destinations. Wire them into one graph and you have triage: “where’s my order?” routes to orders, which calls lookup_order and answers; “what’s like Dune?” routes to recommendations, which searches the catalog.
An honest note on “verified.” The mechanics — the handoff Command, the specialists as agent-nodes, the graph wiring — are run-verified. The routing quality (does the supervisor pick the right specialist?) is a model judgment, and a small local model routes less reliably than Claude. So this series verifies that the handoff transfers control correctly and each specialist runs; it does not claim a 3B model triages flawlessly. Plan your prompts, and in production your model choice, accordingly — the graph is correct regardless of which model fills the supervisor slot.
Keeping specialists focused, and out of loops
The payoff of this structure is scoping. The orders agent’s prompt and tools are only about orders, so its behavior is predictable and its tool descriptions don’t compete with unrelated ones. Need a new capability — a shipping specialist? Add an agent and a handoff destination, without touching the others. That modularity is the real argument for multi-agent: not smarter, but simpler per part, and simple parts are the ones that behave.
The risk to watch is handoff loops (A hands to B hands back to A), especially in the network topology, where no central authority stops it. The supervisor topology mostly avoids this by construction: specialists report to the hub, not to each other, so there’s no peer cycle to fall into. That’s a large part of why it’s the recommended default. When you do need peer handoffs, the recursion limit is your backstop (a high one, remember — 10007 — so it won’t save you quickly), and a clear “hand off when X, otherwise answer and stop” instruction in each agent’s prompt is your real prevention.
Final thoughts
Multi-agent is a graph of agents, and the edge between them is a handoff — a Command that records a decision and transfers control, optionally driven by a handoff tool so the model chooses, with Command.PARENT letting a specialist return to the hub. Split into agents for focus, not for intelligence: several simple, scoped specialists beat one overloaded generalist, provided the handoffs are clean. Supervisor is the topology to default to — one hub, focused specialists, no peer loops — with network and hierarchical for the cases it doesn’t fit. You’ve built a triage system; next we give it two more powers: running specialists in parallel, and nesting whole graphs as single nodes.
Next: subgraphs and parallelism — the Send API for fanning out to many workers at once, composing graphs as nodes, and the state-sharing gotcha that catches everyone.
Comments