Guide

A multi-agent setup is usually an orchestrator that plans and workers (sub-agents) that execute slices of the task. The orchestrator reads the user goal, writes a task list, and merges what comes back. Each worker gets a brief, a tool set and an output schema. That brief matters more than a fancy message bus.

Concept

Before you start: an agent is a model-directed loop that can call tools until it stops. A worker is that loop, scoped to one task. Promote a function to a worker only when it needs multi-step tool use and a private context.

The big idea

The production shape is five steps:

  1. The orchestrator reads the user goal and produces a task list with a success criterion per item.
  2. It spawns workers, in parallel or in sequence, each with a task spec: goal, constraints, tools allowed, output schema.
  3. Workers run their own tool loops in fresh contexts.
  4. Workers return condensed results, not full transcripts.
  5. The orchestrator merges, resolves conflicts, may spawn follow-ups, then answers the user.

A mailroom is a useful picture. The orchestrator sorts incoming work onto labeled desks. Each clerk handles one pile and sends back a short report. The analogy breaks when two clerks must edit the same file: the mailroom has no lock.

A bad brief ("look into billing") produces vague worker output. A good brief is half the system: "Find the customer's plan, last invoice amount, and whether autofailure retries are enabled. Return JSON with keys plan, last_invoice_usd, autofailure. Cite tool observations."

Keep the strong model for planning and final synthesis. Use a cheaper, faster model for a narrow worker. That one routing choice often dominates latency and cost.

Walking through a competitive teardown

Goal: "Compare our checkout UX to Stripe, Adyen and Shopify checkout for guest users."

A single agent would browse three sites in one context, filling the window with three DOM dumps.

WorkerBriefTools
W1Guest checkout steps and friction on Stripe hosted checkoutsearch, fetch
W2Same for Adyensearch, fetch
W3Same for Shopifysearch, fetch
W4Our own checkout steps from the internal UX specread_resource

Each worker returns {steps[], friction[], citations[]}. The orchestrator builds a comparison table. Wall-clock is about the slowest worker plus synthesis, not the sum.

Python
import asyncio

async def run_worker(task):
    # Sketch: a real worker would run its own tool loop here.
    return {"task_id": task["id"], "findings": [f"done:{task['id']}"]}

async def main():
    tasks = [
        {"id": "t1", "brief": "Stripe guest checkout"},
        {"id": "t2", "brief": "Adyen guest checkout"},
    ]
    results = await asyncio.gather(*[run_worker(t) for t in tasks])
    print(results)

asyncio.run(main())
[{'task_id': 't1', 'findings': ['done:t1']}, {'task_id': 't2', 'findings': ['done:t2']}]

Avoid free-form chat between workers. Orchestrator to worker is a task spec. Worker to orchestrator is a schema-valid result. Worker to worker is none by default. Peer chat makes causality impossible to debug.

Common mistakes

  • A vague brief. "Look into billing" comes back as a paragraph you cannot merge.
  • Giving every worker the strong model. Planning needs it. Narrow fetch-and-extract often does not.
  • Letting workers talk to each other. Route collaboration through the orchestrator or a locked artifact.

Check yourself

  • Why is wall-clock closer to the slowest worker than to the sum? The four checkout workers run at the same time. Synthesis waits for the last one.
  • When should a parallel function stay a function, not a worker? When it does not need its own multi-step tool loop or a private context.

Key takeaways

  • The orchestrator writes sharp task specs. Workers run in clean contexts and return structured results.
  • Parallel workers buy wall-clock. They do not remove the need for a good brief.
  • Keep workers from chatting. Merge at the orchestrator.

Further learning

Next, see what each worker is allowed to remember in context isolation.