Crack your next interview in 2 weeks — cohort starts Jul 27 — Join free →
ai agents system-design engineering

Multi-Agent AI Systems: The Two Bugs That Only Show Up After You Add a Second Agent

The first multi-agent system most engineers build works on the first try. That’s the trap.

It works because the demo only exercises the happy path: agent one produces something, agent two reads it, agent three reads that, done. Nobody hands agent two garbage. Nobody feeds agent three an instruction disguised as data. The moment you put that same pipeline in front of real, messy input — API timeouts, malformed responses, a tool result that happens to contain the string “ignore previous instructions” — it breaks in ways a single-agent system never does, and it often breaks quietly.

Why “multi-agent” isn’t automatically the right call

Before any of that, there’s a prior question worth asking honestly: does this task need more than one agent at all? A single agent with the right context window and the right tools handles most tasks fine. The case for splitting into multiple agents is narrow and specific — the task genuinely exceeds one context window, distinct steps need genuinely different expertise, or steps can run in parallel. “It has multiple steps” is not on that list. A three-step task is still one agent’s job if nothing forces the split.

Once you’ve earned the split, the question stops being “how many agents” and becomes “who’s responsible for what travels between them.”

The orchestrator’s one job

A multi-agent system is a set of specialized agents plus something that decides the order they run in, passes output from one to the next, and checks that what’s passed is trustworthy. That something — the orchestrator — is deliberately not an agent itself in the usual sense. For a fixed pipeline shape, the routing decision (“who runs next”) doesn’t need reasoning, so writing it as plain code is both cheaper and easier to debug than delegating it to another LLM call. The exception worth remembering: if the next step itself depends on interpreting what a previous agent said — not just “did it finish” but “what did it actually conclude” — that’s a case where an LLM-based routing decision earns its cost.

Everything else the orchestrator does comes down to one responsibility, repeated at every step: don’t let anything pass downstream unchecked.

The failure mode that looks like success

Here’s the one that catches teams off guard. An agent times out, or a downstream API call fails, or a parsing step returns an empty string instead of raising an error. If nothing checks that output before forwarding it, the next agent in the chain processes nothing meaningful — and the pipeline still finishes. No exception. No log line screaming for attention. The system reports success on a run that produced nothing of value.

Compare that to a crash: a crash is annoying but honest. It tells you immediately that something broke. Silent corruption doesn’t announce itself. The only symptom is that the final output, three agents downstream, is quietly useless — and by the time anyone notices, tracing it back to which handoff actually failed is a debugging exercise, not a two-second glance at a stack trace.

The fix is unglamorous: validate every handoff, every time, before it moves forward. Non-empty, correctly shaped, plausible length. It’s the kind of check that feels like overkill until the first time it saves a production run.

The failure mode that looks like a security problem, because it is one

The second failure mode is more interesting because it doesn’t require a malicious user at all. If one agent’s output can contain text, and the next agent treats that text as instructions rather than data, then anything that can influence the first agent’s output — a compromised tool call, a scraped web page, a poisoned retrieval chunk — can effectively give orders to the second agent. This is prompt injection, and in a multi-agent system it doesn’t need to come anywhere near your actual users to do damage.

The fix mirrors how you’d treat any other untrusted input: sanitize what crosses a trust boundary before the next component acts on it, and never assume that because content originated inside your own pipeline, it’s safe. An agent’s output is data to the next agent, not a command — that distinction has to be enforced by something outside both agents, which is, again, the orchestrator’s job.

What this buys you

None of this shows up in a demo. It shows up the first time a real production run hits a flaky dependency, or the first time someone’s retrieval pipeline pulls in a document with adversarial text buried in it. Teams that design the orchestrator to validate and sanitize from day one catch these as a log entry. Teams that don’t catch them as a support ticket asking why the AI feature “went crazy” — usually much later, and usually without a clean trail back to the cause.

Multi-agent systems are genuinely useful — for the narrow set of problems that actually need them. The engineering discipline that makes them trustworthy isn’t in the agents themselves. It’s in the boring code between them that decides what’s allowed to pass through.

This is exactly the ground covered in Session 06 of the AI Transition Course — including a hands-on project where you build this exact PM → Engineer → QA pipeline and deliberately trigger both failure modes yourself, so you’re debugging them for the first time in a sandbox instead of in production. It builds directly on the tool-use and agent-loop foundations from managing what an LLM actually remembers across a conversation — memory and multi-agent orchestration turn out to be the same discipline (deciding what’s trustworthy enough to carry forward) applied at different layers.

Find your path →

Want more like this?

Free newsletter. Real projects, delivered fortnightly.

No spam. Unsubscribe anytime. Replies go to a real person.

← Back to all articles