Architectures
Multi-agent is a scaling decision, not a vibe. Supervisors, handoffs, shared blackboards — and the honest bill for what multi-agent costs you.
▶ Watch this reelWhat you'll learn
- Supervisor pattern
- Handoffs
- Shared state & blackboard
- When multi-agent hurts · A2A
Remember this
- Supervisor is the default topology: one legible decision-maker, testable specialists, compressed returns — mind the supervisor's context bottleneck
- Handoffs transfer ownership with distilled briefs and capability-checked routing; blackboards decouple agents via shared, status-annotated state
- Multi-agent's bill is real: cost, latency, distributed debugging; A2A standardizes agent-to-agent interop as MCP did for tools
Supervisor
- Central orchestrator + specialists; legible control flow; independent evals.
- Bottleneck: supervisor context → compressed returns, digest reads.
- Keep specialist boundaries sharp: route, don't let workers self-select.
Handoffs
- Transfer of ownership: distilled brief (goal/tried/facts/state).
- Capability-checked routing; graceful hand-backs with logged misses.
Blackboard
- Shared workspace: decoupled, async, inspectable.
- Schema = coordination protocol: sections with owner + status.
- Mix: messages for control, board for artifacts.
When multi-agent hurts
- Bill: cost × agents, latency × hops, distributed debugging, no auto-quality.
- Escalate only on proven single-context failure.
- A2A: agent-to-agent interop; MCP = tools, A2A = agents; portability hedge.
Code: Supervisor loop with compressed returns and budgets
async def supervisor(task: str):
board = Blackboard(task_id=new_id()) # shared state (ch.3)
budget = CostBudget(usd=2.00, wall=timedelta(minutes=10))
while not budget.exhausted():
plan = await llm(DELEGATE_PROMPT, task=task,
board=board.digest(), # compressed view
roster=specialist_cards())
if plan.done:
return plan.answer
results = await asyncio.gather(*[
run_specialist(step, board) for step in plan.parallel_batch])
for r in results:
board.write(r.section, # pointer, not payload
summary=r.summary,
artifacts=r.artifact_paths,
status="verified" if r.self_checked else "proposed")
return escalate(task, board.history())
# Specialists read/write sections; supervisor reads digests.
# The board — not message history — is the system's memory.