Guide
Multi-agent design patterns: supervisor, pipeline and handoff
Use a pipeline when the steps are known and fixed, a supervisor when the steps depend on the task and someone must combine the results, and a handoff when a conversation should move to a specialist who then talks to the user directly. The main question is who decides what happens next: your code, a coordinating agent or the agent currently working.
Before choosing a pattern
This guide assumes that you have already decided to use more than one agent. If you have not, read single agent vs multi-agent systems first, because one well-designed agent is often the better answer. Here the focus is on how the three most common arrangements behave once you have split the work: where control sits, what information moves and how each one fails.
The samples are illustrative and framework-neutral. call_agent stands in for one agent's complete loop of model and tool calls. Frameworks offer their own names and helpers for these ideas, so the terms may differ from one set of documentation to another.
Three questions that separate the patterns
Patterns are easier to compare through the decisions they make for you:
- Who picks the next step? Your code, a coordinating agent or the current specialist.
- Who talks to the user? One consistent voice, or whichever agent currently holds the conversation.
- What does each agent see? The whole history, a summary or only a specific brief.
Most design trouble comes from answering the third question carelessly, so it gets a section of its own below.
The pipeline pattern
In a pipeline, agents run in a fixed order and each one receives the output of the step before it. An extractor pulls facts from a document, a drafter writes a report from them and a reviewer checks the draft against the source. No model decides the route, because your code already has.
# Illustrative only. Validate each stage before passing its output on.
def run_pipeline(document):
facts = call_agent("extractor", document)
check_facts(facts)
draft = call_agent("drafter", facts)
review = call_agent("reviewer", {"draft": draft, "source": document})
if not review["approved"]:
return {"status": "needs_human", "draft": draft, "notes": review["notes"]}
return {"status": "done", "draft": draft}
Note that the reviewer receives the original document as well as the draft. Had it seen only the draft, it could check style but not accuracy.
Where it fits. Pipelines suit repeatable work with a known sequence, such as document processing or content production. Strictly speaking, this is often a workflow containing agents, and that is a strength: it is the easiest pattern to test, trace and cost, since each stage has a defined input and output.
How it fails. The characteristic failure is the silent carry-forward. An early mistake becomes the "truth" for all later stages, which then build on it with confidence. The defence is a validation gate between stages, using a schema where possible, as described in structured output from LLMs. Pipelines also handle exceptions badly: if a task needs a stage skipped or repeated, you end up adding branches until it has stopped being a simple pipeline.
The supervisor pattern
A supervisor is a coordinating agent that reads the task, delegates pieces to specialists, reviews what returns and decides what to do next. Specialists report only to the supervisor and do not talk to one another, or usually to the user. The supervisor typically treats each specialist as if it were a tool.
# Illustrative only. The supervisor returns either a delegation or a final answer.
def run_supervisor(task, specialists, max_rounds=6):
notes = []
for _ in range(max_rounds):
decision = plan_next_step(task, notes, list(specialists))
if decision["type"] == "finish":
return decision["answer"]
if decision["agent"] not in specialists:
notes.append({"error": "Unknown agent: " + decision["agent"]})
continue
result = call_agent(decision["agent"], decision["brief"])
notes.append({"agent": decision["agent"], "result": result})
return "Stopped: round limit reached."
Where it fits. A supervisor works well when the necessary steps depend on the request, such as a research question that may or may not need the database, the document store and the web. It keeps a single point of control and one consistent voice, and specialists can be given narrow permissions.
How it fails. Every result passes through the supervisor, so model calls and context accumulate there, and it can become slow and expensive. Its instructions also tend to grow as specialists are added. A supervisor may delegate in circles, or may lose detail when it paraphrases a specialist's result. Set a round limit, keep specialist results short and structured, and consider letting a specialist's output go straight into the final answer where no rewriting is needed. A deterministic supervisor is also a legitimate option: if plain code can route the work, you avoid a model call on each decision. The guide on building an orchestrator with LangGraph shows one way to model this kind of control flow.
The handoff pattern
In a handoff, control itself moves. The active agent decides that another is better placed and transfers the conversation, and the new agent carries on from there, often talking directly to the user. Nothing has to report back to a central coordinator. A general support agent passing a customer to a billing specialist is the classic example.
# Illustrative only. A handoff changes which agent handles the next turn.
ALLOWED = {
"triage": {"billing", "technical"},
"billing": {"triage"},
"technical": {"triage"},
}
def run_turn(state, user_message, max_handoffs=3):
state["messages"].append({"role": "user", "content": user_message})
for _ in range(max_handoffs + 1):
result = call_agent(state["active_agent"], state["messages"])
if result["type"] != "handoff":
state["messages"].append({"role": "assistant", "content": result["text"]})
return result["text"]
if result["target"] not in ALLOWED[state["active_agent"]]:
return escalate_to_human(state)
state["active_agent"] = result["target"]
return escalate_to_human(state)
The active agent is saved in the state, so the next user message goes to the billing specialist without passing through triage again. The explicit table of allowed routes means that the model proposes a handoff but your code decides whether it is valid.
Where it fits. Handoffs suit conversations that move through distinct areas, particularly where each area has different tools or permissions. They can also reduce latency, because there is no coordinator to consult at each turn.
How it fails. The obvious failure is agents passing a user back and forth, which the handoff limit above contains. Less obvious is the lack of an overview: with no central agent, no one is responsible for the whole request. If a user asks about a refund and a login problem in one message, the first specialist may deal with its part and forget the rest. Users can also find changes of tone jarring, and a specialist that receives too little context may ask them to repeat themselves.
Comparing the three
| Concern | Pipeline | Supervisor | Handoff |
|---|---|---|---|
| Who picks the next step | Your code | Coordinating agent | Current agent, within your rules |
| Flexibility | Low | High | Medium to high |
| Who talks to the user | Usually the final stage | The supervisor | The active specialist |
| Extra model calls | Predictable | Highest, as a rule | Moderate |
| Ease of testing | Easiest | Harder, as routes vary | Harder, as conversations vary |
| Typical failure | Early error carried forward | Bottleneck, circular delegation | Bouncing, lost overview |
A quick way to choose: if you can draw the steps before seeing the input, begin with a pipeline. If a single conversation should move between specialists, use handoffs. If a task must be broken up and the pieces reassembled, use a supervisor.
What each agent should see
Context passing causes more trouble than the choice of pattern. Three common options have different costs:
- The full history. Nothing is lost, but context grows quickly, cost rises and irrelevant detail can distract the specialist. It also exposes everything to every agent, which may breach your permission boundaries.
- A generated summary. This is compact, but it can quietly drop the one detail that mattered, and no one will notice.
- A structured brief. Defined fields, such as the goal, known facts, constraints and identifiers, make omissions visible and can be validated. This takes more design but is often the most dependable choice.
Keep IDs and exact figures as data outside the model's prose wherever you can, so that they are never paraphrased. The guide on agent memory and state covers what to keep and where.
Combining patterns
Real systems often nest these. A handoff might route a customer to a claims specialist, which internally runs a fixed pipeline. A supervisor might delegate one branch to a pipeline while running two specialists in parallel. This is reasonable when each level has a clear boundary, but every layer adds another place for failures to hide, so add one only to answer a specific problem.
Controls every pattern needs
- Hard limits. Cap rounds, handoffs, tool calls and spending per run, and define what the system does on reaching a limit.
- Permissions outside the model. Enforce what each agent may do in the tool layer, not through instructions.
- Tracing across agents. Link every step to one run ID, as explained in LLM observability and tracing.
- Approval for risky actions. Pause before anything that is hard to undo, using human-in-the-loop approval.
- Tests at two levels. Test each agent on its own, then test the routing and the complete run.
If you are weighing up these designs for a real system, the multi-agent systems page describes what I can help with.
Frequently asked questions
Which multi-agent pattern should I start with?
Start with the simplest one that fits. If the steps are known in advance, use a pipeline. Move to a supervisor or to handoffs only when the route truly depends on the request, because both are harder to test and to predict.
What is the difference between a supervisor and a handoff?
With a supervisor, control returns to the coordinating agent after each specialist finishes, and it decides the next step. With a handoff, control transfers to the new agent, which continues the work and usually talks to the user directly.
Is a pipeline of agents really multi-agent?
It depends on your definition. The order is fixed by code, so it is partly a workflow, but each stage can still be an agent that chooses its own tool calls. The label matters less than whether the design suits the task.
How do I stop agents looping forever?
Set hard limits in code on rounds, handoffs, tool calls and spending, and define what happens when a limit is reached, such as returning a partial result or escalating to a person. Do not rely on instructions in a prompt to prevent loops.