InterviewKata
AI engineering · Case study 11 · AI in the real world

Anthropic: a multi-agent research system

When Claude's Research feature answers a broad question, it doesn't use one agent. A lead agent plans the research, starts several subagents that search in parallel, each in its own context window, and then writes the answer from their findings. In June 2025 Anthropic published how they built it, with numbers: a large gain over a single agent, a large token bill, and a list of ways early versions went wrong. It's the clearest public evidence for when the supervisor architecture pays.

A 2-minute conversation: Sam asks, Priya explains
0:00 / 2:08

1. The situation

Research questions such as "find all the board members of the companies in this sector" have many independent leads. One agent working through them in sequence runs out of context window and time; it has to keep every search result in one place while it decides where to look next.

Real case, from the buildersAll facts and quotes are from "How we built our multi-agent research system" (Anthropic Engineering, 13 June 2025). The demo's numbers are illustrative.

2. What they built, and what it achieved

FindingReported
QualityA lead (Claude Opus 4) with subagents (Claude Sonnet 4) beat a single Opus 4 agent by 90.2% on Anthropic's internal research evaluation
CostAgents use about 4× the tokens of a chat; "multi-agent systems use about 15× more tokens than chats"
What drives resultsOn the BrowseComp evaluation, three factors explained 95% of the variance in performance; token usage alone explained 80%
SpeedRunning subagents in parallel, each using tools in parallel, cut research time by up to 90% for complex queries
FitBest for breadth-first questions with many independent directions; the economics work only for high-value tasks

3. How it works

Orchestrator-worker: the architecture Module 07a calls a supervisor.

4. The trade-off in code

A model of the trade-off, with illustrative numbers. One agent keeps every result in one window, rereading it each step, until the window is full. A lead with subagents gives each sub-question a fresh window, so subagents can dig deeper and all run at once. For a simple fact, the team is slower and costs 2.5× the tokens. For broad research, one agent answers only half the sub-questions before its window fills; the team answers all eight, faster, for 1.7× the tokens. The program was run in all three languages; each prints the output below it.

WINDOW = 30000       # tokens one agent's context can usefully hold
RESULT = 2000        # tokens each search or page read adds
STEP = 4             # seconds per tool call
BRIEF, SUMMARY = 500, 1500    # tokens: a task brief, a subagent's returned summary
CALLS_SINGLE = 3     # tool calls per sub-question for one agent sharing its window
CALLS_SUB = 5        # a subagent with its own window can afford to dig deeper


def single_agent(questions):
    """One agent, one context: every result stays in the window, and each step rereads it."""
    context, processed, covered, calls = BRIEF, 0, 0, 0
    for _ in range(questions):
        if context + CALLS_SINGLE * RESULT > WINDOW:
            break                                  # the window is full: the rest goes unanswered
        for _ in range(CALLS_SINGLE):
            processed += context
            context += RESULT
            calls += 1
        covered += 1
    return covered, calls * STEP, processed + context


def lead_and_subagents(questions):
    """The lead writes a brief per sub-question; subagents research in parallel, each in a fresh window."""
    processed = BRIEF + questions * BRIEF          # the lead plans and writes briefs
    for _ in range(questions):
        context = BRIEF
        for _ in range(CALLS_SUB):
            processed += context
            context += RESULT
        processed += context                       # the subagent writes its summary
    processed += questions * SUMMARY               # the lead reads every summary and writes the answer
    return questions, CALLS_SUB * STEP, processed


for questions, kind in ((1, "simple fact"), (8, "broad research")):
    c1, t1, k1 = single_agent(questions)
    c2, t2, k2 = lead_and_subagents(questions)
    print(f"{kind}, {questions} sub-question{'s' if questions > 1 else ''}:")
    print(f"  one agent:        answered {c1}/{questions}, {t1:3} s, {k1:7,} tokens")
    print(f"  lead + subagents: answered {c2}/{questions}, {t2:3} s, {k2:7,} tokens ({k2 / k1:.1f}x the tokens)")
const WINDOW = 30000; // tokens one agent's context can usefully hold
const RESULT = 2000; // tokens each search or page read adds
const STEP = 4; // seconds per tool call
const BRIEF = 500, SUMMARY = 1500; // tokens: a task brief, a subagent's returned summary
const CALLS_SINGLE = 3; // tool calls per sub-question for one agent sharing its window
const CALLS_SUB = 5; // a subagent with its own window can afford to dig deeper

// One agent, one context: every result stays in the window, and each step rereads it.
function singleAgent(questions: number): [number, number, number] {
  let context = BRIEF, processed = 0, covered = 0, calls = 0;
  for (let q = 0; q < questions; q++) {
    if (context + CALLS_SINGLE * RESULT > WINDOW) break; // the window is full: the rest goes unanswered
    for (let c = 0; c < CALLS_SINGLE; c++) { processed += context; context += RESULT; calls++; }
    covered++;
  }
  return [covered, calls * STEP, processed + context];
}

// The lead writes a brief per sub-question; subagents research in parallel, each in a fresh window.
function leadAndSubagents(questions: number): [number, number, number] {
  let processed = BRIEF + questions * BRIEF; // the lead plans and writes briefs
  for (let q = 0; q < questions; q++) {
    let context = BRIEF;
    for (let c = 0; c < CALLS_SUB; c++) { processed += context; context += RESULT; }
    processed += context; // the subagent writes its summary
  }
  processed += questions * SUMMARY; // the lead reads every summary and writes the answer
  return [questions, CALLS_SUB * STEP, processed];
}

const fmt = (n: number, w: number) => n.toLocaleString("en-US").padStart(w);
for (const [questions, kind] of [[1, "simple fact"], [8, "broad research"]] as [number, string][]) {
  const [c1, t1, k1] = singleAgent(questions), [c2, t2, k2] = leadAndSubagents(questions);
  console.log(`${kind}, ${questions} sub-question${questions > 1 ? "s" : ""}:`);
  console.log(`  one agent:        answered ${c1}/${questions}, ${String(t1).padStart(3)} s, ${fmt(k1, 7)} tokens`);
  console.log(`  lead + subagents: answered ${c2}/${questions}, ${String(t2).padStart(3)} s, ${fmt(k2, 7)} tokens (${(k2 / k1).toFixed(1)}x the tokens)`);
}
import java.util.Locale;

public class Main {
    static final int WINDOW = 30000;   // tokens one agent's context can usefully hold
    static final int RESULT = 2000;    // tokens each search or page read adds
    static final int STEP = 4;         // seconds per tool call
    static final int BRIEF = 500, SUMMARY = 1500; // tokens: a task brief, a subagent's returned summary
    static final int CALLS_SINGLE = 3; // tool calls per sub-question for one agent sharing its window
    static final int CALLS_SUB = 5;    // a subagent with its own window can afford to dig deeper

    // One agent, one context: every result stays in the window, and each step rereads it.
    static int[] singleAgent(int questions) {
        int context = BRIEF, processed = 0, covered = 0, calls = 0;
        for (int q = 0; q < questions; q++) {
            if (context + CALLS_SINGLE * RESULT > WINDOW) break; // the window is full: the rest goes unanswered
            for (int c = 0; c < CALLS_SINGLE; c++) { processed += context; context += RESULT; calls++; }
            covered++;
        }
        return new int[] {covered, calls * STEP, processed + context};
    }

    // The lead writes a brief per sub-question; subagents research in parallel, each in a fresh window.
    static int[] leadAndSubagents(int questions) {
        int processed = BRIEF + questions * BRIEF; // the lead plans and writes briefs
        for (int q = 0; q < questions; q++) {
            int context = BRIEF;
            for (int c = 0; c < CALLS_SUB; c++) { processed += context; context += RESULT; }
            processed += context; // the subagent writes its summary
        }
        processed += questions * SUMMARY; // the lead reads every summary and writes the answer
        return new int[] {questions, CALLS_SUB * STEP, processed};
    }

    public static void main(String[] args) {
        int[][] runs = {{1}, {8}};
        String[] kinds = {"simple fact", "broad research"};
        for (int i = 0; i < 2; i++) {
            int questions = runs[i][0];
            int[] a = singleAgent(questions), b = leadAndSubagents(questions);
            System.out.println(kinds[i] + ", " + questions + " sub-question" + (questions > 1 ? "s" : "") + ":");
            System.out.println(String.format(Locale.US, "  one agent:        answered %d/%d, %3d s, %,7d tokens", a[0], questions, a[1], a[2]));
            System.out.println(String.format(Locale.US, "  lead + subagents: answered %d/%d, %3d s, %,7d tokens (%.1fx the tokens)", b[0], questions, b[1], b[2], (double) b[2] / a[2]));
        }
    }
}
simple fact, 1 sub-question:
  one agent:        answered 1/1,  12 s,  14,000 tokens
  lead + subagents: answered 1/1,  20 s,  35,500 tokens (2.5x the tokens)
broad research, 8 sub-questions:
  one agent:        answered 4/8,  48 s, 162,500 tokens
  lead + subagents: answered 8/8,  20 s, 280,500 tokens (1.7x the tokens)

5. Try it: is a team worth it?

6. What went wrong on the way

7. Lessons: when the supervisor pattern pays

8. Your turn

  1. Find the breadth (10 min). Name one task in your work with many independent directions, and one that looks similar but is coupled.
  2. Write a brief (10 min). For one subagent: objective, output format, tools and sources, boundaries.
  3. Price it (10 min). Estimate the tokens of a single agent and a team for that task. Is the better answer worth the difference?
Say it in the interview
  • "When would you use multiple agents?" For breadth-first work with independent parts, like research or multi-angle review. Anthropic's research system beat a single agent by 90% that way, but used about 15× a chat's tokens, so I'd reserve it for valuable tasks and keep coupled work in one agent.

9. Check yourself

By how much did Anthropic's multi-agent system beat a single agent on its internal research evaluation?

A lead with parallel subagents, on broad research questions.

Roughly how many tokens did the multi-agent system use compared with a chat?

Agents used about 4× chat; multi-agent about 15×.

Early versions spawned 50 subagents for simple queries. What fixed it?

A simple fact needs one agent and a few tool calls.

Which kind of task fits this architecture best?

Independent parts run in parallel, in separate windows.

10. Sources and further reading

ResourceWhy
How we built our multi-agent research system (Anthropic, June 2025)Every fact and quote on this page.
C12: Cognition, don't build multi-agentsThe counter-argument, for coupled work.
Modules 07a and 16aArchitectures, and running teams of agents.