Record the run, not the result
The first time an agent does something inexplicable in production, you will want the exact message list it saw. If you did not store it, the run is gone: you cannot reproduce it, because the input has moved on and the model is stochastic.
So log, for every run:
- A run id, generated at the start, and the trigger that started it.
- The pinned model id and the prompt version. Not “GPT-class”: the exact string, because behaviour changes between versions and you will be comparing across weeks.
- Every message, in order, including the system prompt.
- Every tool call: name, arguments, result, duration, and whether it errored.
- Token counts per turn, input and output, plus a running total.
- The final status: succeeded, failed, hit the budget, stopped for a person.
- On whose behalf it ran.
Truncate large tool results in the log and write the full payload to a file named by run id and step number. You want the trace readable and the evidence retrievable, which are different requirements.
Start with a file, not a platform
One JSON object per line, one file per run, and jq. This answers most questions on day one and costs nothing:
# every run that hit an error from the payments tool, this week
jq -r 'select(.tool=="issue_refund" and .error!=null) | "\(.run) \(.error)"' runs/*.jsonl
# the ten most expensive runs
jq -s 'map(select(.event=="end")) | sort_by(-.total_tokens)[:10]' runs/*.jsonlMove to a hosted tracing tool when the volume makes files awkward, not before. OpenTelemetry gives you the vocabulary (a trace per run, a span per step, attributes on each) and free self-hosted backends like Jaeger or Grafana Tempo will render it. Langfuse self-hosts and is built for this shape of data. All of them are improvements on a file; none of them is a prerequisite for starting.
Three numbers and one histogram
Counters: runs started, runs succeeded, cost. Then the histogram that earns its place: steps per run.
A healthy agent produces a distribution with a hump in the middle (most tasks take four to eight steps) and a thin tail. What you are looking for is a spike at the maximum. If your step limit is twenty and 12 per cent of runs use exactly twenty, then 12 per cent of runs were cut off mid-task.
The reason this matters more than any other metric is what those runs look like from outside. An agent stopped at its budget still writes a final message, and that message is usually a confident summary of partial work. Nothing in the output says “I was interrupted”. The step histogram is where it shows, and it shows immediately.
Add a latency histogram and a cost-per-run histogram beside it. Averages hide precisely the tail you need to see; a mean of nine seconds is compatible with one run in fifty taking four minutes.
Correlate outward
Pass the run id into every outbound call: as a header on HTTP requests, as a field on rows you write, in the subject line of tickets you create. When the CRM team asks who changed four hundred records on Tuesday, the answer is one query rather than a week of guessing. This costs one line in your HTTP client and repays it the first time anything goes wrong.
Logs are a data store
Whatever the agent read, your logs now hold. That includes the customer’s address, the contents of their email and whatever else came back from a tool. Treat the trace store with the same access rules as the database it drew from, and be specific about it:
- Redact at write time, not at read time. Hash or truncate identifiers before they land.
- Set a retention period and enforce it with a scheduled job that actually deletes.
- Remember that a deletion request covers the trace store too. An agent’s log is a copy nobody thinks to include in the erasure path, and that omission is a real compliance failure rather than a theoretical one.
Sampling, when volume arrives
At low volume, keep everything. At high volume: keep every failure, keep every run that took an irreversible action, and keep a random sample (one in twenty is plenty) of ordinary successes.
The random sample is the part teams drop, and it is the part that tells you what normal looks like. Without it, you only ever read broken runs, and after a month you have a vivid and completely unrepresentative picture of how the system behaves.
What a trace cannot give you
It records what the model saw and what it did. It does not record why. A reasoning trace is text the model generated, not an account of its computation, and treating it as an explanation will mislead you: models produce plausible justifications for choices made on other grounds.
So use traces for the questions they can answer, which are the useful ones anyway: did it see the right thing, was the next action reasonable given only what was in front of it, and did the harness do what it was told.
Every lesson here is open. Your progress is recorded once you pass the Context Engineering exam.
Check your understanding
An agent’s step limit is 20. Its step-per-run histogram shows a normal hump around six steps and a sharp spike at exactly 20, covering 12 per cent of runs. Users have not complained. What does this most likely mean?
Pick the one you would defend. Your answer stays private.
Stuck on something?Ask Mai, your AI tutor