« Phase 07 README · Hitchhiker's · Deep Dive · Principal Deep Dive · Core Contributor · Staff Notes

Phase 07 Warmup — Multi-Agent Orchestration

Who this is for: you can write Python, you did Phase 00 (the reliability/cost math) and Phase 01 (the agent loop). You have never composed several agents into one system. By the end you will have built a supervisor, workers, a critic, a shared message bus, and a critique-revise loop — and, just as important, you will know when not to. No framework, no API key: every agent's "model" is a pure function you inject.

Table of Contents

  1. What a multi-agent system is (and when it is the wrong tool)
  2. Why we inject the policy (again)
  3. Roles: supervisor, worker, critic
  4. The message bus and the blackboard
  5. Topologies: the five shapes you will actually see
  6. The supervisor-worker pattern: routing by blackboard state
  7. Typed handoffs and the least-context principle
  8. Critique-revise: verification is the reliability lever
  9. Reflection, debate, and the wider verification family
  10. The step budget: why multi-agent ping-pongs, and how to bound it
  11. Coordination failure modes
  12. When multi-agent is actually worth it: the honest tradeoff
  13. Framework mapping: AutoGen, CrewAI, LangGraph, ADK, OpenAI Agents SDK
  14. Common misconceptions
  15. Lab walkthrough
  16. Success criteria
  17. Interview Q&A
  18. References

1. What a multi-agent system is (and when it is the wrong tool)

A multi-agent system is more than one agent — each an LLM-in-a-loop from Phase 01, each with a role and its own policy — coordinating to finish a task. "Coordinating" is the load-bearing word: the agents pass work to each other and share information through some channel, rather than one monolithic prompt doing everything.

Why would you ever want this instead of a single agent? Three legitimate reasons, and it is worth being precise because the field over-reaches for all of them:

  1. Separation of concerns. A task with genuinely distinct sub-jobs — gather sources, then write, then fact-check — is easier to build and keep reliable if each sub-job is a small agent with a focused prompt and a small toolset, instead of one agent with a sprawling prompt trying to hold all three jobs (and all their tools) in its head at once.
  2. Verification. A second agent whose only job is to check the first agent's output is the single most valuable multi-agent pattern, because — as we will derive in §8 — verification is how you buy back the reliability that Phase 00's \(0.95^n\) takes away.
  3. Parallelism. Genuinely independent sub-tasks (summarize 20 documents; probe 5 sources) can run on N workers at once, turning a long sequential chain into a fan-out.

And here is the sentence the rest of this warmup keeps coming back to, because it is the Staff- level judgment: most systems marketed as "multi-agent" should be a single agent with good tools. Anthropic, who ship one of the most-used multi-agent research systems in production, say this plainly: multi-agent multiplies token cost, latency, and coordination failure modes, and it is worth it only when the task is genuinely parallel or genuinely benefits from specialized verification — not to compensate for a weak single agent. Adding agents is the opposite of the "least-agentic that works" reflex from Phase 00 §10; you should feel the same suspicion here that you felt about "just let the agent run 30 steps."


2. Why we inject the policy (again)

Same discipline as Phase 01, now across several agents. Each agent's "model" is an injected policy: a pure function Policy: str -> str that takes a context string and returns the agent's text. In tests the policy is scripted and deterministic, so the whole orchestration — who routed to whom, how many rounds the critic took, the exact message log — is reproducible and assertable.

This matters more in multi-agent than in single-agent, for two reasons. First, a multi-agent run is a small distributed system: many moving parts, many places non-determinism could hide. If the "models" are pure functions and the bus orders messages by a counter, not a wall clock, two identical runs produce byte-identical transcripts — which is the only way to unit-test coordination logic. Second, it forces the right architecture: your orchestrator's correctness (routes to the right worker, terminates on "done", never exceeds the budget) must not depend on any model being smart. If your supervisor only works because a real LLM happened to say the right thing, it is not a supervisor; it is a hope. The injected policy makes you prove otherwise.


3. Roles: supervisor, worker, critic

A role is an agent with a fixed job. Three roles cover the vast majority of real systems, and they are the three you build in the lab:

  • Supervisor (a.k.a. orchestrator, router, manager) — reads the shared state and decides who works next, or that the task is done. It does not do the work; it routes it. Its policy is a function from "the state of the world" to "the next worker's name, or done."
  • Worker — does one specialized task and posts a result. A worker sees only what it is handed (a task and the minimum context), not the whole system state. Researcher, writer, coder, summarizer — each a worker.
  • Critic (a.k.a. reviewer, evaluator, judge) — evaluates a worker's output and returns either approve or revise plus feedback. The critic is the verification role, and it is the reason multi-agent can be more reliable than a single agent rather than just more expensive.

In code this is one Agent base with a name, a role tag, and an injected policy; Worker, Critic, and Supervisor are thin subclasses. The value is not the class hierarchy — it is that each agent's prompt and tools stay small and single-purpose, which is what keeps each individual step reliable. A giant "do everything" agent has a giant surface area for the model to get confused; three focused agents each have a small one. This is the same modularity argument as microservices, with the same caveat (see §11): the coordination between the pieces becomes the new hard part.


4. The message bus and the blackboard

How do agents share information? The wrong answer is "each agent calls the next directly and passes whatever it wants" — that is a tangle of hidden side channels you cannot audit or replay. The right answer, and one of the oldest ideas in AI (the blackboard architecture, 1970s), is a shared channel:

                        ┌─────────────────────────────────────────┐
   supervisor ─post──►  │   MESSAGE BUS (ordered log)              │
   researcher ─post──►  │   #0 supervisor→researcher [handoff]     │   ◄─history()─ anyone
   writer     ─post──►  │   #1 researcher→supervisor [result]      │
   critic     ─post──►  │   #2 supervisor→writer     [handoff] ... │
                        ├─────────────────────────────────────────┤
                        │   STATE (blackboard dict): task,         │
                        │   completed=[researcher], results={...}  │   ◄─read/write─ anyone
                        └─────────────────────────────────────────┘

Two pieces:

  • The message log — every agent communicates by post(msg)-ing a Message(sender, recipient, kind, content). The bus stamps each message with a monotonic sequence number, so history() is a total, deterministic order. The kind field (handoff, result, control, draft, critique) makes the transcript self-describing: you can filter "show me every handoff" or "every message the critic sent." This is your audit log and your replay tape.
  • The blackboard — a shared state dict any agent can read and write: the task, which workers have completed, the accumulated results. The supervisor routes off it; workers append to it.

Coordinating through one inspectable channel is what makes a multi-agent run debuggable at 2 a.m. When something goes wrong, you read the transcript in order and see exactly who said what to whom. Compare that to hunting through a call stack of agents invoking each other directly. (This is also AutoGen's core abstraction — a shared conversation every agent appends to.)


5. Topologies: the five shapes you will actually see

"Multi-agent" is not one architecture; it is a family of topologies — the graph of who can talk to whom. Five shapes cover essentially everything:

TopologyShapeWhen
Supervisor / orchestrator-workerone router delegates to N specialists, collects resultsthe default; a task with distinct sub-jobs and a clear "who's next" decision
Hierarchicalsupervisors of supervisors (teams of teams)large tasks that decompose into sub-tasks that themselves decompose
Network / peeragents hand off to each other directly, no central routerflexible collaboration; harder to bound and reason about
Sequential / parallel pipelinea fixed chain (A→B→C) or fan-out (A→{B,C,D}→join)the path is known — this is a workflow (Phase 00!), not really an "agent system"
Blackboardall agents read/write shared state, a controller picks who runsopportunistic problem-solving where any agent might contribute next

Two things to notice. First, the sequential / parallel pipeline is a workflow in disguise: if the order of agents is fixed and doesn't branch on runtime observations, you should hard-code it (Phase 00's "least-agentic that works") and get determinism for free — you don't need a model-driven supervisor to run A then B then C. Second, most production systems are supervisor-worker or a sequential pipeline. The exotic network/peer topologies look impressive in a diagram and become very hard to bound, debug, and cost-control in practice (whose turn is it? when does it stop?). The lab builds the supervisor-worker shape because it is the one you will actually ship, plus the critique-revise loop because verification is the one that pays.


6. The supervisor-worker pattern: routing by blackboard state

Here is the supervisor loop with nothing hidden — it is Phase 01's agent loop, one level up, where the "tools" are whole agents:

state := {task, completed: [], results: {}}
repeat up to max_turns times:
    decision := supervisor.policy(render(state))     # "researcher" | "writer" | "done"
    if decision == "done":  stop (reason = "done")
    handoff := make_handoff(from=supervisor, to=decision, task, context)  # validates target
    result  := worker[decision].act(render(handoff)) # the worker sees ONLY the handoff
    post result to the bus; state.results[decision] = result; state.completed += [decision]
stop (reason = "max_turns")     # the guard fired

The key design choice: the supervisor routes off the blackboard state, and its policy is a pure function of a rendered view of that state. It sees "the task is X; researcher has completed; writer has not" and returns "writer". It does not need to see the content of every result — it routes on progress, not on the details, which keeps the supervisor's context small and its decision simple. When it sees everything is done, it emits "done" and the loop stops.

Why is this better than the supervisor calling workers directly in code? Because the decision of who's next is made by a policy (a model, in production), so the system can adapt: if a worker's result says "I need more data," the supervisor can route back to the researcher. A fixed pipeline can't. That adaptivity is the only reason to use a model-driven supervisor at all — and if you don't need it, §5 says use a pipeline.

The max_turns guard is not optional. A confused supervisor can route in a circle (researcher → writer → researcher → …) forever; the budget stops it. We return to this in §10.


7. Typed handoffs and the least-context principle

A handoff is a first-class, typed transfer of work from one agent to another. In the lab it is a record Handoff(frm, to, task, context) — literally {from, to, task, context} — and two properties make it production-grade:

  1. Validate the target. make_handoff(...) checks that the destination agent exists before building the handoff; an unknown target is a routing bug that should fail loudly (ValueError), not silently drop the work. This is exactly how the OpenAI Agents SDK handoff works: you can only hand off to a declared agent, and the SDK surfaces the transfer as a first-class event. (In their model, a handoff is even exposed to the LLM as a special "tool" it can call — transfer_to_<agent> — so routing is just tool-calling.)
  2. Least-context. The receiving agent sees only the handoff's context, not the whole message history. This is the crucial discipline. Context is a budget (Phase 04): every token you hand a worker costs money, adds latency, and — past a point — degrades quality (lost-in-the-middle). So you pass the writer the researcher's findings and the task, and nothing else — not the supervisor's routing decisions, not the other workers' chatter, not the blackboard's bookkeeping. In the lab a test proves this: an "echo worker" returns exactly what it saw, and we assert its view contains its TASK: but not the supervisor's COMPLETED: line. One agent's context is another agent's noise.

The anti-pattern — passing the entire running transcript to every agent — is how multi-agent systems blow their token budget and their quality at the same time (see context explosion in §11). Least-context is the default; you widen it only when a specific agent demonstrably needs more.


8. Critique-revise: verification is the reliability lever

This is the section that justifies multi-agent existing at all. Recall Phase 00 §5: there are three levers to buy reliability back, and the third is verify instead of trusting. The critique-revise loop is that lever, implemented as two agents:

draft   := worker.act(task)                  # round 1
repeat (bounded by max_rounds):
    verdict := critic.act(review(task, draft))
    if verdict approves:   return (draft, rounds, approved=True)
    if rounds == max_rounds: return (draft, rounds, approved=False)   # out of budget
    draft := worker.act(revise(task, draft, feedback))   # incorporate the critic's feedback

Now the math, because it is the whole point. Suppose a worker produces a correct draft with probability \(p\). A single-agent system ships that draft: reliability \(p\). Add a critic that reliably catches bad drafts and forces one revision; if the revision is another independent draw at \(p\), the step now fails only if the first draft and the revision are both wrong:

$$P(\text{good after 1 revision}) = 1 - (1-p)^2.$$

At \(p = 0.9\) that is \(1 - 0.01 = 0.99\). One critic, one revision, and a 0.9 step became a 0.99 step — the same shape as the retry formula from Phase 00, but the "retry" is a verified redo, not a blind one. Extend to \(k\) allowed revisions and it is \(1 - (1-p)^{k+1}\), which is exactly why the loop is bounded: each round has diminishing returns and non-zero cost, so you cap it (max_rounds) and accept the best draft you have if the critic never approves.

Two subtleties the lab makes you get right:

  • The round count is the assertion. A good draft approved immediately is 1 round. A bad draft, revised once, then approved is 2 rounds. A never-approved draft stops at max_rounds. Tests assert each of these exactly, because the round count is the behavior — it tells you how much verification cost you paid.
  • The critic must be a pure function of the draft. In the lab the critic approves a draft that cites a source and rejects one that doesn't; because the revised draft differs from the original (it added the citation the feedback asked for), the same pure critic returns a different verdict. That is how a deterministic critic can reject-then-approve without any hidden state.

This is the legitimate core of multi-agent. Everything else (routing, handoffs) is plumbing; the critic is the part that changes the reliability arithmetic.


9. Reflection, debate, and the wider verification family

Critique-revise is one member of a family of verification-by-more-inference patterns. Knowing the family — and its limits — is a strong interview signal:

  • Reflection / self-refine. The same agent critiques and revises its own output (no second agent). Cheaper (one persona), but a model is a weak judge of its own work — it shares its own blind spots. A separate critic with a different prompt catches more.
  • Generator-critic (what you build). A dedicated critic agent, separate prompt/role, evaluates the generator. This is LangGraph's evaluator-optimizer and AutoGen's critic pattern.
  • Multi-agent debate. Several agents argue different positions and a judge (or a round of mutual critique) converges on an answer. The research line (Du et al., 2023, "Improving Factuality and Reasoning via Multiagent Debate") shows debate can improve factuality and reasoning on some tasks — and later work shows it is not a free win: it multiplies cost, can amplify a shared wrong prior, and often a single strong model with good prompting matches it.
  • Ensemble / vote. Run N generators, take the majority or a judge's pick — self-consistency, lifted to agents.

The unifying idea, and the thing to say out loud: these all spend more inference to buy more reliability, and they obey the same diminishing-returns-plus-cost tradeoff as retries. Debate is not magic; it is verification with a bigger bill. Reach for the cheapest member of the family that hits your reliability target — usually a single critic, sometimes just reflection, rarely a full debate.


10. The step budget: why multi-agent ping-pongs, and how to bound it

Single agents loop; multi-agent systems ping-pong. A supervisor routes to a worker who kicks work back to the supervisor who routes to the worker again; a critic rejects every draft and a stubborn worker never satisfies it; two peer agents hand off to each other forever. Every one of these is an infinite loop burning tokens and never terminating — the multi-agent version of Phase 00's "no max_steps" incident, and it is more likely here because there are more actors and more transitions.

So every loop is bounded, and the guard has a name at each level:

  • max_turns on the supervisor — the most delegations it will make before stopping. Hitting it returns a partial transcript with stopped_reason == "max_turns", not a hang.
  • max_rounds on the critique-revise loop — the most draft-critique cycles before accepting the best draft with approved == False.
  • Framework equivalents: LangGraph's recursion_limit, ADK's LoopAgent(max_iterations=...), AutoGen's max_turns / termination conditions.

These are the step budget from Phase 00, applied per loop. And the same rule holds: the guard is a safety net, not a target. If your critique loop routinely needs 8 rounds to get an acceptable answer, the fix is a better worker or a clearer critic, not raising the cap — a higher cap just lets a broken loop fail more expensively. The lab tests each guard directly: a supervisor that never says done stops at exactly max_turns; a critic that never approves stops at exactly max_rounds.


11. Coordination failure modes

Multi-agent adds failure modes a single agent does not have. Name them, because interviewers do, and because each has a specific guard:

  • Ping-pong loops — agents pass work back and forth without converging. Guard: bounded max_turns / max_rounds (§10).
  • Context explosion — passing the whole history to every agent, so each call's prompt (and cost, and latency) grows with the number of agents and turns. Guard: least-context handoffs (§7); summarize before handing off.
  • Cost / latency blowup — N agents, each doing multiple LLM calls, multiply the token bill and (if sequential) sum the latency. A 3-agent pipeline with a 2-round critic can be 5–10× a single agent. Guard: measure $/resolved-task (Phase 00 §8); only keep agents that earn their cost.
  • Error propagation — a bad output from one agent becomes another agent's trusted input and corrupts everything downstream; the researcher hallucinates a source, the writer cites it, the critic (if weak) approves it. Guard: the critic; typed results; validation at each handoff.
  • Responsibility diffusion — with many agents, no single one "owns" correctness, and each assumes another will catch the problem (the multi-agent version of the bystander effect). Guard: an explicit critic/owner role with the final say; a clear termination condition.

Notice that most guards are things you already built: the budget, least-context, the critic, and Phase 00's cost arithmetic. Multi-agent doesn't need new kinds of controls — it needs you to apply the old ones at every seam, because there are more seams.


12. When multi-agent is actually worth it: the honest tradeoff

Put the whole phase into one decision. Reach for multi-agent only when at least one of these is true, and you have checked the cost:

  • Genuine parallelism. The sub-tasks are independent and there are enough of them that fanning out to N workers is a real latency/throughput win (summarize 50 docs, probe 10 sources).
  • Genuine specialization + verification. The task benefits from a separate critic whose job is to catch what the generator misses, and the reliability lift (from §8) is worth the extra inference.
  • Genuine role separation. The sub-jobs are distinct enough that one focused agent per job is measurably more reliable than one agent juggling all of them.

And against it, always: multi-agent multiplies token cost, multiplies latency (sequential chains sum), and multiplies failure modes (§11). Anthropic's own write-up of their multi-agent research system is refreshingly blunt: it works for them because research is embarrassingly parallel and benefits from a lead agent delegating to sub-agents — and it costs about 15× the tokens of a single chat, so it is only worth it for high-value tasks. The senior instinct, transplanted from Phase 00 §10: start with a single well-tooled agent, add a critic if reliability needs it, and only go to a full multi-agent topology when the task's structure genuinely demands it. "This should be one agent with good tools" is the multi-agent version of "this should be a workflow," and it is just as often the right answer.


13. Framework mapping: AutoGen, CrewAI, LangGraph, ADK, OpenAI Agents SDK

Everything in the lab maps directly onto the frameworks the JDs name — and they are all elaborations of "agents posting to a shared channel, a supervisor routing, a bounded loop":

  • AutoGen (Microsoft; Wu et al., 2023) — conversational multi-agent. Agents (AssistantAgent, UserProxyAgent) share a message list and take turns; GroupChat + GroupChatManager is your supervisor over the bus; termination conditions are your max_turns. Your MessageBus is their conversation.
  • CrewAIrole/crew framing. You define agents with a role, goal, and backstory, group them into a Crew, and run Tasks either sequentially or through a manager (hierarchical). Your role tags and supervisor map straight onto this.
  • LangGraphgraph framing. Agents and tools are nodes; edges are control flow; the graph state is your blackboard. The supervisor and hierarchical patterns are prebuilt; the evaluator-optimizer is your critique-revise loop; recursion_limit is your max_turns.
  • Google ADKcomposition framing. LlmAgents wrapped in SequentialAgent / ParallelAgent / LoopAgent (your pipeline and bounded-loop topologies), with sub-agents and an AgentTool for delegation. LoopAgent(max_iterations=...) is your critique-revise guard.
  • OpenAI Agents SDKhandoff framing. Agents with handoffs=[...]; the Runner loop; a handoff is a first-class transfer surfaced to the model as a transfer_to_<agent> tool, with the target validated — exactly your make_handoff. guardrails validate at the boundary.

The skill is not memorizing each framework's node/decorator names — it is recognizing that they are the same four mechanisms (bus, roles, handoff, bounded verification) with different ergonomics, so you can pick one, debug it when it loops, and defend the choice.


14. Common misconceptions

  • "More agents = better / smarter." Usually false. More agents = more cost, latency, and failure modes. A single well-tooled agent beats a swarm on most tasks; multi-agent is for genuine parallelism or specialized verification, not for papering over a weak agent.
  • "Multi-agent is a different kind of thing from an agent." No — each agent is the same loop from Phase 01. The orchestrator is a loop over policies. It is composition, not a new primitive.
  • "Hand the whole conversation to every agent so they have full context." That is context explosion: it blows your token budget and degrades quality (lost-in-the-middle). Least-context handoffs are the default.
  • "A supervisor makes it reliable." Routing does not verify. The critic is what buys reliability back (\(1-(1-p)^{k+1}\)); a supervisor without a critic just distributes the same unreliability across more agents.
  • "Debate/reflection is free reliability." It is verification with a bigger inference bill and diminishing returns; sometimes a single strong model with good prompting matches a debate. Cost it before you ship it.
  • "You don't need a step budget if the agents are well-behaved." You always need one. The ping-pong loop shows up precisely when an agent is misbehaving, which is exactly when you can't rely on it to stop itself.
  • "Frameworks make coordination correct for you." Frameworks make it ergonomic. The termination bug, the context-explosion bill, the routing loop are still yours to prevent — and to debug at 2 a.m., which is why you build the bus from scratch here.

15. Lab walkthrough

Open lab-01-multi-agent-orchestrator/ and fill the TODOs top to bottom — the dataclasses and rendering helpers are already written so you focus on the coordination logic:

  1. MessageBus.post / history — stamp a monotonic seq, append, and return; history returns a copy you can filter by kind/sender/recipient. Get the ordering deterministic first; everything else depends on it.
  2. make_handoff — validate the target exists (ValueError if not), require a dict context, return the typed Handoff. This is the least-context, validated-target discipline.
  3. Supervisor.run — the bounded routing loop: render state → policy decision → "done" or a least-context handoff → worker acts on the handoff only → post the result → update the blackboard. Confirm it routes researcher then writer, stops on "done", and hits max_turns when the supervisor never finishes.
  4. parse_verdict then critique_revise — the verdict parser (never accidentally approve), then the bounded draft → critique → revise loop. Confirm the round counts: 1 for an immediately-good draft, 2 for revise-then-approve, max_rounds for never-approved.

Run LAB_MODULE=solution pytest -v first to see green, then match it. Finish by reading solution.py's main() — it runs the supervisor pipeline and the critique-revise loop and prints the full message-bus transcript so you can see the coordination.


16. Success criteria

  • You can draw the supervisor-worker topology and the blackboard, and explain why agents coordinate through a shared bus instead of direct calls.
  • You can name the five topologies and say which one a given task wants (and why the pipeline is really a workflow).
  • You can explain the least-context handoff and why passing the whole history is a bug.
  • You can derive \(1-(1-p)^2\) and say, in one sentence, why a critic buys reliability back.
  • You can list the coordination failure modes and the guard for each.
  • You can argue when not to go multi-agent — the "one agent with good tools" answer.
  • All 28 lab tests pass under both lab and solution.

17. Interview Q&A

Q: When would you use a multi-agent system, and when would you not? A: Use it when the task has genuine parallelism (independent sub-tasks worth fanning out), genuine role separation (distinct sub-jobs each more reliable as a focused agent), or benefits from a separate critic for verification. Don't use it to paper over a weak single agent — it multiplies token cost, latency, and failure modes. My default is a single well-tooled agent, add a critic if reliability needs it, and only go full multi-agent when the structure demands it. Anthropic's own multi-agent research system costs ~15× the tokens of a single chat and is worth it only because research is embarrassingly parallel — that framing is the honest tradeoff.

Q: Why route agents through a message bus / blackboard instead of having them call each other? A: Auditability and reproducibility. A shared, ordered, inspectable log means every interaction is recorded in one place, so I can replay a run, unit-test the coordination, and debug it by reading the transcript in order. Direct agent-to-agent calls are hidden side channels you can't audit or deterministically test. Order the log by a counter, not a wall clock, and two identical runs are byte-identical.

Q: What is a handoff, and what does "least-context" mean? A: A handoff is a first-class, typed transfer of work to a named, validated agent — {from, to, task, context}. Least-context means the receiver sees only the context it needs (the task plus the one prior result), not the whole history. Context is a budget: dumping everything blows the token bill and degrades quality via lost-in-the-middle, and one agent's chatter is another's noise. The OpenAI Agents SDK models a handoff as a transfer_to_<agent> tool with a validated target — same idea.

Q: How does adding a critic improve reliability — with numbers? A: If a worker's draft is correct with probability \(p\), a single agent ships at \(p\). A critic that catches bad drafts and forces one revision makes the step fail only if both the draft and the revision are wrong: \(1-(1-p)^2\). At \(p=0.9\) that's 0.99 — a 0.9 step became a 0.99 step. It's Phase 00's verification lever; with \(k\) revisions it's \(1-(1-p)^{k+1}\), which is exactly why the loop is bounded — diminishing returns against non-zero cost.

Q: Your multi-agent system is looping and never returns. What happened and how do you prevent it? A: Ping-pong: agents passing work back and forth (supervisor↔worker, or a critic that never approves) with no termination. Prevent it with a step budget on every loop — max_turns on the supervisor, max_rounds on the critique loop — that returns a partial result with a stopped_reason instead of hanging. The budget is a safety net, not a target; if a loop routinely needs many rounds, fix the agent, don't raise the cap.

Q: A PM wants "a team of five AI agents" for a task that's really fetch → summarize → check. Push back. A: Fetch → summarize → check is a mostly-fixed pipeline with one verification step, so it's a two-worker sequence plus a critic, not a five-agent swarm — and if the order never branches, the fetch/summarize part is a workflow (Phase 00). I'd build a single agent with a fetch tool and a summarize step, wrap the output in one critique-revise loop for the "check," and measure it against the swarm on $/resolved-task. Five agents would multiply cost and latency for no reliability gain. The senior move is usually fewer agents, not more.

Q: How do AutoGen, CrewAI, LangGraph, ADK, and the OpenAI Agents SDK relate to what you built? A: They're the same four mechanisms with different ergonomics. AutoGen is conversational (shared message list + a group-chat manager = my bus + supervisor). CrewAI is role/crew (agents with roles, a manager for hierarchy). LangGraph is a graph (nodes/edges, state = blackboard, evaluator- optimizer = my critique loop, recursion_limit = my budget). ADK composes Sequential/Parallel/ Loop agents with sub-agents. The OpenAI Agents SDK centers on validated handoffs. I built the bus, roles, handoff, and bounded verification underneath all of them, so I can pick one and debug it when it loops.


18. References

  • Wu et al., AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation (2023). https://arxiv.org/abs/2308.08155
  • Anthropic, How we built our multi-agent research system (2025) — the orchestrator-worker pattern and the ~15× token-cost tradeoff. https://www.anthropic.com/engineering/multi-agent-research-system
  • Anthropic, Building Effective Agents (2024) — orchestrator-workers, evaluator-optimizer, and "the simplest thing that works." https://www.anthropic.com/research/building-effective-agents
  • Du et al., Improving Factuality and Reasoning in Language Models through Multiagent Debate (2023). https://arxiv.org/abs/2305.14325
  • Park et al., Generative Agents: Interactive Simulacra of Human Behavior (2023) — many agents, memory, and a shared environment. https://arxiv.org/abs/2304.03442
  • Madaan et al., Self-Refine: Iterative Refinement with Self-Feedback (2023) — the reflection / critique-revise loop. https://arxiv.org/abs/2303.17651
  • OpenAI Agents SDK — agents, handoffs, and the Runner. https://openai.github.io/openai-agents-python/
  • LangGraph — multi-agent (supervisor, hierarchical) and evaluator-optimizer templates. https://langchain-ai.github.io/langgraph/concepts/multi_agent/
  • CrewAI — role/goal agents and crews. https://docs.crewai.com/
  • Google ADK — multi-agent systems, sub-agents, and Sequential/Parallel/Loop agents. https://google.github.io/adk-docs/agents/multi-agents/
  • Nii, The Blackboard Model of Problem Solving (AI Magazine, 1986) — the shared-state architecture multi-agent coordination descends from.