Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 15 — Why Multiple Agents?

Intake, Resolution, Policy, and Outreach are built. The temptation is to make every stage a separate agent — more messages, credentials, failure modes, and eval work. That only pays when the split enforces a real boundary.

For O-1001, Policy decides whether a refund or reship proposal satisfies the rule pack. Outreach drafts or sends only after that verdict and only with the right permission. They do not need a debate to reach truth; policy runs against evidence and deterministic rules.

Intake facts → Resolution track → Policy verdict → Outreach draft → approve → send

This chapter adds the decision test: split for permissions, context isolation, blast radius, or eval surface — not because “agents feel advanced” or to dodge the FSM from Chapter 7.

First principles

The valid reasons are operational, not theatrical:

ReasonShopOps example
Permissions / SoDOutreach can send; Policy cannot; Intake cannot
Context isolationPolicy rules pinned without CRM novel-length notes
Model routingTiny classifier vs larger strategy narrative (Ch 34)
Latency / parallelismIndependent reads fan out
Org / trust boundaryVendor contact gateway vs in-house policy
Blast-radius isolationCompromised contact tools cannot read full order + payment PII
Eval surfaceScore policy agent on rule fixtures alone

These are not valid reasons:

  • “Agents feel more advanced”
  • Roleplay personas without capability differences
  • Belief that debate yields truth
  • Dodging a clear FSM (Ch 7) by chatting

The key test is blast radius: if one worker’s credentials leak, what can it still read, change, or send? If the answer is “everything,” the split did not isolate anything.

Concrete example

Policy separated from Outreach:

  • Policy mounts: rule pack, proposal read, verdict write to ledger.
  • Outreach mounts: draft/send channel adapters, reads verdicts.
  • Neither needs the other’s full prompt.
  • A single-process mode can still call the same functions in order — mode=single|multi is a deployment switch, not a different product.

Diagram

flowchart TD
  Q{Need multi-agent?} --> P[Different permissions?]
  P -->|yes| Split[Split]
  P -->|no| C[Different context / model / org boundary?]
  C -->|yes| Split
  C -->|no| E[Need separate eval surface?]
  E -->|yes| Split
  E -->|no| Mod[Keep modules in one agent]
  Split --> SoD[Enforce SoD in authz + mounts]
  Mod --> FSM[Prefer FSM / orchestrated stages]

Implementation

from shopops.orchestrator import (
    Orchestrator,
    default_supervisor,
    mode_config,
)

cfg = mode_config("multi")
assert cfg["separation_of_duties"] is True
orch = Orchestrator(default_supervisor())
orch.create_case("O-1001", topology=cfg["topology"], order_total_cents=240_00)

# Drive stages: intake → resolution → policy → outreach
while orch.cases["O-1001"].status == "open":
    orch.tick("O-1001")

assert orch.cases["O-1001"].status in {"completed", "failed", "awaiting_approval"}

# Same tools/functions, narrower topology
cfg_single = mode_config("single")
orch2 = Orchestrator(default_supervisor())
orch2.create_case("A-1002", topology=cfg_single["topology"])
orch2.tick("A-1002")

The workers are ordinary functions. “Multi-agent” here means separate contracts, capabilities, and ledger producers — optionally separate processes later (Ch 32). You can refactor an unjustified split back to modules without changing tool semantics.

Failure modes

  1. Persona proliferation — ten agents, one shared API key.
  2. Consensus theatre — majority vote on send window. send window are a clock, not an opinion.
  3. Chat as integration bus — unbounded transcripts as “state.”
  4. Split without eval — you cannot tell which agent regressed.
  5. Duplicate writes — two agents both “own” contact (Ch 17).

Production considerations

  • Write the SoD matrix before the prompts (architecture.md).
  • Prefer one orchestrated case worker with staged modules until a valid split reason appears.
  • When you split, split credentials and tool mounts, not only system prompts.
  • Measure: illegal send rate, cross-capability attempts, eval flake rate. If multi-agent worsens them, roll back.
  • Industry writeups on multi-agent failures are mostly about coordination and authority — treat them as systems lessons, not model-quality nits. [VERIFY SOURCE when citing a specific postmortem.]

Worked decision: Policy vs Outreach

Ask the split questions in order for ShopOps contact:

  1. Permissions? Yes — Outreach may draft/send under policy; Policy must not hold send credentials.
  2. Context? Yes — rule packs should stay pinned; CRM novels dilute them (Ch 3).
  3. Eval? Yes — Policy can go green on 100% deterministic fixtures before any model assist (Ch 38).
  4. Org boundary? Sometimes — if a vendor owns the email gateway, Outreach is already a trust boundary.

Resolution vs Intake is weaker: often same process, different modules, until Profile’s data plane must not see draft copy. Default to modules; graduate to agents when a row in the table lights up.

Anti-pattern autopsy: five personas in one process, one API key, shared scratchpad. You paid the coordination tax (Ch 16–17) and gained zero blast-radius reduction. Refactor back.

Cost of a bad split

Every extra agent process multiplies: credentials to rotate, prompts to version, eval surfaces to maintain, and conflict surfaces on the ledger. That cost is justified when SoD or blast radius demands it. It is not justified for “the Resolution persona sounds cooler.”

A useful review question in design docs: If we merged these two agents into functions tomorrow, which invariant would we lose? If the answer is only “roleplay flavor,” merge them. If the answer is “Outreach’s send credential would sit beside Policy’s rule pack in one mount,” keep the split — and prove it with authz tests (Ch 27).

Single-process multi-agent

mode=multi does not require Kubernetes on day one. Four workers as functions behind contracts already buy SoD if tool mounts and credentials differ. Process isolation comes later when blast radius or org boundaries demand it (Ch 32–33). Do not confuse “we named four agents” with “we isolated four trust domains.”

Chapter summary

  • Split for permissions, context, models, latency, org boundaries, isolation, eval — not roleplay.
  • Debate ≠ truth; clocks and rule packs are not committee topics.
  • mode=single|multi should share tool semantics.
  • Blast radius is the test of isolation.
  • Modules first; agents when boundaries are real.
  • SoD lives in authz and mounts.
  • Unjustified splits should be easy to undo.
  • Orchestration comes next (Ch 18); communication and conflict before that (Ch 16–17).

Exercises

  1. Take a design with five persona agents; rewrite as modules. List which splits you kept and why.
  2. Draw the SoD matrix for Intake / Resolution / Policy / Outreach — read vs write vs send.
  3. Implement a negative test: Outreach worker cannot append Profile-only ledger keys (extend ledger ACLs in a later chapter; stub the test now).
  4. Find one public multi-agent failure writeup; map it to a row in the valid/invalid table. [VERIFY SOURCE]

References

  • Anthropic. Building Effective Agents. 2024. [VERIFY URL]
  • Industry multi-agent failure writeups — cite specifically per claim. [VERIFY SOURCE]
  • OWASP LLM Top 10 — excessive agency / permission themes. [VERIFY edition]