Why AI Agents Break in Production (And How to Build Around It)
Brian Mutai
Full-Stack Engineer
The demo looks incredible. An agent receives a natural-language task, calls a series of tools, reasons through intermediate outputs, and returns a correct answer. Then you deploy it.
Two weeks later your on-call engineer gets paged at 3 AM.
Building agentic AI systems in 2025 and 2026 has taught teams everywhere the same uncomfortable lesson: the gap between a working demo and a reliable production system is not small. It is a chasm, and it is filled with specific, repeatable failure modes that most tutorials never mention.
The Illusion of the Happy Path
Most agent demos show the happy path: the model picks the right tool, the tool returns clean data, the model synthesizes a correct answer. Everything goes right in sequence.
Production is the unhappy path. Tools time out. APIs return malformed JSON. The model picks the wrong tool and confidently proceeds. A tool call succeeds, but returns data in a format that the next step cannot parse. None of these scenarios are unusual; they are the default.
The first design principle for production agents: assume every step fails some percentage of the time, and design for recovery, not success.
Context Exhaustion
Language models operate within a context window. As an agent loop runs, it accumulates: the original task, tool definitions, intermediate tool calls, intermediate results, and any reasoning the model emits. This compounds quickly.
For a typical agentic task requiring 12 to 15 tool calls, a mid-complexity chain can exhaust 64K tokens before completing. At 128K context, agents running nested sub-tasks hit limits faster than teams expect.
What happens when context fills depends on how your framework handles it. Some truncate silently. Some error loudly. Some truncate the wrong end and drop the original instructions, leaving the model operating on stale context with no memory of its original goal.
Mitigation patterns:
- Summarize intermediate results before they accumulate. After every three or four tool calls, emit a compressed summary that replaces the raw tool outputs in context.
- Use structured state instead of free-form context accumulation. Keep a separate data structure for working memory and inject it selectively per step.
- Set hard turn limits. If your agent has not finished in 20 tool calls, it probably needs a different approach, not 30 more.
Non-Determinism at Scale
A model that returns the correct answer 95% of the time sounds great. In production, at 10,000 invocations per day, a 5% failure rate means 500 daily failures. If those failures are silent (where the model returns an answer, just not the correct one), you have a harder problem than a system that simply errors.
Non-determinism compounds through tool chains. If step A has 95% accuracy and step B has 95% accuracy, a two-step chain is already at 90% accuracy. At five steps, you are at 77%. This is not a pathological scenario; it is arithmetic.
What this demands:
- Output validation at every step. Do not trust the model's output. Parse it, validate its shape, and check invariants before passing it downstream.
- Confidence signals. Some models support logprobs; use them. For others, asking the model to rate its own certainty (with appropriate prompting) is imperfect but useful as a trigger for human review.
- Human-in-the-loop checkpoints for high-stakes steps. For any action that mutates state (writes to a database, sends an email, charges a payment), require explicit confirmation before execution. The cost of a confirmation step is small; the cost of an incorrect irreversible action is not.
The Retry Storm Problem
When a tool call fails, the naive response is to retry. This is reasonable. What agents do, however, is retry with the same context and the same prompt, often in a tight loop.
If the failure is a rate limit or a transient network issue, this works fine. If the failure is semantic, meaning the tool returned something the model cannot parse, retrying produces the same failure indefinitely.
Worse, retry loops that call external APIs can trigger secondary rate limits. An agent retrying a failing tool call ten times in thirty seconds can cascade across multiple downstream systems simultaneously, turning a single agent failure into a platform-wide incident.
Better retry patterns:
- Distinguish recoverable failures (timeouts, 5xx errors) from unrecoverable ones (schema mismatches, invalid inputs, 4xx errors).
- Implement exponential backoff with jitter between retries.
- Set a maximum retry count per tool call, not per task.
- Log every retry with the full tool input and output. This data is the foundation of every useful post-mortem.
Tool Design Is Half the System
Most agentic failures trace back to poorly designed tools. A tool that returns inconsistent schemas, or that requires implicit knowledge about what constitutes a valid input, will cause the model to fail in unpredictable ways.
Good agent tools share properties with good API design:
- Idempotent where possible. The model will call the same tool twice if it forgets it already did. Design tools so a duplicate call is harmless.
- Explicit, structured error types. Return
{ "error": "NOT_FOUND", "resourceId": "abc" }rather than a raw exception string. The model can reason about structured errors far better than stack traces. - Narrow scope. A tool that does one thing is easier for a model to invoke correctly than a tool that does five things based on parameter combinations.
- Precondition checking. Validate inputs before execution and return informative errors early. This prevents half-applied mutations that are expensive to detect and reverse.
Observability Is Not Optional
You cannot debug an agent you cannot observe. This sounds obvious, but the tracing needs of agentic systems are significantly more complex than traditional service tracing.
A single user request can fan out into dozens of LLM calls, tool executions, and sub-agent invocations. The observability infrastructure you need:
- A trace ID that propagates through every step, every sub-agent call, every tool invocation. This is the single most important thing. Without it, post-mortem debugging is nearly impossible.
- Full capture of model inputs and outputs at every turn. Not summaries: the full prompt and response. Storage is cheap; being unable to reproduce a failure is not.
- Structured events for every tool call: tool name, input, output, duration, retry count, success or failure status.
- Latency histograms broken down by step. Agents can silently degrade from two-second responses to thirty-second responses when a downstream tool slows down.
The Failure Scenarios You Must Test
Most engineering teams test the happy path. For agents, the failure scenarios require equal investment:
Test: tool returns an empty result. What does the agent do when a search returns zero results? Does it conclude the answer is "nothing found," or does it enter a retry loop looking for data that does not exist?
Test: tool returns a malformed response. Inject a response that does not match the expected schema. Does your output validation catch it? Does the agent emit a meaningful error or silently produce a wrong answer?
Test: the agent exceeds the turn limit. For long-running tasks, ensure the turn limit fires and emits a structured failure, not an obscure timeout error.
Test: two tools return contradictory information. What does the agent do when tool A says a record exists and tool B says it does not? This should trigger a defined resolution strategy, not an undefined behavior.
A Practical Pre-Production Checklist
The engineering literature on agents focuses on capabilities. The operational reality demands equal investment in constraints.
Before any production deployment:
- Every tool has input validation and structured error returns.
- There is a hard turn limit; the agent cannot run forever.
- Context accumulation is bounded; intermediate results are summarized.
- All state mutations require pre-execution validation.
- Trace IDs propagate to every LLM call and tool invocation.
- There is a circuit breaker on external tool APIs.
- You have tested the failure scenarios, not just the happy path.
Agents are powerful. They are also systems, and systems fail according to the same laws of physics as every other distributed component. Respecting that is not pessimism. It is engineering.