Lab 01 — Multi-Agent Orchestrator (Supervisor / Worker / Critic)

Phase 07 · Lab 01 · Phase README · Warmup

The problem

Phase 01 built one agent loop. Real systems sometimes need several agents with different jobs, talking to each other. This lab builds the mechanism underneath every multi-agent framework — a message bus / blackboard, roles, typed handoffs, and a critique-revise loop — with the LLM injected as a deterministic policy so you can assert the exact transcript:

  • Supervisor reads a shared blackboard and routes work to the right worker, then stops on "done" (the orchestrator / supervisor-worker topology).
  • Worker does a task and posts its result — and sees only the handed-off context, not the whole history (least-context handoff).
  • Critic evaluates a worker's draft and returns approve or revise: <feedback>. The critique-revise loop is the multi-agent reliability lever: verification buys back the reliability that Phase 00's 0.95^n takes away.

Every loop is bounded (max_turns / max_rounds), because a multi-agent system with no step budget is an infinite ping-pong waiting to happen.

What you build

PieceWhat it does
MessageBus.post / historyan ordered, deterministic message log + a shared state blackboard
Agent / Worker / Critic / Supervisorone base with an injected policy(context) -> str, three roles
make_handoffa typed {from, to, task, context} handoff that validates the target exists
Supervisor.runroute work to workers by blackboard state, via handoffs, until "done" or max_turns
parse_verdicta critic verdict → (approved, feedback); never accidentally approves
critique_reviseworker drafts → critic approves/revises → worker revises, bounded by max_rounds

File map

FileRole
lab.pyyour implementation (fill the # TODOs — dataclasses and renderers are given)
solution.pyreference + a worked example: a supervisor pipeline and a critique-revise loop
test_lab.py28 tests: the bus, routing-by-state, the max_turns guard, handoff validation, least-context, the round-count assertions, determinism
requirements.txtpytest only

Run it

pytest test_lab.py -v                       # your lab.py (red until you implement)
LAB_MODULE=solution pytest test_lab.py -v   # the reference (green)
python solution.py                          # the supervisor + critique-revise worked example

Success criteria

  • Your MessageBus posts in a deterministic order (a monotonic counter, never a clock) and history() returns a copy you can filter by kind/sender/recipient.
  • Supervisor.run routes to the right worker by state, terminates on "done", and stops at max_turns when the supervisor never finishes — with turns == max_turns.
  • make_handoff rejects an unknown target, and a worker sees only its handoff context (the COMPLETED: bookkeeping never leaks into a worker's view).
  • critique_revise approves a good draft in 1 round, revises a bad draft then approves in 2 rounds, and stops at max_rounds when the critic never approves.
  • Two identical runs produce byte-identical transcripts.
  • All 28 tests pass under both lab and solution.

How this maps to the real stack

  • The message bus / blackboard is AutoGen's group-chat message list and the classic blackboard architecture: agents coordinate through a shared, inspectable channel rather than hidden side-effects. Your state dict is the shared scratchpad every serious multi-agent framework exposes (CrewAI's shared context, LangGraph's graph state).
  • The supervisor is LangGraph's supervisor pattern and the OpenAI Agents SDK / Google ADK orchestrator-worker shape: one agent that routes to specialists. Your render_statepolicy → worker-name decision is exactly a supervisor node choosing the next edge.
  • The typed handoff is the OpenAI Agents SDK handoff: a first-class transfer to a named agent, carrying only the context that agent needs, with the target validated at construction. The least-context choice (pass the task + one prior note, not the whole log) is the production default — context is a budget (Phase 04), and one agent's chatter is another's noise.
  • The critique-revise loop is reflection / self-refine and the generator-critic pattern (LangGraph's evaluator-optimizer, AutoGen's critic agent). It is Phase 00's verification lever made concrete: a critic that forces one revision turns a 0.9 step into a ~0.99 one.
  • max_turns / max_rounds are the framework recursion/iteration limits (LangGraph's recursion_limit, ADK's LoopAgent max_iterations) — the guard against a ping-pong loop.

Limits of the miniature. Real agents are LLMs whose routing and critiques are themselves unreliable; real handoffs cross process/network boundaries (an agent can be a remote MCP server, Phase 03); real systems add parallel fan-out (map-reduce over workers), tool use inside each agent (Phase 02), and durability so a crash mid-handoff can resume (Phase 08). The coordination shape — bus, roles, typed handoff, bounded verification loop — is exactly this.

Extensions (your own machine)

  • Parallel fan-out. Add Supervisor.map(task, workers) that hands the same sub-task to N workers concurrently and a reduce step that a critic scores — the map-reduce topology.
  • Debate. Run two workers with opposing prompts and a judge critic that picks a winner (the multi-agent-debate line of work); measure whether debate beats a single critic.
  • Cost accounting. Add an llm_calls counter to the bus and print the cost of the supervisor pipeline vs a single agent doing the whole task — make Phase 00's "more agents multiply cost/latency" tradeoff concrete.
  • Wire a real model behind the Policy interface (one function swap per agent) and run the same supervisor + critique-revise against a live LLM; compare transcripts.

Interview / resume signal

"Built a multi-agent orchestrator from scratch — a deterministic message bus/blackboard, supervisor/worker/critic roles with an injected model, typed least-context handoffs with target validation, and a bounded critique-revise loop — and proved the coordination invariants (routes by state, terminates on done, never exceeds the turn/round budget) in the trace. Verification via a critic is the reliability lever that buys back Phase 00's 0.95^n."