L3 · 03 · Multi-Agent Systems & Orchestration

One agent with the right tools solves most tasks. Multi-agent systems help when work is long-running, splits into independent subtasks, or benefits from a critic that isn't the author. This page covers the patterns that work in production, the coordination costs nobody mentions in demos, and agent-to-agent protocols.

Level 355 minTrack 3Last verified 2026-10

By the end of this page you can

Start with the honest question

Do you need more than one agent? Each extra agent adds latency, multiplies token cost, and introduces a new failure surface. Multi-agent earns its keep when subtasks are genuinely independent (parallel work), need different tools or permissions, or need separation of duties (the critic must not be the author). If a single agent with good tools can do it, do that.

The patterns that work

Pipeline triage draft send Orchestrator–worker orchestr. worker worker worker Author–critic author critic Planner–executor planner executor re-plan?
PatternShapeBest forWatch out
PipelineA → B → C, deterministic orderDocument workflows: extract → draft → reviewDoesn't need agents at every stage — code is fine
Orchestrator–workerOne agent spawns N parallel sub-agents, merges resultsIndependent subtasks: search 5 sources, check 10 filesMerging; workers reporting partial results as complete
Planner–executorPlanner emits steps; executor runs them; planner re-plans on failureLong tasks where early steps decide later onesRe-planning loops need hard caps
Author–criticAuthor produces, a separate agent reviews, iterate until pass or capCode, copy, anything with a checkable quality barPoliteness drift — critics go soft; give them a checklist
HandoffsOne agent transfers the conversation to a specialistTriage → specialist in chat productsState transfer; the specialist needs context, not a cold start

Artefacts, not conversations

The biggest practical rule: agents pass artefacts (files, JSON, summaries), not their full message histories. A worker returns "here are the 3 findings with citations", not 40 messages of exploration. This keeps each agent's context clean, makes results testable, and lets you swap agents without rewiring anything.

from concurrent.futures import ThreadPoolExecutor


def make_worker(model, role: str):
    def work(task: str) -> dict:
        # In production this is a real model call with the role as system prompt.
        # Returns an artefact (dict), not a conversation.
        return model(f"[{role}] {task}")
    return work


def orchestrate(task: str, subtasks: list[str], workers, merge) -> dict:
    with ThreadPoolExecutor(max_workers=len(subtasks)) as pool:
        artefacts = list(pool.map(lambda t: workers[t[0]](t[1]),
                                  enumerate(subtasks)))
    return merge(task, artefacts)


if __name__ == "__main__":
    # Scripted stand-ins: each "worker" returns a fake finding.
    scripted = lambda model: make_worker(model, "researcher")
    workers = [scripted(lambda p: {"finding": p[:40], "source": "doc-A"}),
               scripted(lambda p: {"finding": p[:40], "source": "doc-B"}),
               scripted(lambda p: {"finding": p[:40], "source": "doc-C"})]

    def merge(task, artefacts):
        return {"task": task, "n_findings": len(artefacts),
                "sources": sorted({a["source"] for a in artefacts})}

    result = orchestrate(
        "Why did pickup cancellations spike in June?",
        ["check order logs", "check staffing rota", "check promotion calendar"],
        workers, merge)
    print(result)

Three workers run in parallel, each returns a small artefact, and merge is plain code you can unit-test. That's the skeleton of every orchestrator–worker system.

The costs nobody mentions

Agents talking to agents: A2A and ACP

MCP connects a model to tools. Agent-to-agent protocols connect agents to agents — one agent delegating a task to another, possibly across organisations or runtimes.

ProtocolFocus
A2A (Agent2Agent)Agent cards describing capabilities, task delegation with lifecycle (submitted → working → completed), streaming updates
ACP and similarSimilar goals: discovery, structured task exchange between independent agents

These matter when agents live in different systems (your support agent calls a vendor's logistics agent). Inside one codebase, a function call is still simpler and better. The field is young — expect the spec names and versions to keep moving; the patterns above are the durable knowledge.

Permissions differ per agent — that's a feature

Separation of duties is a security pattern, not just an org chart: the drafting agent can read the ticket queue; the sending agent can send replies but not read the whole queue; the critic can only read. Each agent gets least-privilege tools (L2·09), and a compromise of one doesn't compromise the rest. L3·08 goes deeper.

Try it (60 min)
  1. Take a real multi-step task (e.g. "summarise these 3 documents, then compare them"). Do it with one agent and log the token use.
  2. Now do it as orchestrator–worker: one agent per document, merge in code. Compare tokens and answer quality.
  3. Add an author–critic loop to the merge step with a 4-item checklist. How many iterations until the critic passes?
  4. Break a worker (return an error artefact). Does your merge handle partial results honestly?

Key takeaways