Orchestration Patterns Compared
Pick supervisor, swarm, hierarchical, debate or a plain workflow. Stdlib Python from the lessons.
- Concepts and terms
- Tasks and commands
- Annotated code
- Diagrams
- Comparisons
- Defaults and numbers
- Troubleshooting
- Questions and tips
Four topologies side by side#
| Factor | Supervisor-worker | Swarm | Hierarchical | Debate |
|---|---|---|---|---|
| Who routes | One central LLM | No central router | Supervisors of supervisors | Parallel proposers |
| Agents talk | Only through the supervisor | Direct handoffs | Only leaves do work | Cross-critique |
| Demo trace | Cleanest | Shortest | Deepest | Most expensive |
| Fits | 2-4 specialists | Latency over reasoning clarity | Large agent populations | Accuracy over cost |
| Weak point | Supervisor is the bottleneck | Hard to reason about | Decomposition drift | Cost |
| Frameworks | LangGraph create_supervisor | LangGraph swarm topology | Nested subgraphs or crews | Custom |
From Lesson 14.28, Lesson 16.09, Lesson 16.06
Decision order#
From Lesson 14.28
Supervisor with parallel workers#
Use each pattern when#
- Use a workflow when you can enumerate the steps.
- Use an agent when the next step depends on what the last step returned.
- Use supervisor for research: each worker gets its own 200k-token window.
- Use swarm for many independent tasks with variable duration.
- Use hierarchical when the task has real independent sub-teams.
- Use sequential when step 2 needs the output of step 1.
- Use static graphs when audit and replay matter more than adaptability.
- Use CrewAI Flow as the production starting point. Use Crew for autonomous roles.
From Lesson 14.12, Lesson 16.05, Lesson 16.09, Lesson 16.06, Lesson 14.28
Five workflow patterns in code#
| Task | Code |
|---|---|
| Prompt chaining: output N feeds call N+1 | prompt_chain(input_text, |
| Routing: classify, then dispatch | route(input_text, |
| Parallelization: N runs, majority wins | parallel_vote(prompt, |
| Orchestrator-workers: pick workers, synthesize | orchestrator_workers(task, |
| Evaluator-optimizer: loop until PASS | evaluator_optimizer(task, |
| Fallback handler for an unknown label | handlers.get(label) or handlers.get("default") |
| Run all five demos | python3 code/ |
Workflow or agent#
| Factor | Workflow | Agent |
|---|---|---|
| Who owns the graph | Engineers | The model |
| Step count | Bounded | Can spiral |
| Debugging | Easier | Harder failure modes |
| Audit | Auditors read the graph | Inferred from trajectories |
| Fits | Predictable tasks | Open-ended research |
From Lesson 14.12
Lead fans out to threads#
sub_questions = self.plan(query)3 sub-questionsresults: list[WorkerResult | None] = [None] * len(sub_questions)threads: list[threading.Thread] = []for i, sq in enumerate(sub_questions): w = Worker(worker_id=i, trace=self.trace)fresh worker per sub-question th = threading.Thread(target=w.run, args=(sq, results, i)) threads.append(th) th.start()all workers run at oncefor th in threads: th.join()wall time near max, not sumsynthesis = self.synthesize(query, [r for r in results if r is not None])From 16.05 code/main.py
Swarm workers pull from one queue#
q: queue.Queue = queue.Queue()for t in tasks: q.put(t)no orchestrator assigns workdef worker(wid: int) -> None: while True: try: task = q.get_nowait() except queue.Empty: returnqueue drained, worker exits fake_work(task) with lock: counts[wid] += 1fast workers pull more jobs q.task_done()From 16.09 code/main.py
Limits and budgets#
| Setting | Default | Note |
|---|---|---|
| Swarm hops | 3 | while hops < 3 stops A to B to A bouncing |
parallel_vote n | 5 | Same prompt, majority vote |
max_iter | 5 | Evaluator-optimizer stops after 5 tries |
| Tree depth | 2 | Three levels hide most errors |
| Reconciliation rounds | 2 | Then the top manager must commit |
| Worker timeout | 2× median runtime | Kill, then respawn narrower or skip |
| Worker token cap | 10× | Of the expected synthesis input |
| Supervisor specialists | 2-4 | Step 2 of the decision order |
From 14.28 code/main.py, Lesson 14.28, 14.12 code/main.py, Lesson 16.06, Lesson 16.05
Numbers that matter#
- Research gain
- +90.2% over single-agent Opus 4 on internal research evals.
- Token share
- 80% of BrowseComp variance comes from token usage alone.
- Token cost
- multi-agent is ~15× the tokens of single-agent.
- Scale effort
- simple queries use one agent and 3-10 tool calls. Complex ones use 10+ agents.
- Wall clock
- three 0.3-second workers finish in ~0.35 seconds, not 0.9.
- Swarm demo
- 8 tasks, 4 slow (0.4s) and 4 fast (0.1s), 4 workers.
- Pattern size
- each workflow pattern is ~10-15 lines of code.
Failures and fixes#
| Symptom | Cause | Fix |
|---|---|---|
| Precise answers to the wrong question | Lead hallucinates the plan | Log the plan, diff it against the query |
| Synthesis gets polluted | Workers over-explore | Set explicit scope boundaries |
| User never sees a conflict | Lead silently picks one side | Re-ask or state the disagreement |
| Branch answers the wrong topic | Manager mislabels a branch | Add a canary worker with the original query |
| Sub-managers loop | Consensus loop | Set a reconciliation budget |
| Long tasks never run | Queue starvation | Priority queue with aging |
| Task runs twice after a crash | Worker crashed mid-run | Make workers idempotent, use a durable queue |
Questions#
- Why supervise through tool calls?
- You decide exactly what each specialist sees.
- Why does supervisor win on research?
- Fresh context per subagent is the main mechanism.
- Why rainbow deployments?
- Agents are long-running and stateful. Blue-green does not work.
- Where does a hierarchy error show?
- At the top synthesis, one level from where a human could catch it.
- Why not swarm for a report?
- A swarm of researchers gives independent facts, not a coherent report.
- How do you debug a swarm?
- Give every task a trace ID. Log start and end with it.