Service 06

Agent observability, so a run can be explained months later

An agent that cannot be replayed is an agent nobody can defend. This is what to record, how to store it, and how to reconstruct a decision taken six months ago.

On this page
  1. What agent observability is
  2. Who it is for, and who it is not for
  3. The replay grades
  4. What we actually build
  5. How it works technically
  6. The build process, stage by stage
  7. What you get at handover
  8. Where these projects go wrong
  9. What it costs to run once live
  10. How to tell whether you need this
  11. How to start

What agent observability is

The short answer

Agent observability is the recording, storage and replay of everything an agent saw, decided and did on a given run, together with the exact configuration it was running under, so the run can be reconstructed and explained after the fact. It differs from ordinary application monitoring because an agent run can return a status of success and still be wrong, which means the useful signal is the decision rather than the response code.

Four questions have to be answerable from a trace alone: what did the agent see, what did it decide, what did it do, and what was it at the time. The fourth is the one teams leave out, and it is the one that ruins the other three. A trace without the prompt version, the model version and the threshold values is an anecdote, because you cannot tell whether the behaviour you are looking at still exists.

This is unglamorous infrastructure that becomes the most important thing you own during an incident. What to log so future you can debug it covers the field-level detail; this page covers the design and the trade-offs.

Terms used precisely on this page
Trace
The complete record of one agent run, from trigger to terminal state, structured as a tree of spans that share a trace identifier.
Span
One unit of work inside a run, with a start time, an end time, inputs, outputs and a parent. A model call, a tool call and a decision are each a span.
Replay
Re-executing a recorded run offline against its recorded tool responses and pinned configuration, to produce the same trace again without touching production.
Reason code
A label drawn from a closed vocabulary that the agent attaches to each decision. Reason codes make traces countable, where free text only makes them readable.
Config snapshot
The prompt template identifiers and versions, model alias and pinned version, temperature, tool registry version and threshold values in force for a run.
  • Four questionsWhat it saw, what it decided, what it did, what it was. A trace that cannot answer all four cannot be interpreted later.
  • Grade 3Deterministic replay, which is the target for every step that writes to a system of record.
  • 2 to 6 weeksOur window to retrofit observability onto an agent already running in production.
  • Never sample failuresSuccesses can be sampled, failures and writes are captured in full. Uniform sampling throws away the runs you built this for.
  • Redact at write timePersonal data is masked before a span leaves the process, because masking later means it was already stored.

Who it is for, and who it is not for

This is for agents that take actions with consequences, and for teams who have already had the conversation that starts with somebody asking why the system did something last Tuesday. It is premature for a prototype that does not yet work, where the money is better spent on an evaluation set.

Your situationWhat it meansWhat we would do
The agent writes to a system of recordEvery write may need explaining to somebody who was not thereDeterministic replay on the whole write path
The agent drafts text a human sendsThe human is the control, so the trace is for improvement rather than defenceFull capture on failures, sampled capture on the rest
An auditor or regulator may askThe evidence requirement is legal, not technicalAgree retention, redaction and access with counsel before capture starts
A reported bug cannot be reproducedYou are at grade 0 or 1 and debugging is guessworkThis is the highest-value retrofit available, start here
Pre-launch, one prototype, no usersThere is nothing yet to explainBuild the evaluation set first, see evaluation and guardrails
Traces exist and nobody reads themA review surface problem, not a capture problemBuild the reason-code rollup and attach it to a weekly ritual
High volume, low consequence per runFull capture will dominate the running costSample successes hard, keep every failure and every write
Observability scope, decided by consequence rather than by agent count.
A trace store is a data protection surface

The moment you record everything the model saw, you have copied customer data into a second system with different access controls, a different retention policy and a different backup regime. Decide redaction and retention before the first span is written. Retrofitting redaction means the unredacted copies already exist, in backups you cannot selectively edit.

The replay grades

Observability is not a switch, it is a ladder, and different parts of the same agent belong on different rungs. Grading each path honestly stops the two common outcomes: capturing far too little on the paths that matter, and capturing far too much on the paths that do not.

Framework

The ChatGPTalker Replay Grades

Five grades, from having an output to being able to ask what would have happened. Grade each path in your agent separately, then decide where you actually need to be.

01
Grade 0, output only

You have the final answer and nothing else. Debugging means asking the user what they typed and hoping they remember. Almost every agent starts here, and it is survivable only while nobody is depending on the output.

02
Grade 1, step log

You know which tools were called in what order, with timestamps and statuses. You can see the shape of a run and spot the step that hung. You cannot see what was passed or returned, so you can see that it went wrong without seeing why.

03
Grade 2, full capture

Every prompt, tool argument, response and decision stored against the trace. You can read exactly what happened. You still cannot rerun it, so a fix is verified by pushing it to production and waiting, which is the slowest possible feedback loop.

04
Grade 3, deterministic replay

The run can be re-executed offline against recorded tool responses, with the prompt version, model version, temperature and tool registry pinned. The same inputs produce the same trace. This is the rung at which regression testing becomes possible at all, and it is the target for any path that writes.

05
Grade 4, counterfactual replay

You can change one variable, a prompt revision, a model version, a threshold, a tool response, and rerun the recorded inputs to see what would have happened instead. This turns an incident into a measurement. It costs real engineering, so put it on the two or three decisions with the highest consequence rather than everywhere.

The sensible default is grade 3 on everything that writes, grade 2 on everything else, and grade 4 on a shortlist you can name in one sentence. Teams that try to reach grade 4 across a whole agent usually stall somewhere around grade 1 with a large unfinished framework, which is worse than grade 2 with a boring one that works.

What we actually build

Five components. The first one decides whether the other four have anything to work with.

The span emitter

A thin wrapper around the model client and the tool registry, so every call is recorded without a developer choosing to record it. Instrumentation that depends on people remembering produces partial coverage, and during an incident the span you need is reliably the one nobody wrapped. Wrapping the client rather than the call sites is the whole trick, and it usually takes two days.

The trace store

Append-only, keyed by trace identifier, with field-level redaction applied on the way in and tiered retention on the way through. Payloads above a size threshold go to object storage with a reference left in the span, because storing a 60,000 token context inline in a queryable index is how observability bills get frightening.

The replay harness

Takes a trace identifier and re-executes the run offline against the recorded tool responses under the recorded configuration. Two uses: reconstructing an incident, and running the regression suite. A harness nobody exercises does not work, so we schedule an automatic replay of a random production trace and fail the build when the result diverges.

The review surface

Not log search. A run view showing the decision tree, the reason code and confidence at each decision, the retrieved context, and where a human later disagreed. Filters by reason code and outcome, because the useful question is almost never about one run. It is about which of eleven reason codes accounts for most of last week.

The rollups and alarms

Reason code distribution, confidence distribution, tool error rates, cost per run by step, and drift alarms that fire when a distribution shifts rather than when a request errors. Silent degradation is the characteristic agent failure, and nothing in ordinary uptime monitoring will catch it. Monitoring an AI system in production goes deeper on the alarm design.

How it works technically

One trace per run, a tree of spans underneath it, and a configuration snapshot stamped at the top. Eight things happen.

  1. The run starts. The orchestrator issues a trace identifier and stamps the config snapshot: prompt template identifiers and versions, model alias and pinned version, temperature, tool registry version, threshold values.
  2. Each model call opens a span carrying the rendered prompt hash, token counts, and the prompt itself where the redaction policy allows, or a redacted copy where it does not.
  3. Each tool call opens a child span with its arguments, the response, the latency and the attempt number, so a retry storm is visible as a shape rather than inferred from a bill.
  4. Each decision opens a span with the choice, the confidence, the threshold that applied, and a reason code from a closed vocabulary. The free-text explanation is stored beside the code, never instead of it.
  5. Writes carry the idempotency key and the confirmation read, so the trace records what actually landed rather than what was attempted.
  6. Redaction runs in-process. Named personal fields are hashed or masked before the span leaves the application, which means the unredacted values never reach the store or its backups.
  7. Spans append to the trace store. Payloads above the size threshold are written to object storage and referenced by pointer.
  8. The run closes with a terminal status, a reason code, and the replay grade achieved, so you know at a glance what you can and cannot reconstruct from it.
  • One span shape, used everywhere, is worth more than a rich schema per component.
  • Reason codes are versioned alongside the prompts, because adding one silently breaks last month's rollup.
  • Every span carries the trace identifier, so a support ticket quoting one identifier is enough to reconstruct everything.
One decision span, completejson
{
  "trace_id": "run_20260826_a41f9c",
  "span_id": "sp_07",
  "parent_span_id": "sp_03",
  "name": "decision.route_refund",
  "kind": "decision",
  "started_at": "2026-08-26T09:14:02.118Z",
  "ended_at": "2026-08-26T09:14:03.902Z",

  "config": {
    "agent": "refunds-triage",
    "agent_version": "4.2.1",
    "prompt_template_id": "refund_triage",
    "prompt_template_version": 11,
    "rendered_prompt_sha256": "3f9c...a71b",
    "model_alias": "triage-primary",
    "model_version_pinned": "vendor-model-2026-06-01",
    "temperature": 0,
    "tool_registry_version": 19,
    "thresholds": { "auto_approve": 0.92, "escalate": 0.55 }
  },

  "saw": {
    "input_ref": "blob://traces/run_20260826_a41f9c/sp_07/input.json",
    "retrieved_doc_ids": ["policy-refunds-v6#s3", "order-88213"],
    "context_tokens": 5812,
    "redacted_fields": ["customer.email", "customer.card_last4"]
  },

  "decided": {
    "choice": "escalate_to_human",
    "confidence": 0.61,
    "threshold_applied": 0.92,
    "reason_code": "policy_ambiguous_partial_shipment",
    "reason_text": "order shipped in two parts, policy covers full shipments only",
    "alternatives_considered": ["auto_approve", "reject"]
  },

  "did": {
    "writes": [],
    "queue": "refunds_review",
    "idempotency_key": "run_20260826_a41f9c:sp_07",
    "confirmation_read": null
  },

  "cost": {
    "input_tokens": 5812,
    "cached_input_tokens": 4900,
    "output_tokens": 214,
    "price_book_ref": "pricebook/2026-08"
  },

  "attempt": { "n": 1, "of": 3, "previous_error": null },
  "error": null,
  "replay": { "tool_responses_recorded": true, "deterministic": true, "grade": "G3" }
}

The config block is the part people cut and the part that makes the rest usable. Without prompt_template_version and model_version_pinned, a trace from six weeks ago cannot tell you whether the behaviour you are staring at still exists, because somebody edited a template in between and nothing recorded it. The alternatives_considered field costs almost nothing and answers the question everybody asks second, which is what else it nearly did.

The build process, stage by stage

  1. Write down the questionsWeek 1

    Five questions the trace must answer and the person who asks each one. Ours usually start as: what did it decide and why, what did it see, what did it change, what did it cost, and who could have stopped it. Everything about the schema follows from this list, and skipping it produces a store full of data that answers nothing.

  2. Redaction and retention policyWeek 1

    Which fields are masked, which are hashed, which are kept whole, how long each tier lives, and who can read the store. Agreed with whoever owns data protection before capture starts, because this is far harder to change after the first month of traces exists.

  3. Instrument the spineWeek 1 to 2

    Wrap the model client and tool registry so every call emits a span automatically. Add the config snapshot at run start. This is the stage that produces coverage, and coverage is the property that matters most when something goes wrong at an inconvenient hour.

  4. Agree the reason code vocabularyWeek 2

    A closed list, deliberately short, named by people who understand the domain rather than by the engineer nearest the keyboard. Ten to twenty codes covers most agents. The moment reason codes exist, traces become countable and the weekly review has an agenda.

  5. Trace store and tieringWeek 2 to 3

    Append-only store, size threshold for payload offloading, hot and warm and cold tiers, and a deletion job that genuinely runs. A retention policy nobody enforces is worse than no policy, because it is a promise you are quietly breaking.

  6. Replay harnessWeek 3 to 4

    Recorded tool responses, pinned configuration, offline execution, trace comparison. Then the scheduled replay of a random production trace, wired into the build, so the harness is exercised weekly rather than discovered to be broken during the incident it was built for.

  7. Review surface and rollupsWeek 4 to 5

    The run view, the filters, the reason code distribution, the cost per run by step, and the drift alarms. Reviewed with the team that will use it, because a surface built without them becomes a dashboard nobody opens.

  8. Backfill the evaluation setWeek 5

    Traces where a human overrode the agent are the most valuable labelled data you will ever get, and they are free. Pull them into a regression set and the observability build has paid for a large part of the next quality improvement.

Retrofits onto a running agent land at the shorter end of that range when the tool layer is already centralised, and at the longer end when every tool call was written by hand in a different style. The instrumentation work is proportional to how disciplined the original build was, which is usually the first honest thing we can tell a client.

What you get at handover

Everything below sits in your repositories and your cloud accounts. Nothing in the pack depends on us being reachable.

The handover pack
0 of 10 done
The weekly ritual is part of the deliverable

A trace store with no obligation attached to it decays into storage cost. We hand over a fifteen minute weekly review with three fixed questions: which reason code grew, which decisions did humans overturn, and what did cost per run do. Teams that keep that meeting keep the system healthy. Teams that skip it are back at grade 1 within a quarter, with a large bill.

Where these projects go wrong

Six patterns, and five of them are decisions rather than bugs.

Instrumentation was left to individual developers

Voluntary logging produces coverage that looks fine in review and fails in production, because the path that breaks is the one written in a hurry by somebody who has since moved teams. Wrap the client and the tool registry so a call cannot happen without a span. Coverage is a property of the architecture, never of anybody's diligence.

The prompt version was never recorded

You have three months of traces and no way to tell which prompt produced any of them, because templates were edited in place. Every conclusion drawn from that archive is unsafe. Pin the template identifier, the version and a hash of the rendered prompt on every span, and treat every prompt edit as a versioned change with an identifier, the same way you would treat a schema migration.

Everything was captured, including what you cannot keep

Full fidelity capture of customer messages, identity documents and payment details into a store with looser access control than the source system. This is not a bug, it is a disclosure waiting for an audit to find it. Decide the redaction list first, apply it in-process, and accept that a few debugging sessions will be harder as a result.

Reasons were free text instead of codes

Ask a model to explain itself and it writes prose, which reads well and cannot be counted. Two hundred runs of prose is not a report. Constrain the reason to a closed vocabulary and keep the prose in a second field. The distribution of reason codes is the single most useful artifact the whole system produces.

Sampling was applied uniformly

A flat sampling rate of one in twenty sounds prudent and means you keep one in twenty failures, which are the runs the system exists to explain. Sample successes aggressively, capture every failure, every escalation and every write in full. The cost difference is small because failures are the minority, which is exactly why uniform sampling looks affordable and is not.

The replay harness was never exercised

It was built, it worked once, and then tool responses changed shape, a recording format drifted, and nobody noticed for four months. During the incident it fails, and by then the trace you wanted has aged out of the hot tier. Replay a random production trace on a schedule, compare against the original, and fail the build on divergence. How agents fail covers the failure shapes this catches.

The dashboard nobody opens is the default outcome

Most observability builds succeed technically and fail organisationally. The traces are there, the rollups are correct, and no one has an obligation to look. Attach the review to a named person, a fixed time and three questions with answers that get written down. Without that, the first anyone knows about a degraded agent is a customer explaining it to them.

What it costs to run once live

Two running costs: storing traces, and reviewing them. Storage is arithmetic on your own volumes and it is usually smaller than people fear once payloads are offloaded and tiers are configured. Automated review, where a second model scores a sample of traces, is the line that grows quietly, because it scales with volume rather than with incidents.

Trace storage and review cost estimator

Use your own volumes and your provider's current storage and model prices. Span size is the average across a run, including offloaded payloads.

0Spans written per month
0GB held at full retention
0Storage cost per month
0Automated review cost per month

Work the defaults once. Two thousand runs a day at fourteen spans is 28,000 spans a day, 840,000 a month. At 8 KB each and 180 days retention that is roughly 38 GB held, which at a blended two cents a gigabyte-month is under a dollar. Automated review at five percent of runs and a cent per trace is 100 runs a day, roughly 30 a month. Both figures are assumptions you should replace, and the point stands after you do: at moderate volume, observability is cheap, and the expensive version is the one where raw contexts are stored inline in a search index instead of offloaded.

Day 0 to 7
Hot tier

Full fidelity, indexed, queryable in seconds. Incident work happens here, which is why the tier boundary should sit beyond your worst realistic time to notice a problem rather than at a round number.

Day 8 to 90
Warm tier

Payloads live in object storage, spans keep metadata and pointers. Queries take minutes instead of seconds. This is where trend work and evaluation set backfilling happen.

Day 91 to the limit
Cold tier

Compressed archives, restored before use. Kept for audit, disputes and the occasional argument about what the system did in a quarter that has already been reported on.

At the retention limit
Deletion, evidenced

A scheduled job that runs, logs what it removed, and can be shown to somebody who asks. A retention policy nobody enforces is a commitment you are breaking without noticing.

How to tell whether you need this

Seven questions about an agent you already run. Any two answered badly is enough to justify the retrofit, and the first two on their own usually settle it.

  1. Can you explain a run from three months ago without rerunning it? If reconstruction means rerunning against today's prompt and today's model, you are not reconstructing anything.
  2. If a customer disputes an action, can you show what the agent saw? Not what it did, what it saw. The retrieved context is the part that explains the decision.
  3. When a prompt changes, can you tell whether quality moved? Without pinned versions and a regression set, prompt changes are edits made on faith.
  4. Do you know your cost per run, broken down by step? A single monthly invoice tells you the total and hides which step is responsible for it.
  5. Can you count failures by cause? Reading them one at a time is not counting, and a distribution is what tells you where to spend the next fortnight.
  6. Do you know which model version produced last month's output? Providers deprecate and revise. A trace without a pin cannot answer this.
  7. If the agent degraded quietly, what would alert you? If the only answer is a customer complaint, that is the gap this service exists to close.
Grade 2 done properly beats grade 4 half built

There is a version of this work that is one engineer for three weeks and gives you full capture, reason codes and a run view. There is another version that takes a quarter and delivers counterfactual replay across every path. The first one is the right starting point for almost everyone, and the second is worth doing only for decisions you can name.

How to start

Bring one agent that already runs in production and one incident you could not explain. In an hour we can usually tell you which replay grade you are actually at, which is often a grade lower than the team believes, and what the shortest path to grade 3 on the write path looks like.

The retrofit is two to six weeks depending on how centralised your tool layer already is. If the codebase has a single model client and a tool registry, instrumentation is days. If every tool call was written by hand in its own style, that is the work, and we will say so before quoting rather than after. Making an agent's decisions auditable is a reasonable thing to read while you decide.

Cite this

ChatGPTalker, "Agent observability, so a run can be explained months later", chatgptalker.com/services/agent-observability/

Questions we get asked

How is agent observability different from normal application monitoring?
Application monitoring answers whether a request succeeded. An agent run can succeed technically and still make a wrong decision, so the useful signal is the decision, the confidence and the reason code rather than the status. You also need the configuration in force at the time, which ordinary monitoring never records.
What should an agent trace actually contain?
Four things: what the agent saw, including retrieved context; what it decided, with confidence, threshold and a reason code; what it did, including writes and their confirmation reads; and what it was, meaning prompt version, model version, temperature and tool registry version. Missing the fourth makes the first three uninterpretable later.
Does storing every prompt and response create a privacy problem?
It can, and that is why redaction is decided before capture rather than after. Named personal fields are masked or hashed in-process, so unredacted values never reach the trace store or its backups. Retention is tiered and the deletion job is evidenced. Agree all of this with whoever owns data protection first.
How much does agent observability cost to run?
Usually less than teams expect once payloads are offloaded to object storage rather than held inline in a search index. The two lines are storage, which is arithmetic on run volume, span count and retention, and automated review, which scales with the percentage of traces you score. Use the estimator with your own numbers.
Can you add observability to an agent that is already live?
Yes, and most of our work here is exactly that. The retrofit takes two to six weeks, and the variance comes from how centralised the existing tool and model calls are. A single model client and a tool registry make instrumentation a few days. Hand-rolled calls in many styles are the real work.
What is deterministic replay and why does it matter?
It means re-executing a recorded run offline against its recorded tool responses with the prompt and model versions pinned, so the same inputs produce the same trace. It matters because it is the point at which regression testing becomes possible: you can prove a change fixed something rather than deploying and waiting.
Should we sample traces to save money?
Sample successes, never failures. A flat rate across everything means you keep the same small fraction of failed runs, which are the runs the system exists to explain. Capture every failure, every escalation and every write in full, then sample successful routine runs as hard as your budget requires.

Tell us what is eating the hours.

Send the process, the volume and the tools it touches. You get a scoped plan with a build shape and a timeline, not a brochure.

Start a project