Multi-agent setups can solve broad tasks no single context could hold, but they multiply cost and coordination problems.
A multi-agent system uses several model-driven agents on one task. The most common and reliable form is the orchestrator-worker (or lead and sub-agent) pattern: a lead agent plans, starts sub-agents for parts of the job, and combines what they return.
Why it helps:
- Separate context windows. Each sub-agent explores in its own fresh context (reading dozens of pages, say) and returns only a short summary. The lead's context stays clean.
- Parallelism. Independent parts run at the same time, so broad research finishes faster.
- Specialisation. A sub-agent can get its own instructions, tools and even a cheaper model.
Anthropic reported that its multi-agent research system clearly beat a single agent on broad research questions, but used roughly 15 times the tokens of a normal chat (single agents about 4 times). That is the core trade-off.
When it does not help:
- Tasks where every part depends on the others, such as most coding changes to one codebase: agents step on each other or make incompatible choices.
- Tasks where the extra spend is not worth it.
- Real-time back-and-forth between agents, which remains fragile.
Design tips:
- Give each sub-agent a precise brief: the objective, the output format, which tools to use, and when to stop. Vague delegation leads to duplicated or missing work.
- Ask sub-agents for condensed results (a summary plus sources), not their whole transcript.
- Keep one agent responsible for the final answer.
- Log every agent's steps; debugging without traces is guesswork.
Example
import asyncio
# research(topic) stands for running a sub-agent with its own fresh context.
async def research(topic: str) -> str:
await asyncio.sleep(0.1) # pretend to browse and read
return f"{topic}: 3-line summary + 2 sources"
async def lead_agent(question: str) -> str:
subtopics = ["pricing", "features", "reviews"] # the lead's plan
briefs = [f"{question} -- focus only on {t}; return a short summary" for t in subtopics]
results = await asyncio.gather(*(research(b) for b in briefs)) # run in parallel
return "\n".join(results) # the lead would now ask the model to synthesise these
print(asyncio.run(lead_agent("Compare note-taking apps")))Remember
- Orchestrator-worker: a lead agent delegates to sub-agents and merges results
- Gains: clean separate contexts, parallelism, specialisation
- Costs: many times more tokens and coordination failures; use for broad, parallel tasks