Agentic AI

Workflows And Multi Agent Systems

Multi-Agent Failure Modes

Multi-agent systems frequently perform WORSE than

JrCodex·7 min read

Jr Codex Agentic AI Notes

Level: Advanced Prerequisites: Chapter 4: Agent Communication Time to complete: ~20 minutes


Table of Contents

  1. The Uncomfortable Baseline
  2. Error Compounding
  3. Cost Explosion
  4. Diffusion of Responsibility
  5. Coordination Deadlock
  6. Deciding Honestly
  7. Summary & Next Steps

1. The Uncomfortable Baseline

The Finding to Take Seriously
─────────────────────────────────────────
  Multi-agent systems frequently perform WORSE than
  a single well-equipped agent on the same task —
  while costing several times more and taking longer.

  This is not an argument against multi-agent. It is
  an argument for MEASURING, because the failure is
  invisible: the system produces plausible output
  and nobody compares it to the alternative.
─────────────────────────────────────────
Why the Intuition Misleads
─────────────────────────────────────────
  Human teams outperform individuals because humans
  have hard limits on attention, expertise and
  working hours, and communication between them is
  cheap and lossless-ish.

  For agents, almost the reverse holds: context is
  the scarce resource, "expertise" is a prompt, and
  communication is LOSSY and EXPENSIVE (Chapter 4).

  The analogy that makes multi-agent feel obviously
  right is the thing that makes it fail.
─────────────────────────────────────────

2. Error Compounding

The Arithmetic
─────────────────────────────────────────
  Suppose each agent is 90% reliable on its part.

  1 agent   ──►  0.90        =  90%
  3 chained ──►  0.90³       =  73%
  5 chained ──►  0.90⁵       =  59%

  And this UNDERSTATES it, because a wrong result
  from agent A is passed to B as an established
  fact. B has no way to know it is wrong and builds
  on it confidently.
─────────────────────────────────────────
def with_verification(agent, task, verify, max_retries=1):
    """Check at each boundary — the alternative is silent compounding."""
    for _ in range(max_retries + 1):
        result = agent.run(task)
        check = verify(result)                        # Module 4, Chapter 3's hierarchy
        if check.passed:
            return result
        task = task.with_feedback(check.reason)
    return result.mark_low_confidence()               # PASS THE DOUBT ON, do not hide it
The Mitigations
─────────────────────────────────────────
  VERIFY AT BOUNDARIES   a check between agents
                         costs one call and stops
                         compounding

  SHORTEN CHAINS         each removed hop removes a
                         multiplication

  PARALLEL NOT SERIAL    independent agents' errors
                         do not multiply — they stay
                         independent and are
                         detectable by disagreement

  PROPAGATE CONFIDENCE   Chapter 4's field, so
                         downstream agents can
                         discount weak inputs
─────────────────────────────────────────

3. Cost Explosion

Where the Money Goes
─────────────────────────────────────────
  SINGLE AGENT, 10 steps
    ~10 calls, one growing context.

  SUPERVISOR + 3 WORKERS, same task
    supervisor decisions          ~8 calls
    handoff briefs                 ~3 calls
    worker A internal loop         ~8 calls
    worker B internal loop         ~8 calls
    worker C internal loop         ~8 calls
    result summarisation           ~3 calls
    final synthesis                ~2 calls
                                 ─────────
                                  ~40 calls

  4x the calls. And each worker re-reads the goal
  and its brief, so token count grows faster still.
─────────────────────────────────────────
class MultiAgentBudget:
    """One budget for the WHOLE system, not one per agent."""
 
    def __init__(self, total_cents=300, per_agent_cents=80):
        self.total, self.per_agent = total_cents, per_agent_cents
        self.spent, self.by_agent = 0.0, {}
 
    def check(self, agent_name, estimate):
        if self.spent + estimate > self.total:
            raise BudgetExhausted(f"system budget reached ({self.spent:.0f}c)")
        if self.by_agent.get(agent_name, 0) + estimate > self.per_agent:
            raise BudgetExhausted(f"{agent_name} exceeded its allowance")
 
    def record(self, agent_name, actual):
        self.spent += actual
        self.by_agent[agent_name] = self.by_agent.get(agent_name, 0) + actual
Per-Agent Budgets Are Not Enough
─────────────────────────────────────────
  Five agents with generous individual limits can
  collectively spend far more than intended, and
  each one looks well-behaved in isolation.

  You need BOTH: a system-wide ceiling and a
  per-agent allowance. This is the multi-agent
  version of Module 4, Chapter 4's bounding layer.
─────────────────────────────────────────

4. Diffusion of Responsibility

What It Looks Like
─────────────────────────────────────────
  Supervisor: "Research agent, find the pricing."
  Research:   "I found tier names but no prices;
               the analysis agent may have better
               sources."
  Analysis:   "I was not given prices. The research
               agent handles that."
  Supervisor: synthesises a report describing "tier
               structures" without any prices, and
               presents it as complete.

  Every agent behaved reasonably. The task failed.
  Nobody owns the gap.
─────────────────────────────────────────
def check_coverage(plan, results) -> list[str]:
    """Verify every required output actually exists. Never ask the agents."""
    gaps = []
    for requirement in plan.required_outputs:
        provider = results.get(requirement.owner)
        if provider is None or provider.status != "completed":
            gaps.append(f"{requirement.name}: owner {requirement.owner} did not deliver")
        elif not satisfies(provider, requirement):
            gaps.append(f"{requirement.name}: delivered but does not meet the spec")
    return gaps
The Fix Is Structural
─────────────────────────────────────────
  EXACTLY ONE OWNER per required output, named in
  the plan before execution.

  An EXTERNAL coverage check against that plan —
  Module 4, Chapter 4's premature-completion check,
  extended across agents.

  Never ask the supervisor whether the task is
  complete. Ask the plan.
─────────────────────────────────────────

5. Coordination Deadlock

Three Shapes
─────────────────────────────────────────
  CIRCULAR WAITING   A waits for B's output, B waits
                     for A's. Both idle.

  PING-PONG          A delegates to B, B decides it
                     is A's job, delegates back.
                     Repeat until the budget is gone.

  POLITENESS LOOP    two agents agree with each other
                     indefinitely without producing
                     anything (Module 5, Chapter 4).
─────────────────────────────────────────
class DelegationGuard:
    def __init__(self, max_depth=3, max_handoffs=10):
        self.chain, self.count = [], 0
        self.max_depth, self.max_handoffs = max_depth, max_handoffs
 
    def check(self, sender, receiver):
        self.count += 1
        if self.count > self.max_handoffs:
            raise CoordinationFailure("handoff limit reached")
        if receiver in self.chain:                            # A ──► B ──► A
            raise CoordinationFailure(f"delegation cycle: {' → '.join(self.chain)}{receiver}")
        if len(self.chain) >= self.max_depth:
            raise CoordinationFailure("delegation too deep")
        self.chain.append(receiver)
 
    def complete(self, agent):
        if self.chain and self.chain[-1] == agent:
            self.chain.pop()                                  # unwind on return
Detect It in Code, Not in Prompts
─────────────────────────────────────────
  This is Module 4, Chapter 4's point again: the
  agents cannot see the cycle. From inside, each
  delegation looks reasonable.

  The delegation chain is a data structure your
  orchestrator owns. Check it there.
─────────────────────────────────────────

6. Deciding Honestly

Run This Before Committing
─────────────────────────────────────────
  1. Build the SINGLE-AGENT version with all the
     tools.
  2. Measure quality, cost, and p95 latency on your
     eval set (Module 7, Chapter 2).
  3. Build the multi-agent version.
  4. Measure the same three.
  5. Multi-agent must win on quality by enough to
     justify what it lost on cost and latency.

  If you cannot run this comparison, you cannot
  claim the architecture is justified.
─────────────────────────────────────────
When Multi-Agent Genuinely Wins
─────────────────────────────────────────
  ✓ Sub-tasks need large, INCOMPATIBLE contexts
    that will not fit together

  ✓ One agent would need 40+ tools

  ✓ Independent sub-tasks run in PARALLEL and
    latency matters more than cost

  ✓ Different sub-tasks genuinely need different
    MODELS — a cheap one for extraction, an
    expensive one for reasoning

  Note that all four are RESOURCE arguments, not
  intelligence arguments. That is the pattern.
─────────────────────────────────────────
The Default to Hold
─────────────────────────────────────────
  ONE agent, good tools, good context management,
  strong evaluation.

  Add a second agent when you can name which
  resource limit forced it — and can show the
  measurement.
─────────────────────────────────────────

7. Summary & Next Steps

Key Takeaways

  • Multi-agent systems often underperform a single well-equipped agent while costing more; the failure is invisible unless you measure the single-agent baseline.
  • Errors compound multiplicatively across chained agents and are passed downstream as established fact — verify at boundaries and propagate confidence.
  • Budgets must be both system-wide and per-agent, because five individually well-behaved agents can collectively overspend by far.
  • Diffusion of responsibility and delegation cycles are invisible from inside the agents; assign exactly one owner per output and detect cycles in orchestrator code.

Concept Check

  1. Why does the human-team analogy actively mislead when reasoning about multi-agent systems?
  2. Three chained 90%-reliable agents give 73% end-to-end. Why is the real figure typically worse?
  3. All four legitimate reasons for multi-agent share a property. What is it, and why does that matter?

Module 6 Complete — What's Next

You can now orchestrate durable, multi-step, multi-agent systems — and you have been told repeatedly to measure rather than assume. Module 7 is how: evaluating trajectories rather than outputs, and operating these systems once they are running.

Next Module

Module 7: Evaluating & Operating Agents


Jr Codex — 1-on-1 Personalized Coaching | Back to Module Index | Back to Agentic AI Index