Swarm / Peer Pattern
Peer agents hand a conversation and its context to whichever agent has the right capability, with no central controller — flexible for routing-heavy dialogues, risky without hop limits.
Mechanism: the hand-off
In a swarm each agent has a normal tool set plus hand-off tools: transfer_to_billing(), transfer_to_refunds(). Calling one does not return a result; it changes which agent runs the next turn. The conversation history (or a filtered slice of it) and a small context object travel with it.
This makes swarms natural for customer-support style flows where the active specialist changes as the conversation reveals what the user needs. Triage hands to billing; billing discovers a refund is required and hands to refunds; refunds resolves and hands back to triage for anything else.
What travels and what does not
Decide explicitly what a hand-off carries. Full history is simple but leaks irrelevant detail and grows without bound. A context object ({customer_id, order_id, verified: true}) plus the last N turns is usually enough and keeps each agent's prompt small. Tool sets do not travel: refunds has issue_refund, triage does not, which is where the security benefit comes from (Tool Permissions and Least Privilege).
Also decide who may hand to whom. A fully connected graph of 8 agents has 56 possible transfers, most of them nonsensical. Restrict edges to the real routing graph and the model has fewer wrong choices.
1class Handoff:2 def __init__(self, to: str): self.to = to3 4def transfer_to_refunds(reason: str) -> Handoff:5 """Hand the conversation to the refunds specialist. Use only after the customer is verified."""6 return Handoff("refunds")7 8def run_swarm(agents: dict, start: str, msgs: list, ctx: dict, max_hops: int = 5):9 active, hops = start, 010 while True:11 out = agents[active].step(msgs, ctx) # returns text or a Handoff12 if isinstance(out, Handoff):13 hops += 114 if hops > max_hops:15 return escalate_to_human(msgs, ctx) # termination guard16 active = out.to17 continue18 return outRisks specific to swarms
There is no single place that knows the plan, so ping-pong hand-offs, dropped tasks and duplicated actions are all easy. Every swarm needs a hop budget, an idempotency key for side effects that may be attempted by two agents (Idempotency), and a trace that records the agent name on every span so you can reconstruct who did what (Trace Inspection: Debugging from a Trace).
Evaluation is also harder: the "right" path through the swarm is not unique. Evaluate on outcomes plus path constraints (e.g. "refund never issued before verification") rather than on exact hand-off sequences.
Key points
- A hand-off is a tool call that switches the active agent instead of returning data.
- Carry a small context object and recent turns, not the full history.
- Tool sets stay with agents — that is the permission boundary.
- Restrict the hand-off graph; add a hop limit and an escalation exit.
- Evaluate on outcomes and invariants, not exact paths.
When to use — and when not to
- Conversational flows where the needed specialist changes mid-dialogue.
- Specialists need very different permission levels.
- Routing decisions are local and do not need a global plan.
- Tasks with a fixed order — a pipeline is simpler and traceable.
- Work requiring a global plan or merge step — use a supervisor.
- Side-effect-heavy tasks where duplicated actions are costly.
Failure modes
- Infinite transfer loops between two agents.
- Task silently dropped at a hand-off because context did not carry it.
- Two agents both perform the side effect.
- Traces without agent identity make incidents unreconstructable.