The one durable reason to go multi-agent is context isolation: keeping what each agent reads out of every other agent’s window. Not speed, not specialization.
The shape
One task in, one answer out, via exactly three call types (w = worker count, chosen at run time):
Task --> 1 decompose call --> w worker runs --> 1 synthesis call --> Answer
(splits into w (each reads a lot, (merges the
disjoint briefs) returns short report) reports)
- Orchestrator/lead: sees whole task, splits it, merges results.
- Worker/subagent: blank conversation, one narrow brief; history discarded on return.
- Context isolation: each worker’s conversation is a separate object no one else can see.
Why isolation is the point
- What matters is read-to-kept ratio. Worker reads 60k, returns ~800-token report; ~180k read compresses to ~2,400 kept (75x).
- Defeats three failures of one long context (all quality/cost, not just overflow):
- Quadratic cost: stateless API resends the whole conversation each turn; input over
nturns is aboutn·P + a·n²/2. Split acrosswworkers, the quadratic term becomesa·n²/(2w). - Positional decay (“lost in the middle”): recall is U-shaped; 20–40 point drop in the middle band where early instructions get buried.
- Hard ceiling: material eventually doesn’t fit and evidence gets dropped.
- Quadratic cost: stateless API resends the whole conversation each turn; input over
- Fixed prefix (system + tool schemas) ≈ 6,000 tokens; the floor for every cost figure.
The cost: 4–15x the tokens
- Ratio numerator
w·W + Oover denominatorB(a single agent reading until satisfied). One search-and-read step ≈ 5,000 tokens. O(orchestrator) is only 6–10% of total; its prefix is paid twice (decompose + synthesize).
single B | workers w·W | orch. O | total | multiplier | |
|---|---|---|---|---|---|
| low | 40,000 | 4×40,000 | 18,400 | 178,400 | ~4.5x |
| high | 25,000 | 6×60,000 | 21,600 | 381,600 | ~15.3x |
- It is a work-volume multiplier, not an efficiency penalty: you read more. Per unit of work, fan-out is cheaper.
- Levers: worker count
w(linear), step budgets(quadratic per worker), model tier (~1.7–2x), summary length (linear). Downgrade workers, not the orchestrator.
Topologies
| Topology | Control | Best for | Watch out |
|---|---|---|---|
| Orchestrator–Worker | Central | Fan-out research, wide code changes | Worker conflict; synthesis quality |
| Handoff / Swarm | Passed along | Customer service by domain | Ping-pong; context lost in transfer |
| Pipeline | Fixed | Content, ETL | It’s a workflow, not multi-agent |
| Debate | Adversarial | High-stakes judgment | Expensive; bland consensus; buys calibration |
- Workflow vs multi-agent: fixed stage list = workflow (cheaper, debuggable). Multi-agent only when the model decides how many workers and what each does.
- Handoff needs two guards: cap the transfers; send a structured handoff summary (established / tried / open).
Briefs and communication
- A brief carries four things: objective (one checkable sentence), scope boundary (explicitly what NOT to touch), output contract (named fields), budget (max steps/tokens).
- Boundaries must be exclusions: “do not cover Y or Z” is checkable; “focus on X” is not. Overlapping scopes ≈ 60% duplicated work.
- Reports must be structured and carry provenance (source + retrieval date) so the synthesizer can break ties.
- Channels back out (default = filesystem):
- Message passing: content paid twice (output ~5x input rate, then re-input on every turn).
- Shared state: cheap, but write conflicts (lost-update race); fix with per-worker keys or locks.
- Filesystem: write file, return “wrote report_a.md” (~10 tokens); large artifacts move without holding content.
- Harness = your code around the model (holds conversations, runs tools, picks next agent). The model owns nothing.
Gotchas
- Averaging failure (worst): synthesizer splits the difference on contradicting reports, producing something true of neither and discarding the recency tiebreaker. Fix: provenance in schema + instruct that contradictions are output, not input to reconcile.
- Truncated worker:
max_tokensis not an error; branch on it explicitly or a cut-off report reads as complete. - Clamp every budget in the harness:
max_stepsand worker count from the model are requests; enforce withmin(...)/ a[:MAX_WORKERS]slice. A number in a prompt is a request; a number inrange()is a rule. - Read fan-out is safe; write fan-out corrupts state silently. If workers must write, isolate at filesystem / git-worktree level (one writer per path).
- Stamp a shared
run_idon every log line to reassemble traces. parallel()makes wall-clock = slowest worker (latency win only, no cost change).
Decision ladder (stop at first match)
- One agent with good context management? → do that.
- One agent chokes on tool-output flood? → isolation helps.
- Subtasks genuinely independent, non-overlapping? → fan out.
- Results compose via a synthesizer? → orchestrator–worker.
- Otherwise → a fixed-stage workflow.