Why Agents Break in Production and Not in the Demo
An agent demo runs a path someone chose. The inputs are clean, the tools are up, the customer record exists, and the person driving knows which question to ask. Production is the opposite: inputs arrive from whoever happens to be typing, a third of the dependencies sit behind a network link that flaps, and the interesting cases are precisely the ones nobody scripted. Gartner's June 2025 press release put a number on the consequence — over 40% of agentic AI projects will be canceled by the end of 2027, citing escalating costs, unclear business value and inadequate risk controls, based on a poll of over 3,400 respondents. Those projects are not failing because the models cannot reason. They fail because nobody built the operational layer underneath them.
The same firm expects 40% of enterprise applications to feature task-specific AI agents by the end of 2026, up from less than 5% in 2025. Both statements are compatible, and together they describe the next two years accurately: many teams will ship agents, and a large share of those deployments will quietly be switched off. The difference between the two groups is rarely the model or the framework. It is whether the team treated the agent as a distributed system with a non-deterministic component in the middle, or as a prompt with some tools attached. The first framing produces budgets, traces and kill switches. The second produces a four-figure invoice and an incident nobody can reproduce.
This article assumes you already know what an agent is; if you do not, start with the explainer, and if you are still deciding how many agents to run and how they should talk to each other, the multi-agent patterns piece covers the topology question. What follows is narrower and less pleasant: the specific ways agentic workflows break once real traffic hits them, roughly in the order they tend to appear, and the control that contains each one. None of it is theoretical. Every failure mode below is something that shows up inside the first eight weeks of a live deployment, usually on a weekend.
Unbounded Loops, Retry Storms and the Bill They Generate
The most expensive agent bug is not a wrong answer. It is a loop. The shape is almost always identical: the agent calls a tool, the tool fails in a way that does not raise — an HTTP 200 with an error object in the body, an empty result set, a timeout the wrapper swallows and returns as an empty string. The model reads that as data, concludes its query must have been slightly wrong, adjusts one argument and calls again. Nothing in the stack has raised an exception, so nothing backs off and nothing pages anyone. The agent is doing exactly what it was instructed to do, which is to keep working until it has an answer.
The cost profile is what makes this dangerous rather than merely annoying. A workflow designed around six to ten tool calls typically consumes something in the range of 30,000 to 80,000 tokens per run, because every step re-sends the accumulated transcript. A loop that reaches sixty steps does not cost six times more; it costs closer to twenty or thirty times more, because the context grows with each turn and each turn pays for the whole thing again. Put that behind a queue processing a few thousand jobs overnight and the arithmetic stops being academic. A single misconfigured retry path can turn an expected daily inference spend into something ten to forty times larger before anyone opens a dashboard in the morning.
Detection is the second half of the problem. Provider billing dashboards update on a lag measured in hours, not seconds, so the bill is not your alarm. The signal you actually hold in real time is your own step counter and your own token accounting, which means you have to be counting. Teams that discover the problem when finance asks about an invoice are teams that never instrumented per-run cost. The metric worth alerting on is not total spend, which moves too slowly; it is the distribution of steps per run. A workflow whose median is seven steps and whose 99th percentile has crept to fifty is telling you something days before the money does.
The controls are unglamorous and they work. Set a hard ceiling on steps per run and terminate at it rather than warning. Attach a token budget and a currency budget to every run and enforce both in the runtime, not in the system prompt, because a model cannot be relied on to enforce a limit against its own sense of the task. Add a loop detector that fires when the same tool is called with near-identical arguments more than three or four times in a row. Wrap external calls in a circuit breaker so a flapping dependency takes the workflow down cleanly instead of grinding through it at full price.
Non-Determinism and the Incident You Cannot Reproduce
Setting temperature to zero does not make an agent deterministic, and believing otherwise is why so many agent incidents die in triage. Provider-side inference is not bit-reproducible across hardware generations and batch composition. Retrieved documents change as the index is rebuilt. Tool responses reflect a database that has moved on. The model behind a floating alias can be swapped without your involvement. Replaying the same user input a day later produces a different run, which means the classic debugging move — reproduce it locally, then bisect — is simply unavailable. If you did not capture the run while it was happening, the run is gone and the incident review will be speculation.
That makes tracing a hard requirement rather than a maturity level you graduate to. A usable trace records, for every step: the system prompt version, the full message list exactly as sent, the tool name, the exact arguments, the raw response before any parsing, token counts in and out, latency, and the resolved model version string rather than the alias. Without the arguments you cannot tell whether the model asked the wrong question or the tool answered it wrongly. Without the raw response you cannot tell whether a parser silently dropped a field. Our working rule is that if an engineer cannot reconstruct the exact bytes the model saw at step four, the trace is not finished. The surrounding practice is covered in observability and evaluation.
Tracing at that fidelity collides with data protection, and you should resolve the collision deliberately rather than by accident. Full traces contain whatever the user typed, which in a Turkish enterprise setting routinely includes identity numbers, contract text, salary data and occasionally health information. Decide the retention window before you switch tracing on — thirty to ninety days covers almost all of the debugging value — and apply field-level redaction on the way in rather than hoping to clean the store afterwards. Keep traces in the same jurisdiction as the underlying records. A trace store is a personal data store, and under Law No. 6698 it carries the same article 12 security obligations as any other system holding that data.
The Tool Error the Agent Papers Over
The failure mode that costs credibility rather than money is the tool error the agent hides. A tool returns a 503, the wrapper converts it into the string 'could not retrieve customer record', the model receives that as ordinary context, and instead of stopping it produces a summary beginning 'based on the available information, the customer appears to be'. The output is fluent, structurally correct and wrong. Nobody is paged, because from the runtime's point of view the workflow completed successfully. An operator reads a confident paragraph and acts on it. This is worse than a crash: a crash tells you the truth immediately, while a papered-over tool error tells you a lie that survives review.
The root cause sits at the tool boundary almost every time. When every tool returns a string, the model has no way to distinguish 'here is your data' from 'this system is down'. Both are just text in the transcript, and the model's job is to make text into a plausible continuation. Tool contracts therefore need structure: a status, a typed error code, and a payload that is either present or absent, so the runtime can branch on failure before the model ever sees it. This is one of the practical arguments for a standardised tool layer. MCP does not solve error semantics for you, but it pushes you toward declaring a schema rather than inventing one per tool.
The policy layer matters as much as the type layer. Decide, per tool, what failure means: some errors should be retried with backoff, some should be surfaced to the model as an explicit instruction to stop and report, and some should abort the run outright. A pricing lookup that fails must never be allowed to degrade into an estimate. Add assertions on the way out as well. If the workflow is supposed to have consulted the ledger and the trace contains no successful ledger call, the run is invalid regardless of how good the prose looks. These output assertions cost an afternoon to write and catch a surprising share of hidden failures before a human ever sees them.
Permission Scope Creep and Blast Radius
Almost every agent starts read-only, and almost none stays read-only. The pattern is predictable: the pilot summarises tickets, someone observes that it could also update the ticket status, and a write scope is added to the existing service account because that account already works and adding a second one is a ticket to the platform team. Six weeks later the same credential can write to four systems, and the summariser has authority no individual employee holds. Nobody made that decision in a single sitting; it accumulated one convenience at a time. The right moment to draw the permission boundary is before the first write tool, because afterwards the boundary is a migration rather than a design choice.
Blast radius is the number to reason about, and it is straightforward to compute: for each tool the agent can call, take the worst outcome of one bad call and multiply it by how many times the agent could make that call before anything stops it. An agent with an unrestricted write credential and a step budget of fifty can modify fifty records. If the write tool happens to be a bulk endpoint, it can modify fifty thousand. Rate limits on write tools are therefore not a performance control but a containment control, and they belong on the tool itself rather than in the prompt. The same reasoning applies to deletes, outbound communication and anything that spends money.
Scope creep is also the mechanism that turns an injected instruction into a real incident. An agent that reads untrusted content — an inbound email, a supplier PDF, a scraped web page — is reading text that may have been written specifically to redirect it, and every additional write permission increases the payoff of that attack. Treat retrieved content as hostile input rather than as instructions, scope credentials per tool rather than per agent, and put high-value tools behind a separate approval path so that a successful injection still cannot complete the action alone. The mechanics of that threat, and the defences that actually hold up, are covered in prompt injection and AI security.
Partial Failure, Missing Transactions and Compounding Latency
Agent workflows perform sequences of side effects with no transaction around them. Step three sends an email, step four writes to the CRM, step five calls a payment endpoint, and step six fails. There is no two-phase commit spanning a mail server, a SaaS API and a ledger, so the run ends in a state no designer ever described: a customer who has been told something the system does not record. Traditional distributed software handles this with sagas and compensating actions, and agents need the same discipline, with the extra complication that the sequence itself was chosen at runtime by a model rather than written down in advance by an engineer who could reason about ordering.
So classify the tools before you wire any of them up. Reversible actions — a draft, a staged record, a held reservation — can be executed freely and undone without anyone noticing. Compensable actions need an explicit inverse that is implemented and tested, and the runtime must invoke it on failure rather than leaving cleanup to the model's judgement. Irreversible actions, chiefly outbound communication and money movement, should be ordered last wherever the workflow allows, so a failure at step six has nothing left to undo. This ordering constraint is one of the few places where we deliberately reduce the agent's freedom: the model may choose what to do, but the runtime decides when the irreversible parts are permitted to run.
State is the quieter problem. Conversation memory grows, scratchpads accumulate, retrieved documents pile up in context, and cost and quality move in the wrong direction simultaneously. Past a certain transcript length the model begins to lose earlier constraints, which surfaces as an agent that forgets a rule it was following correctly ten steps ago. Summarise aggressively at fixed checkpoints, keep durable facts in a structured store rather than in the transcript, and treat the bağlam penceresi as a working set to be managed rather than a log to be appended to. A long-running agent with an unmanaged transcript degrades on a schedule you can almost predict in advance.
Latency compounds in a way that single-call systems never taught anyone to expect. If each model call takes two to six seconds and each tool call adds another two hundred milliseconds to two seconds, an eight-step workflow lands somewhere between twenty and sixty seconds on a good run. Add one retry and one slow dependency and the 99th percentile is measured in minutes. Users do not wait, so either the workflow becomes asynchronous with a real progress channel, or the step count comes down. In practice the answer is usually both: collapse steps by giving the model better tools rather than more turns, and stop putting a multi-step agent behind a synchronous request.
Silent Degradation After a Model Upgrade
The most under-instrumented risk in a production agent is the model changing underneath it. A provider retires a snapshot, you move to the successor, and nothing throws. The new model is better on most public benchmarks and slightly different on yours: it formats a field differently, becomes more cautious and starts declining a category of request it used to handle, or stops emitting a key your parser treats as optional. Your error rate does not move at all. Your quality does. Weeks later someone notices that a downstream team has been quietly correcting the output by hand, and by then you have no baseline left to compare against.
The only detection that works is a regression suite you run before the switch rather than after it. Build a golden set of one hundred to three hundred real traces spanning your actual input distribution, deliberately including the awkward and ambiguous ones, with the expected outcome recorded per step and not only at the end. Per-step evaluation matters because an agent can reach the right final answer through a wrong path, and a path that happens to work today is an incident tomorrow. Run the suite against the candidate model, compare step-level pass rates, and treat a regression on any high-cost step as blocking. This is ordinary release engineering; the only novelty is that the artefact under test is probabilistic.
Operationally, three habits remove most of the surprise. Pin the resolved model version explicitly instead of pointing at a floating alias, so an upgrade becomes a deployment you chose rather than something that happens to you on a Tuesday. Canary the new version on a small share of traffic and compare step-level metrics before a full cut. And where the workload genuinely cannot tolerate an uncontrolled model change, that constraint becomes an architecture decision rather than a preference; the trade-offs of running the model yourself are set out in on-prem and sovereign deployment. Control over when your model changes is a legitimate requirement, and it carries a real price.
Designing Human Approval So It Is Not Theatre
Human approval is the control everyone reaches for first and designs worst. The useful question is not whether a human should review this, but which actions are reversible. Sort every tool into three buckets and design from there. Reversible actions need no gate at all; a human reviewing a draft that nobody will send is pure cost with a compliance smell. Compensable actions need a gate only when the compensation is expensive or visible to a customer. Irreversible actions — sending, paying, deleting, filing with an authority — need approve-before-act without exception. Most teams gate the wrong set, typically by gating everything at launch and then quietly removing gates once the queue becomes unmanageable.
Approval fatigue is a measurable failure, not a personality flaw. If reviewers approve ninety-five percent of what they see, they have stopped reading, and the control has become theatre with an audit trail attached. Track approval rate and median time-to-decision as first-class metrics alongside latency and cost. An approval that takes three seconds is a rubber stamp and should be reported as one. The fix is to reduce volume rather than to exhort people: raise the confidence threshold that triggers review, gate only irreversible actions, and batch low-risk items into a periodic digest instead of an interrupt. A queue a reviewer clears in ten minutes a day with genuine attention beats a hundred approvals a day at two seconds each.
The interface decides whether review is real. Show the reviewer the effect, not the reasoning: the exact record that will change, the before and after values, the recipient and the literal text that will be sent. A rendered chain of thought is not evidence, and reading one is how reviewers talk themselves into approving a wrong action, because a confident explanation is easier to follow than a diff. Give every pending approval a deadline and a default that fails closed rather than open. Log the rejections too, because a tool whose proposals are rejected a fifth of the time is a tool that is not ready for autonomy, and that rate is the cleanest signal you will get.
The Control Set That Actually Holds
Budgets come first, and they are enforced in the runtime. Every run receives a maximum step count, a maximum token spend, a wall-clock deadline and a currency ceiling, and hitting any one of them terminates the run and records which limit fired. Writing the limit into the system prompt does not count as a control; a model asked to respect a budget will occasionally decide the task is important enough to continue. Budgets should exist per run and per tenant, so one pathological workload cannot exhaust the quota for everyone else. And a terminated run must land somewhere a human actually looks, rather than disappearing, because a run that hits its ceiling is a bug report in disguise.
Idempotency keys and dead-letter queues are the second layer, and they come straight out of ordinary distributed systems practice. Every side-effecting tool call carries a key derived from the run identifier and the step index, so a retry after a timeout updates the same record instead of creating a second one. Without this, the first network blip becomes duplicate invoices and a reconciliation project. Runs that fail terminally go to a dead-letter queue with their full trace attached rather than being retried into the same wall, and a named person owns that queue with a review cadence. A dead-letter queue nobody reads is just a slower way of losing the same information.
Then evaluation and tracing, which have already been argued for, and kill switches, which have not. You need three levels of stop: disable one tool, disable one workflow, and halt all agent execution across the estate. Each must be operable by whoever is on call, without a deployment, and each must be exercised in a drill rather than discovered during an incident. The question to answer before launch is simple: who can stop this system at three in the morning, and how many minutes does it take them. If the honest answer involves a pull request and a build pipeline, you do not have a kill switch, you have an intention.
Finally, staged autonomy, which is the control that makes all the others affordable. An agent earns permissions by track record instead of receiving them at launch because the business case assumed them. In stage one it runs in shadow and its proposals are logged and scored against what the human actually did. In stage two it suggests and a human executes. In stage three it acts autonomously on reversible tools and asks before irreversible ones. In stage four it acts within explicit limits with sampled review. Movement between stages is a decision backed by numbers from the previous stage, and it runs backwards as readily as forwards when a metric degrades.
How We Build and Run Agents
When we build agentic workflows at HatsonTech, we start with the tool layer rather than the prompt, and the ordering is deliberate. Before any model is involved we define each tool's schema, its typed error codes, its idempotency semantics, and whether it is reversible, compensable or irreversible. That document usually runs two or three pages and it determines most of the system's behaviour under stress, long before prompt wording matters. Teams that start from the prompt end up discovering these properties during an incident instead. We would much rather argue about whether the invoice endpoint is idempotent in week one than at two in the morning in week nine.
We also instrument before we scale. Full traces, per-run cost accounting and a step-count distribution go in before the workflow leaves a single team, because retrofitting them onto a live system is both harder and less useful — by then you have lost the baseline you needed to compare against. On the governance side, KVKK published guidance titled 'Etken Yapay Zekâ (Agentic AI)' on 12 March 2026. It is guidance rather than binding regulation, but it is a reasonable checklist for the questions a Turkish veri sorumlusu will be asked about an autonomous system, particularly around informing data subjects and maintaining meaningful human oversight of automated decisions.
Most of the agent work we do is not model work at all. It is custom software engineering around a probabilistic component: queues, idempotency, scoped credentials, traces, approval interfaces and the unglamorous reliability layer that decides whether the thing survives contact with a real workload. We are also willing to say when an agent is the wrong shape for a problem, and for a large share of the workflows we are asked about, a deterministic pipeline with a single model call in the middle is cheaper, faster and far easier to defend in an audit. Agents earn their complexity only when the path genuinely cannot be written down in advance.