Module 1: Why Multi-Agent (and When Not To)

The cost of coordination

Description

Lesson 02 defined what a multi-agent system is: several agents, each with its own decision, coordinated by a mechanism that splits the work and gathers the results. This lesson answers the question that definition leaves open: how much does that mechanism cost? Not in the abstract — in numbers you can calculate before writing a single line of orchestration.

Every additional agent a system consults adds, at minimum, three measurable costs: one model call to decide who to delegate to, that specialist's internal calls to solve its part, and the messages ("hops") that travel back and forth between the coordinator and the specialist. You'll run a formula that grows with the number of specialists consulted, and a second, simpler model that shows how every additional step is also one more opportunity for something to go wrong. Neither example runs the full runner yet — that's lesson 05, with the real comparison of two systems — here you build the vocabulary and the numeric intuition that lesson 05 will apply to a concrete case.

Connection to the module

Lesson 01 said it in prose: "more agents = more calls, more steps, more error surface." This lesson turns it into executable code. Lesson 04 uses this same vocabulary — model calls, hops — to compare the cost of an agent with many tools against splitting those tools across several agents. Lesson 05 applies this lesson's formula to a real case, with agent-fundamentals's runner actually running.


Analogy: every new person in the chain is a chance for miscommunication

Pick back up the team-of-people analogy from lesson 01. If you solve a task alone, there's exactly one place where something can go wrong: your own work. If you ask someone else to solve a piece and hand it back to you, you've added two new places: the moment you explain the task to them (did they understand it correctly?) and the moment they hand the result back to you (did they communicate it correctly?). Neither of those is "work" in the sense of advancing the task — they're coordination overhead, and every new person in the chain multiplies them.

That's exactly what a multi-agent system pays for: every specialist a supervisor consults adds a "who do I send this to" decision and one message out and one back — before the specialist even starts working on the part only it can solve.


Worked example: cost grows with the number of specialists

We model two paths for solving a task that needs the work of n_specialists specialists: a single agent that does all the work itself (with no coordination messages at all), and a supervisor that delegates to n_specialists distinct agents. The number of internal calls it takes a specialist to solve its part — 3, on average, for a typical Reservo task with one quote and one action — is the same real number you'll see executed in lesson 05.

def single_agent_cost(n_specialists, calls_per_specialist=3):
    """A single agent solves the work of the N areas itself -- no
    routing, no synthesis, no messages between agents."""
    return {"model_calls": calls_per_specialist * n_specialists, "hops": 0}


def supervised_cost(n_specialists, calls_per_specialist=3):
    """A supervisor delegates to N specialists: 1 routing call, each
    specialist's internal calls, 1 synthesis call, and 2 hops
    (out and back) per specialist consulted."""
    route_calls = 1
    compose_calls = 1
    return {
        "model_calls": route_calls + calls_per_specialist * n_specialists + compose_calls,
        "hops": 2 * n_specialists,
    }


print(f"{'specialists':>14} | {'1 agent (calls/hops)':>24} | "
      f"{'supervisor+N (calls/hops)':>26} | {'extra calls':>16}")
for n in (1, 2, 3):
    single = single_agent_cost(n)
    multi = supervised_cost(n)
    extra = multi["model_calls"] - single["model_calls"]
    print(f"{n:>14} | {single['model_calls']:>10} / {single['hops']:<10} | "
          f"{multi['model_calls']:>12} / {multi['hops']:<10} | {extra:>16}")

What to expect:

   specialists |    1 agent (calls/hops) |  supervisor+N (calls/hops) |      extra calls
             1 |          3 / 0           |            5 / 2           |                2
             2 |          6 / 0           |            8 / 4           |                2
             3 |          9 / 0           |           11 / 6           |                2

Read the table carefully, because it holds two different stories. The extra calls column stays constant at 2, no matter how many specialists you consult — it's the supervisor's own fixed cost (one routing call, one synthesis call), and it doesn't grow with n because in this model the supervisor decides once who gets all the work, not once per specialist. The hops column, on the other hand, does grow: 2 * n, because every new specialist adds its own round trip. With a single specialist (n=1), the supervisor system uses exactly 5 calls and 2 hops against a single agent's 3 calls and 0 hops — the exact number you'll confirm, run end to end with the real runner, in lesson 05.


The second cost: more steps, more error surface

Counting calls and hops measures the cost in work. There's a second, different cost that matters just as much: every model call and every tool call is a step where something can fail — a malformed argument, a timeout, a wrong routing decision. If we model each step with a fixed probability of failing (a number invented for illustration, not a real measurement of any system), the probability that the whole path finishes with no failure at all drops with every additional step — not linearly, but multiplicatively.

def end_to_end_success(steps, failure_rate_per_step=0.02):
    """Simple, illustrative model: if each step has a fixed probability
    of failing, the probability that ALL steps go well is the product
    of each one, separately, going well."""
    return (1 - failure_rate_per_step) ** steps


steps_single = 3   # lesson 05's single agent: 3 calls
steps_multi = 5    # lesson 05's 2-agent system: 5 calls

success_single = end_to_end_success(steps_single)
success_multi = end_to_end_success(steps_multi)

print(f"System A (1 agent,  {steps_single} steps): "
      f"{success_single:.4f} ({success_single * 100:.2f}% end-to-end success)")
print(f"System B (2 agents, {steps_multi} steps): "
      f"{success_multi:.4f} ({success_multi * 100:.2f}% end-to-end success)")
print(f"difference: {(success_single - success_multi) * 100:.2f} percentage points "
      f"less reliable in System B, with the same 2% risk per step")

What to expect:

System A (1 agent,  3 steps): 0.9412 (94.12% end-to-end success)
System B (2 agents, 5 steps): 0.9039 (90.39% end-to-end success)
difference: 3.73 percentage points less reliable in System B, with the same 2% risk per step

The point isn't that 0.02 is the real probability of a call failing in production — that figure depends on the system, the provider, and a thousand factors this guide doesn't measure. The point is structural: with the same failure rate per step, a 5-step path is arithmetically less reliable than a 3-step one, because success probability multiplies, it doesn't subtract. Every extra call coordination adds isn't just time and cost — it's one more chance for the whole system to fail, even if every individual step is exactly as reliable as any other.


Why this lesson doesn't run the full runner yet

It might seem odd that this lesson, so focused on "the cost of coordinating," doesn't run run_agent_parallel or build any real AgentMessage. That's deliberate: the formulas above (single_agent_cost, supervised_cost, end_to_end_success) are models — they capture the shape in which cost grows, for any task with that structure, without tying themselves to a specific Reservo task. Lesson 05 takes exactly the n=1 case from the table above — a system with a single specialist consulted — and makes it concrete: a real Reservo task, a real runner, a real script, and the same numbers (3 vs. 5, 0 vs. 2 hops) confirmed with the complete history printed on screen, not with a formula.


Common mistakes

  1. Confusing "extra calls" (fixed) with "hops" (grows with N). In this lesson's model, adding a third specialist doesn't add a third routing or synthesis call — the supervisor still decides only once — but it does add 2 more hops. Treating both costs as if they grow the same way leads to underestimating one or overestimating the other.

  2. Taking the reliability model's 0.02 as a real production number. It's an illustrative value chosen to keep the example readable, not a measurement of any system — the point to take away is the multiplicative shape of the drop, not the exact figure.

  3. Thinking the cost of coordinating always justifies avoiding multi-agent. This lesson measures the cost; it doesn't say the cost is never worth paying. Lesson 06 shows real cases where it is, despite the cost measured here.

  4. Assuming calls_per_specialist=3 is a universal constant. It's this guide's number, for the concrete task you'll see in lesson 05 (quoting and booking). A task with more internal steps — or with retries for errors, a topic from agent-fundamentals M7 — would have a higher number, and the gap between the two paths would grow in the same proportion.

  5. Forgetting single_agent_cost isn't free either. A single agent doing n_specialists times more internal work also has a cost that grows with n — it just grows without the extra cost of routing, synthesis, and hops. The comparison is always relative, never "multi-agent costs something, one agent costs nothing."


Exercises

Exercise 1: Read the formula without running it (Easy)

Without running any code: (a) if n_specialists=4, how many model calls does supervised_cost use with calls_per_specialist=3? (b) how many hops? (c) how many extra calls does it have over single_agent_cost for the same n?

See solution

(a) route_calls + calls_per_specialist * n_specialists + compose_calls = 1 + 3*4 + 1 = 14 calls.

(b) 2 * n_specialists = 2 * 4 = 8 hops.

(c) single_agent_cost(4) = 3 * 4 = 12 calls. The difference is 14 - 12 = 2 extra calls — the same fixed cost as always (1 routing + 1 synthesis), no matter that n went up from 1 to 4. This is exactly the pattern the worked example's table shows: extra calls stay at 2 across every row.

Exercise 2: Extend the table and graph the growth of hops (Medium)

Run supervised_cost and single_agent_cost for n_specialists from 1 to 6, and print, in addition to the worked example's columns, the supervised system's hops / model_calls ratio for each row (rounded to 2 decimals). Does the ratio grow, shrink, or stay stable as n increases?

See solution
def single_agent_cost(n_specialists, calls_per_specialist=3):
    return {"model_calls": calls_per_specialist * n_specialists, "hops": 0}


def supervised_cost(n_specialists, calls_per_specialist=3):
    route_calls = 1
    compose_calls = 1
    return {
        "model_calls": route_calls + calls_per_specialist * n_specialists + compose_calls,
        "hops": 2 * n_specialists,
    }


print(f"{'n':>3} | {'calls':>6} | {'hops':>5} | {'hops/calls':>11}")
for n in range(1, 7):
    multi = supervised_cost(n)
    ratio = multi["hops"] / multi["model_calls"]
    print(f"{n:>3} | {multi['model_calls']:>6} | {multi['hops']:>5} | {ratio:>11.2f}")

Expected output:

  n |  calls |  hops | hops/calls
  1 |      5 |     2 |        0.40
  2 |      8 |     4 |        0.50
  3 |     11 |     6 |        0.55
  4 |     14 |     8 |        0.57
  5 |     17 |    10 |        0.59
  6 |     20 |    12 |        0.60

Explanation: the ratio grows, though more and more slowly (0.40 → 0.50 → 0.55 → 0.57 → 0.59 → 0.60, approaching a ceiling). It makes algebraic sense: hops grow as 2n (pure, no fixed cost) while calls grow as 3n + 2 (with the fixed routing-and-synthesis cost added once); as n grows, the fixed cost weighs less and less on the total, and the hops proportion approaches 2/3 ≈ 0.67 — the limit the ratio would have if the fixed cost didn't exist. In systems with many specialists, almost all the coordination cost ends up being hops, not the supervisor's two fixed calls.

Exercise 3: Design a cost model for the pipeline pattern (Hard)

Modules 2 and 3 of this guide distinguish the supervisor pattern (a coordinator decides who to delegate to) from the pipeline pattern (a fixed sequence of agents, each feeding the next, with no routing decision at each step). Write a function pipeline_cost(n_stages, calls_per_stage=3) that models the cost of a pipeline of n_stages agents in sequence, where there's no routing call per stage (the order is already fixed in advance) but there is 1 hop between each consecutive stage (one stage's result passes to the next). Compare its result with supervised_cost for n=3 and explain, in one sentence, why the pipeline should cost fewer hops than the supervisor for the same number of stages.

See solution
def pipeline_cost(n_stages, calls_per_stage=3):
    """A pipeline has NO routing call per stage -- the order is already
    fixed -- but it does have one hop between each consecutive stage
    (n_stages - 1 hops for n_stages chained stages)."""
    return {
        "model_calls": calls_per_stage * n_stages,
        "hops": max(0, n_stages - 1),
    }


def supervised_cost(n_specialists, calls_per_specialist=3):
    route_calls = 1
    compose_calls = 1
    return {
        "model_calls": route_calls + calls_per_specialist * n_specialists + compose_calls,
        "hops": 2 * n_specialists,
    }


pipe = pipeline_cost(3)
sup = supervised_cost(3)
print(f"pipeline (3 stages):   {pipe['model_calls']} calls, {pipe['hops']} hops")
print(f"supervisor (3 agents): {sup['model_calls']} calls, {sup['hops']} hops")

Expected output:

pipeline (3 stages):   9 calls, 2 hops
supervisor (3 agents): 11 calls, 6 hops

Explanation: the pipeline uses fewer calls (9 vs. 11, because it doesn't pay the supervisor's routing or synthesis call) and far fewer hops (2 vs. 6). The underlying reason: in a pipeline, each stage only needs to pass its result to the next one — one hop per join between consecutive stages, n_stages - 1 in total — while in a supervisor each specialist has to go out and back to the central coordinator — 2 hops per specialist, no matter how many specialists there are in total. This is exactly the cost advantage Module 3 of this guide will exploit when a task always needs the same steps, in the same order: a pipeline is cheaper to coordinate than a supervisor, at the cost of losing the flexibility to decide the path at each step.


Summary and next step

  • Every specialist a multi-agent system consults adds, at minimum, internal model calls (to solve its part) and hops (to receive the task and hand back the result) — a cost a single agent, solving everything itself, doesn't pay.
  • We ran single_agent_cost and supervised_cost: for a single specialist consulted, the supervisor pattern uses 2 extra calls (5 vs. 3) and 2 hops (vs. 0) against a single agent — the exact concrete case lesson 05 will confirm with the real runner.
  • A second, distinct, and equally measurable cost: with the same failure rate per step, a path with more steps is arithmetically less reliable (0.98**3 = 94.12% vs. 0.98**5 = 90.39% in our illustrative model) — more error surface, not just more time.
  • Neither cost says "never use multi-agent" — it says "know the price before you pay it." Lesson 06 shows when the price is worth it.

Next lesson: 04 — One agent with many tools vs. many agents. With the cost vocabulary now built, we apply it to the other side of the decision: is it better to grow a single agent's tool registry, or to split those tools across several specialists?


Additional resources

  1. Anthropic — Building effective agents — Why adding steps and agents has a cost in latency and reliability that must be justified against the benefit, not assumed free.
  2. Anthropic — Multi-agent research system — The real coordination cost Anthropic reports in a production multi-agent system (more tokens, more calls) versus a single agent.
  3. Python — Functions and ** for exponentiation — The operator used in end_to_end_success for the compound reliability model.
  4. Python 3.14 — What's New — The version this lesson's code all runs on.