Code, craft, and hard-won lessons.
Building with code & caffeine.

LLM Agents Are Distributed Systems β€” Treat Them Like It

Multi-agent AI is having its microservices moment. Teams are decomposing monolithic prompts into fleets of specialised agents β€” a planner, a coder, a reviewer, a test runner β€” connected by orchestration layers that look deceptively simple in diagrams. Then they hit production and discover what distributed systems engineers have known for 40 years: splitting a system across independent processes introduces a class of failure that is fundamentally different from single-process bugs.

The irony is that most of the hard-won knowledge already exists. Lamport’s clocks, the CAP theorem, idempotent consumers, bulkheads, backpressure β€” this is solved territory. But AI teams are largely not coming from systems backgrounds, and AI frameworks are not surfacing these concepts. The result is brittle agent pipelines that fail in opaque, non-deterministic ways that are genuinely difficult to debug.

This is a correctable mistake. The patterns transfer directly. Here is how to apply them.


The Core Problem: Partial Failure

In a single process, failure is binary. Either the function returns or it throws. In a distributed system β€” and a multi-agent pipeline is a distributed system β€” a component can be in a third state: unknown. The agent sent a message; did the downstream agent receive it? Did it act on it? Did it complete? You often cannot know.

Classic distributed systems handle this with acknowledgement protocols and idempotency. An LLM agent pipeline needs the same discipline. Consider an orchestrator that dispatches a coding task to a sub-agent:

orchestrator β†’ [write code for feature X] β†’ coding-agent

If the orchestrator crashes after dispatching but before receiving the result, it will retry on restart. If the coding agent is not idempotent β€” i.e., running the same task twice produces side effects (committed files, API calls, database writes) β€” you have a consistency problem. The fix is the same fix as in any message-driven system: give every task a stable ID, and make every agent check whether it has already processed that ID before acting.

This sounds obvious. It is rarely implemented.


Ordering Is Not Guaranteed

Agent pipelines that fan out to parallel sub-agents and then collect results assume that ordering is preserved. It is not, for the same reason it is never preserved in distributed systems: network (or in this case, inference) latency is non-deterministic.

A concrete example: a pipeline that runs three agents in parallel β€” research, summarise, critique β€” and then feeds their outputs into a synthesis agent may receive those outputs in any order, including partial orders where critique arrives before the thing it was supposed to critique.

The synthesis agent’s context window is not a database with transactions. It will process whatever arrives in whatever order it arrives, and the output will silently vary based on that ordering. This is not a prompt engineering problem. It is a sequencing problem that requires explicit coordination: barriers, join points, or dependency graphs that enforce that critique cannot begin until summarise has completed.

Tools like LangGraph and similar DAG-based frameworks are beginning to encode this, but most teams building custom pipelines are not thinking in those terms.


Context Windows Are Buffers With Backpressure

Every distributed system has bounded buffers. When producers outpace consumers, buffers fill and you need a backpressure strategy: drop, block, or shed load. LLM context windows are bounded buffers. When an agent pipeline feeds more context into a downstream agent than its context window can accommodate, something is dropped β€” but silently, and with no clear contract about what.

This is worse than a full queue. A queue tells you it is full. A context window silently truncates or, depending on the implementation, wraps around and loses early instructions. The agent continues to produce output that looks plausible but is missing critical context.

The engineering response is the same as in stream processing: apply backpressure explicitly. Before dispatching to a downstream agent, estimate context utilisation. If the payload would push the agent past a safe threshold, summarise or paginate before sending. Treat the context window as a resource with a capacity contract, not as a black box that accepts arbitrary input.


Observability Is Not Optional

In a monolith, a debugger and a stack trace are often sufficient. In a distributed system, you need distributed tracing β€” correlation IDs that follow a request across every service boundary, structured logs at every handoff, and metrics on latency and error rates per stage.

Agent pipelines need the same infrastructure, and almost none of them have it. The typical debugging experience is: the pipeline produced a wrong answer; good luck figuring out which agent made the error, what context it received, what it returned, and how that propagated.

Structured tracing for agent pipelines should record, at minimum:

  • A root trace ID for the entire run
  • A span for every agent invocation, including input tokens, output tokens, and wall time
  • The full input and output at each stage (or a hash of it, for privacy)
  • Any tool calls made by agents, with their inputs and results

OpenTelemetry spans work for this. Several agent frameworks are beginning to emit them. If yours does not, instrument it manually. There is no debugging an opaque multi-agent system without it.


Failure Modes Compound

The properties above interact. An agent pipeline that has no idempotency, no ordering guarantees, no backpressure, and no observability will exhibit failure modes that are multiplicative, not additive. A partial failure causes a retry, which runs out of order due to non-deterministic timing, which overflows the context window of a downstream agent, which produces subtly wrong output, which is invisible because there is no tracing. Each issue is individually manageable. Together they produce cascading, difficult-to-reproduce failures that erode trust in the system.

The path forward is boring: apply distributed systems discipline to agent architecture from the start. Design for idempotency. Model your pipeline as a DAG with explicit sequencing guarantees. Treat context windows as bounded resources. Instrument everything.


The Silver Lining

Distributed systems engineering has 40 years of accumulated tooling and theory. The hard problems β€” consensus, exactly-once delivery, partial failure, backpressure β€” are well understood even if they are never easy. LLM agent pipelines are new in the sense that the components are language models rather than databases or queues, but the structural problems are the same.

Engineers building in this space would do well to read the distributed systems literature. Not the AI-native frameworks (many of which abstract these concerns away in ways that will eventually bite you), but the primary sources: the original Dynamo paper, Designing Data-Intensive Applications, the writings on the actor model. The vocabulary is directly applicable.

Multi-agent AI is not a new kind of system. It is a distributed system with probabilistic, non-deterministic components. The faster that framing becomes standard, the more reliable these pipelines will become.

Build it like you would build anything that has to work in production β€” because eventually, it will have to.