When to reach for it
- Decentralized exploration is desired.
- Tasks can be adaptively distributed.
- Central control would be too rigid.
/pattern/swarm/
Agents coordinate decentrally via local rules, messages, and handoffs, allowing the execution path to emerge at runtime.
When to reach for it
When it backfires
The tradeoff
High adaptability is gained at the cost of lower predictability and difficult debugging.
Any agent may take over. Messages flow peer-to-peer; the next speaker emerges from local rules, not a central queue.
from langgraph_swarm import create_handoff_tool, create_swarm
from langgraph.prebuilt import create_react_agent
# Each agent carries ONLY the peers it may hand off to. The edge set is the
# union of these handoff tools, never registered in one central place;
# the path through the swarm emerges at runtime, one handoff at a time.
billing = create_react_agent(
model,
tools=[issue_refund, create_handoff_tool(agent_name="tech")],
prompt="Resolve billing questions. Hand device faults to tech.",
name="billing",
)
tech = create_react_agent(
model,
tools=[reset_device, create_handoff_tool(agent_name="billing")],
prompt="Resolve technical issues. Hand charge disputes to billing.",
name="tech",
)
# No supervisor node: control passes peer-to-peer, not back to a hub.
swarm = create_swarm([billing, tech], default_active_agent="billing").compile()
result = swarm.invoke(
{"messages": [("user", "I was double-charged and my router is dead.")]},
config={"recursion_limit": 12}, # the max_handoffs fuse
)Every agent broadcasts to every other agent. Token usage explodes and latency becomes unpredictable.
Fix · Add a broadcast budget per turn, or route messages through a lightweight coordinator that enforces backpressure.
The same input produces different execution paths on each run. Bugs are non-deterministic and hard to debug.
Fix · Log the full message sequence and seed the turn-order rule. Replays should be deterministic given the same seed.
Both are decentralised — no central node owns the control flow — so they sit side by side at the autonomous end of the spectrum, and they are the pair most often conflated. The difference is not whether they self-organise but the coordination substrate.
Swarm is push, Blackboard is pull.
It is the classic distributed-systems split: Swarm coordinates by message-passing — an agent names its successor and hands off both control and context; Blackboard coordinates by shared, stigmergic state — agents never address each other, they react to what is written on a shared board.
| Dimension | Blackboard | Swarm |
|---|---|---|
| Handoff vector | Indirect — a write to shared state | Direct — transfer_to(named_peer) |
| Who is addressed | The board (a state predicate) | A specific peer agent |
| Activation | Data-driven (“I have something to add now”) | Control-driven (the active agent passes the baton) |
| Where context lives | Persistently and visibly, on the board | Travels with each handoff |
| Adding an agent | A subscription — existing agents unchanged | Must appear in peers’ transfer_to sets |
| Synchrony | Natural fit for asynchronous, long-running work | Live baton-pass; control flows continuously |
| Termination | Quiescence — no agent has a relevant action left | An agent answers, or max_handoffs is reached |
several specialists incrementally build a shared artefact and partial results unlock further work, contributors are not simultaneously available, or you need to add and remove specialists without rewiring the others.
a single task must travel live between specialists, the next specialist depends on what the previous one just discovered, and no static plan can be drawn in advance.
Both forfeit the guarantees Pipeline and Graph give on path length, coverage and cost, and both make tracing non-optional. Swarm’s failure mode is hallucinated routing and unbounded loops — cap max_handoffs and schema-validate transfers; Blackboard’s is stall and hard debugging — add a liveness check and partition the board by trust.
Next pattern
Search patterns, frameworks, and pages.