← all posts
// agents · agents

Why agents fail in production (it's almost never the model)

Every agent demo works. That should make you suspicious.

You stand up a loop, hand it three tools, point it at a tidy task, and it does something that looks like magic on the first attempt. The room nods. Then it ships, real users arrive with their real mess, and a week later you're reading a 200-line transcript trying to work out how the thing rewrote the wrong file at step 14 and then spent the next sixteen steps building, with total conviction, on top of its own mistake.

I've watched this happen enough times that the failures have started to rhyme. And the one thing they almost never share is the model. "It's not smart enough" is the first diagnosis people reach for, and it's usually wrong. The model is the part you rented, and it mostly works. What breaks is everything around it: the scaffolding the demo never stressed because the demo never ran long enough, or weird enough, to expose it.

These are the ones I keep meeting.

The context turns into a landfill

A short task keeps a clean window. A long one doesn't. By turn thirty the context is stale tool output, abandoned sub-plans, and reasoning the agent moved past ten steps ago, all still sitting there, still being re-read every turn, still being billed, and quietly burying the three lines that actually matter right now.

So the agent gets worse as the session gets longer, which is precisely backwards from what you'd hope, and it happens with no error and no warning. The demo task finished in six turns and never hit this. The production task that runs for forty does. Most of what people call "the agent lost the plot" is really "the plot scrolled out of usable attention." Keeping the window lean (compaction, pruning stale results, isolating sub-work in subagents) is the unglamorous bulk of real agent architecture, and it's the first thing the demo lets you skip.

It retrieved the wrong thing and reasoned beautifully about it

This one is nasty because the transcript looks great. The agent's reasoning is articulate, step-by-step, defensible. It's also about the wrong files, because the retrieval step that fed it grabbed the plausible-but-irrelevant chunks and nobody checked. Garbage in, eloquent garbage out.

You can't tell from the answer that it happened. The model doesn't know its context is wrong; it works with what it was handed. If your retrieval is mediocre, a smarter model just gives you a more convincing wrong answer. The fix lives upstream of the model, in retrieval quality, and it's invisible until you go looking for which chunks actually got pulled.

There was no oracle, so "done" just meant "stopped"

Ask yourself a blunt question about any agent you've built: how does it know when it succeeded? If the honest answer is "it decides it's finished," what you've got is a very confident text generator with tools.

The agents that hold up have something outside the model to check against. Tests that pass or fail. A schema that validates or doesn't. A linter, a type checker, a script that exits non-zero. That external check is what turns the loop from guessing into engineering, because it gives the agent a reason to keep going when it's wrong and a reason to stop when it's right. Without it, the agent stops when it feels done, and "feels done" and "is correct" are different things that happen to coincide in demos. This is the same verification gate that makes a model cascade work, and the same reason tests are the agent's best friend.

You gave it a tool that could hurt you, and eventually it did

If an action is in the tool surface, it is in the sample space. An agent with an unrestricted shell will, on some unlucky input weeks from now, run the command you'd never run. Not because it's malicious. Because the space of things it can do includes the thing you didn't want, and it's rolling those dice thousands of times.

The blast radius is a design decision you make up front or regret later. Scope each tool to the minimum. Gate the irreversible stuff behind a human. Run the dangerous parts in a sandbox so the worst case is bounded by construction. The demo skipped this because the demo ran ten times on inputs you chose; production runs ten thousand times on inputs you didn't.

The happy path met the long tail

Your prompt was tuned on the cases you thought of. Users supply the cases you didn't. The empty input, the half-corrupt file, the request phrased so strangely it inverts your instruction, the document with injected text that says ignore your previous instructions. The agent that sailed through your test cases meets the distribution of real inputs and discovers most of them live in the part you never wrote for.

There's no clever fix here, only the boring one: feed it real, messy inputs early, watch where it breaks, and treat each break as a case to handle rather than a fluke to wave off.

You changed a prompt to fix one thing and broke three others

Without evals, every change to an agent is a bet you can't see the odds on. You tweak a prompt to stop one annoying behavior, ship it, and quietly regress three behaviors that were working, because prompts are global and the model's response to your edit rippled somewhere you weren't looking. You find out from users.

Twenty real tasks with known-good outcomes, run on every change, is the difference between improving the agent on purpose and changing it at random. It's tedious, and it's mandatory. Evals are the regression suite for a system that has no other way to tell forward from backward.

The bill exploded and nothing told you

One day the agent costs ten times what it did yesterday and the output looks identical. Usually a cache that stopped hitting: someone slipped a timestamp into the system prompt, or the tool list started varying, and the stable prefix that used to bill at a tenth of the rate now bills at full price every turn. Nothing errors. The agent works. The invoice is just wrong now, and it'll stay wrong until somebody notices the cache-read number went to zero. That's another way of saying: until you were watching it.

What the survivors do

The agents that make it to production and stay there run the same models as the ones that died. They're wrapped in more discipline instead, and it's the same short list every time.

They keep the context tight and treat the window as a scarce resource rather than a bucket. They obsess over retrieval, because they've internalized that the model is only as good as what it's handed. They give the agent an oracle and refuse to call anything "done" that wasn't checked. They scope tools to the task and put a human on the irreversible. They run a small eval set on every change so regressions can't hide. And they watch cost and cache the way an SRE watches latency, because a silent 10x is its own kind of outage.

None of that is exotic. That's rather the point. Agents fail in production because production punishes the corners the demo let you cut, not because it needs a frontier breakthrough. If you've got an agent that wows in a notebook and falls apart with users, resist the urge to swap in a bigger model. Go read a long, failed transcript instead, find the exact step where it went wrong, and you'll almost always find one of the boring failures above, and a boring fix waiting next to it.

#agents#architecture#production