The first time I tried to debug a non-deterministic agent in production, I reached for the same tools I had used for fifteen years: a stack trace, a debugger, and a hypothesis. I set a breakpoint on the LLM call, replayed the request, and watched the stack frame land on a single line — the `openai.ChatCompletion.create()` invocation — with no information about what had actually happened. The model returned a wrong tool call. The stack trace told me nothing. The breakpoint told me nothing. The request ID, when I grepped for it in the logs, was buried under 4,000 other request IDs from the same five-minute window, all of which had called the same model with slightly different prompts and gotten slightly different results.
That weekend I spent eight hours trying to reproduce the bug. I never did. The next morning the same agent made the right call, and I have no way to know why. This is the failure mode that the phrase post-mortem-the-flaky-LLM was invented to describe, and it is the reason the stack trace has reached the end of its useful life for AI systems. The traditional stack trace assumes four things that AI systems violate by design. Once you internalize what those four assumptions are, the new debugging paradigm — the prompt-trace-first paradigm — falls out naturally.
Why the stack trace died for AI
Traditional debugging was built on four assumptions, all of them baked into the format of the stack trace itself:
- Deterministic execution. The same input, with the same code, on the same machine, returns the same output. The stack trace captures a single execution path because there is only one execution path to capture.
- A single call site. When something goes wrong, you can point at a line. The bug lives in a function, the function lives at a line number, and the line number is stable across runs.
- Stable source. The code at the line number is the code you are debugging. You can attach a debugger, step through the lines, and see the state. The state is reproducible because the code is reproducible.
- Reproducible state. Given the same inputs and the same code, you can rebuild the exact execution state. That is what "can you reproduce it?" means.
AI systems violate all four. The same prompt returns a different completion on every call — the temperature parameter is a knob, not a bug, and turning it to zero only flattens the surface of the non-determinism (the model still samples differently for every sequence, even with greedy decoding, because of floating-point ordering on GPU kernels). An agent loop has five to fifteen call sites per request — prompt construction, tool selection, tool execution, result parsing, error recovery, retry logic, prompt re-construction — and the path through those call sites varies by run. The "source" is the prompt, which lives in a config file or a database, not in a `.py` file, and the prompt is versioned in a different system (LangSmith, Helicone, your own feature store) than the code. The only reproducible state for a non-deterministic model is the input plus a seed plus the exact model checkpoint, and even that varies across providers when they silently upgrade a model version overnight.
The stack trace is still useful for the LLM-serving layer. When vLLM crashes with a CUDA OOM, you want the Python traceback that tells you which tensor allocation failed. When your agent framework throws an exception because a tool call returned malformed JSON, you want the line that called the tool. But for the application layer — for the question every senior engineer actually asks at 2am, which is "why did the agent do that?" — the stack trace is structurally silent. It can show you the call site. It cannot show you the reasoning.
The 4 primitives that replace the stack trace
Four debug primitives have emerged in 2024-2026 as the building blocks of the new paradigm. None of them are about replacing the stack trace wholesale — the stack trace is still where you start, and then you step up the abstraction stack to the four primitives below. Tooling is converging on this taxonomy: LangSmith, Arize Phoenix, Helicone, Braintrust, Vellum, and the OpenLLMetry / OpenTelemetry gen_ai.* semantic conventions all implement some subset of these four.
Primitive 1: The prompt trace
The prompt trace is a first-class trace object that captures the full sequence of one request through the system: every prompt sent to the model, every completion received, every tool call dispatched, every side effect committed, and every cost incurred. It is to the LLM call what a distributed trace is to a microservices request: a single object that you can navigate, search, replay, and analyze. The OpenTelemetry gen_ai.* semantic conventions (now stable as of 2025) give you a vendor-neutral schema for this. A sample trace for a 3-turn agent conversation looks like this:
{
"trace_id": "0af7651916cd43dd8448eb211c80319c",
"name": "agent.run",
"start_time": "2026-06-13T14:23:01.412Z",
"duration_ms": 4712,
"spans": [
{
"name": "gen_ai.prompt",
"attributes": {
"gen_ai.system": "openai",
"gen_ai.request.model": "gpt-4o-2025-08",
"gen_ai.usage.input_tokens": 842,
"gen_ai.usage.output_tokens": 137
}
},
{
"name": "tool.call",
"attributes": {
"tool.name": "search_kb",
"tool.query": "refund policy enterprise",
"tool.result_count": 4
}
},
{
"name": "gen_ai.completion",
"attributes": {
"gen_ai.completion.text": "Based on the refund policy in your enterprise plan..."
}
}
]
}
The point is that this object is queryable, replayable, and analyzable in bulk. You can find every request where the tool call returned zero results. You can find every request where the model took more than two seconds to generate a completion. You can find every request where the cost exceeded a threshold. None of this requires reproducing the request — the trace is the reproduction. This is the layer that the existing pillar article on OpenTelemetry for AI inference covers in detail; this article treats it as the foundation and builds the workflow on top.
Primitive 2: The reasoning chain
The reasoning chain is the step-by-step record of what the model was thinking at each turn: the "thought" it generated (ReAct-style "Thought: I should call the search tool..."), the action it chose, the observation it received, and the next thought. For ReAct, Chain-of-Thought, and tool-using agents, this is where the silent failures live. 80% of agent failures, in my experience across the four agent systems I have operated in the last eighteen months, are silent reasoning failures — the model chose the wrong tool, the model hallucinated a fact, the model looped on a no-op tool, the model gave up after two retries when it should have tried a different approach. None of these failures show up in a stack trace. All of them show up in the reasoning chain, if you capture it.
The tooling here is converging: LangSmith's "reasoning" tab, Arize Phoenix's "chain" view, Helicone's "steps" panel, and the OpenLLMetry `gen_ai.completion.reasoning` attribute (still experimental as of mid-2026, but shipping in vLLM and LiteLLM nightly builds). The right way to think about the reasoning chain is that it is a sibling artifact to the prompt trace, captured at higher verbosity for the spans where the model is doing tool selection or planning. When a senior engineer asks "why did the agent do that?" the answer lives in the reasoning chain, not the prompt trace.
Primitive 3: The replay primitive
The replay primitive is the new "reproduce the bug." Given a captured prompt trace, replay it against the same model with the same seed and a single variable changed — a different prompt, a different temperature, a different tool definition, a different model version. The "diff" between the original output and the replay output is your debugging signal. The prompt trace is reproducible by definition; the model behind it is not, but if you replay against the same model checkpoint on the same day, you can isolate the variable that caused the failure.
The tooling for replay has matured significantly in 2025-2026. Promptfoo's replay mode (open source) lets you capture a trace, change a single variable, and re-run against the same model. Humanloop's replay (YC S21) wraps the same primitive in a UI with side-by-side comparison. Helicone's request replay captures the full trace including tool calls, replays it as a synthetic request, and shows you the cost and latency diff. LangSmith's dataset replay is the most feature-complete: it ties replay to a labeled dataset, lets you promote a replayed trace into the dataset, and runs the dataset as an eval. None of these existed in 2023. All of them are table stakes in 2026.
Primitive 4: The verification gate
The verification gate is the new unit test. For async agents that write to production data — agents that issue refunds, update CRMs, deploy infrastructure, send emails — the unit-test pattern of "run the test, see the red, fix the code" does not work. The action commits before the test runs. So the verification has to move inside the inner loop: every agent action is wrapped in a verifier (a schema check, a cost cap, a side-effect allow-list, a content safety filter) before the action is committed. The verifier is the assertion. If the verifier fires, the action is rolled back or blocked. If it does not, the action proceeds.
Tooling for verifier-first agent design is younger than the other three primitives, but it is moving fast. Vellum (workflow editor with built-in verifiers) and Braintrust (eval + verifier primitive) are the two I see most often in 2026 production systems. The YC F24 batch produced Relvy, which launched on Hacker News on 2026-04-09 (48 points, 25 comments) and treats the verifier as a first-class object with its own versioning and replay history. The pattern is converging: an agent action is not "fire and observe." It is "fire through a verifier, commit only if the verifier passes." The verifier primitive is what makes the other three primitives safe to use in production — without it, replay is a debugging tool that can fire a real refund.
The 5-step debugging workflow
These four primitives combine into a 5-step workflow that replaces the old "set a breakpoint, step through, hypothesize, fix" loop. The steps assume you have OTel gen_ai.* wired (covered in detail in the OpenTelemetry AI inference tracing article) and that the four primitives above are at least partially available in your stack.
- Capture the prompt trace. The first signal is always the trace. Find the failed request by query, user ID, or trace ID, and pull the full prompt trace. Do not try to reproduce the request from logs. The trace is the source of truth.
- Inspect the reasoning chain. Drill into the spans where the model was reasoning. The silent reasoning failure — wrong tool, hallucinated fact, premature exit — will be visible in the chain. This is the step that has no equivalent in traditional debugging. It is the new "read the stack frame."
- Replay with the single changed variable. Once you have a hypothesis (the model was confused by tool X, the prompt template Y was wrong, the temperature Z was too high), use the replay primitive to test it. Change one variable at a time. The diff between original and replay is your evidence.
- Add the verifier. Once you have identified the failure mode, wrap the action in a verifier that would have caught it. If the model chose the wrong tool, add a tool-selection verifier that checks the chosen tool against a policy. If the model hallucinated, add a grounding verifier. The verifier turns a debugging insight into a regression guard.
- Ship the eval. Take the original failing trace, add it to an eval dataset, and assert that the verifier fires on it. The eval is the test. The eval runs in CI. The eval runs against every prompt-template change, every model upgrade, every new tool. This is the equivalent of the regression test suite that the stack trace used to support.
Steps 1 and 2 are passive: they consume existing telemetry. Step 3 is interactive: it requires a hypothesis. Steps 4 and 5 are durable: they turn a one-time debugging insight into a permanent regression guard. The ratio of durable work to interactive work is the metric I use to judge whether a debugging process is healthy. If your team is spending all their time on step 3 and never getting to steps 4 and 5, you are debugging in a loop.
Tooling comparison: how LangSmith, Arize Phoenix, Helicone, Braintrust, and Vellum implement the 4 primitives
No single tool implements all four primitives well. The table below is from running the same 12-step agent task through each of the five tools in Q1 2026 and grading them on prompt-trace fidelity, reasoning-chain capture, replay support, verifier primitives, and eval integration.
| Tool | Prompt trace | Reasoning chain | Replay | Verifier | Eval |
|---|---|---|---|---|---|
| LangSmith | Strong (OTel-native) | Strong (LangGraph-aware) | Strong (dataset replay) | Weak (manual) | Strong (built-in) |
| Arize Phoenix | Strong (OTel-native) | Strong (chain view) | Medium (manual) | Medium (code-level) | Strong (datasets + LLM-as-judge) |
| Helicone | Strong (proxy-based) | Medium (steps panel) | Strong (request replay) | Weak (none) | Medium (user-defined) |
| Braintrust | Medium (custom) | Strong (span-level) | Medium (dataset) | Strong (built-in) | Strong (built-in) |
| Vellum | Medium (workflow) | Medium (step view) | Weak (manual) | Strong (first-class) | Strong (built-in) |
The pattern that emerges: trace tools (LangSmith, Arize Phoenix) win on primitives 1 and 2. gateway tools (Helicone) win on replay because they sit in the request path. workflow tools (Braintrust, Vellum) win on primitives 3 and 4 because they treat the agent as a testable artifact, not a stream of traces. Most production teams I talk to in 2026 are running two of these in parallel — a trace tool for primitives 1 and 2, a workflow tool for primitives 3 and 4 — and using the OpenTelemetry gen_ai.* conventions as the integration layer between them.
The 3 new debugging patterns
Beyond the workflow, three patterns are emerging as the new best practices for AI debugging in 2026. Each is a paradigm shift, not a tool, and each maps to a step in the workflow above.
Pattern 1: Trace-driven reasoning review
Code review used to mean reading the source. For agent code paths, code review increasingly means reading the trace. The reviewer pulls up the prompt trace for a representative run, walks the reasoning chain, and asks: did the model make the right decision at each step? Did it use the tool the way the prompt intended? Did it call the right tool at all? This is a different skill from code review, and it requires the reviewer to be fluent in the model's failure modes — not in Python.
The implication for engineering orgs is non-trivial. The senior engineer who was the best code reviewer on the team is not necessarily the best trace reviewer. The person who is best at trace review is the person who has seen the most agent failures and has the best mental model of "what does a model going wrong look like." That person may be a junior engineer who has been running evals for six months. Pair them. Treat trace review as a learnable skill, not a senior-engineer-only skill, and rotate the role.
Pattern 2: Replay-driven root cause analysis
The old RCA workflow was: reproduce the bug, isolate the variable, fix it, write a regression test. The new workflow, for AI systems, is: replay the bug, isolate the variable, fix it, ship a verifier. The verb changed from reproduce to replay, and the noun changed from test to verifier. A flaky LLM is not reproducible in the traditional sense. A captured prompt trace is reproducible by definition.
This pattern shows up most clearly in incident retrospectives. When a team writes an AI incident postmortem (covered separately in the LLM incident postmortem article and the AI incident postmortem template), the "reproduction steps" section is increasingly a link to a replayed trace, not a description of a manual repro procedure. The replay is the proof. The verifier is the prevention.
Pattern 3: Verifier-driven safe deployment
The old deployment pattern was: deploy, monitor, roll back if metrics go bad. The new pattern is: deploy behind a verifier, monitor the verifier, roll back if the verifier fires too often. The verifier sits between the agent and the side effect. It is the new "test in production." It is not a replacement for evals — evals run in CI, verifiers run in production. They serve different purposes: evals catch regressions before deploy, verifiers catch failures after deploy.
This pattern is the one I am most cautious about, because it is also the one that is most often over-applied. A verifier that fires on 30% of legitimate requests is worse than no verifier at all — it blocks the agent from doing its job. A verifier that fires on 0.1% of legitimate requests is the right shape. The verifier should be a tight, well-tested assertion on the action, not a vague "is this output OK" check. If you cannot write a verifier that is tight, the action should not be in the agent's tool set. Move it to a human-in-the-loop step.
How this fits the rest of the AI debugging stack
This article is the active-debugging piece in a four-piece cluster that covers the AI debugging workflow end-to-end. The cluster:
- Agentic Observability — the four-layer observability stack for agents (trace, cost, reliability, eval). What to instrument.
- OpenTelemetry for AI Inference — the gen_ai.* semantic conventions and how to wire them. How to instrument it.
- AI Agent Reliability 2026 — the four silent failure modes (silent loops, context overflow, tool call cascades, credential drift). How to detect them.
- LLM Incident Postmortem 2026 — the postmortem framework for non-deterministic failures. What to do after the failure.
- This article — Beyond the Stack Trace — the active debugging workflow. What to do during the failure.
The pieces are designed to be read in order if you are building a new AI debugging practice, or in any order if you are debugging a specific problem and need the relevant primitive. The companion piece for building the underlying observability stack is the LLM monitoring stack tutorial, which covers Prometheus + OpenTelemetry + Grafana as the substrate the four primitives run on.
What I still do not have a good answer for
A few open problems, in the interest of honesty:
Verifier maintenance is a real cost. Verifiers drift the same way models drift. A verifier that fires 0.1% of the time today may fire 3% of the time in six months because the model's output distribution has shifted and the verifier's threshold no longer matches reality. There is no equivalent of "re-run the test suite" for verifiers. The best pattern I have seen is to instrument the verifier with a daily "false positive rate" metric, and to set a CI check that the false positive rate has not moved more than 2x in 30 days. If it has, the verifier is stale and needs review.
Replay is not a substitute for a real test. Replay tells you "what would the model have done with this input and this variable changed." It does not tell you "is the model correct in general." For that, you need evals on labeled datasets, and the cost of building those datasets is the single biggest operational expense in an AI reliability practice. I have not seen a vendor that solves this end-to-end. Braintrust gets close. Vellum gets close. Neither is the answer.
Multi-agent reasoning chains are still hard to read. When a request goes through three sub-agents and each one generates a reasoning chain, the resulting trace is a tree of thought, and the tree does not fit cleanly into a "reasoning chain" UI. LangGraph's trace UI is the best I have seen, but "best I have seen" is a low bar. This is an open UI problem.
None of these are reasons to wait. The four primitives and the 5-step workflow are shipping in production at companies I have talked to in the last six months, and the teams running them are debugging in minutes what used to take days. The stack trace is not dead — it is just no longer the whole story.
Free Newsletter
Get one analysis like this every week
The Stack Pulse covers production AI incidents, FinOps playbooks, and infrastructure patterns — written for engineers who operate at scale.
Subscribe FreeTrace + reasoning + eval for LangGraph and LangChain agents
Open-source LLM observability with embedding-based drift detection