Your agent got it right. Can you show how it got there?

A correct agent response does not prove the execution was correct. If you cannot reconstruct what happened during the run, it is hard to operate and debug it in production.

person reviewing documents and data on a laptop

Auditing an agent's process means reconstructing the run: which tools were called, with which data, on which version of the system, and what effect that had on the product. A correct agent response does not prove the execution was correct. If you cannot reconstruct what happened during the run, it is hard to operate and debug it in production.

Every run should have an identifier (run_id, trace_id, or equivalent) that correlates every action in that process: user, agent, tenant (a customer account in your SaaS), each tool, the version that ran, where the context came from, whether a human approved, and what changed in the product. That identifier is not the same thing as an observability trace. In OpenTelemetry, a trace is usually made of spans and describes the topology of a request; the run_id is the business identifier that ties that request to the effect in your product. They can be correlated, but they are not interchangeable.

OpenTelemetry already describes what you can annotate on a generative system: model, tokens, tools, and, if you enable it explicitly, the content. The text is off by default, because names, credentials, and customer data fit in there.

This article is not about standing up an evals lab, and it does not replace what we already covered on permissions. It is about the information you have to be able to recover after a run has already happened, when the output alone is no longer enough to operate it. In the map of layers this was one line (evaluation and logs). Here it is the work.

The myth of the perfect output

The demo rewards an answer that reads well. The pilot rewards the effect in the product. The copilot can close a thread by saying it already updated the CRM, created the task, or changed an opportunity's status, and the chat looks clean. Hours later the customer (or the sales team) finds that the record did not move. Nobody can say which tool ran, with which id, or whether a human approved. An agent can use the wrong tool, mix the tenant into the context, and still write a close that sounds senior.

You do not see that in the chat. You see it if you can answer which tool ran, with which arguments, which prompt version, which document it read, and who approved. If the answer is "it read well", you are scoring style. Same jump as a demo is not an agent: the output is not the proof.

A correct response does not prove three things. It does not prove that the right tool was used or that it ran well: a tool can look up, search, calculate, read a database, or write, and the record has to say which one it was and what came back. It also does not prove that the context belonged to that tenant, because a clean summary can rest on the neighbor's account file. And it does not prove that nobody had to step in: if a human corrected the status change or rewrote the email and that is not written down, the agent gets the credit and the team gets the incident.

If you cannot verify those three questions, you do not have enough traceability over the run: you have a chat that reads well and a process you cannot audit.

What you have to be able to reconstruct from a run

A useful record is not "we store the prompt". It is being able to reconstruct what happened when something goes wrong, with names and identifiers, without depending on internal chat or on the memory of whoever was looking at the thread. The minimum is being able to follow the chain from who starts the run to the effect in the product.

Step

What gets recorded

1. User or trigger

Who started the run, and on which tenant.

2. Model

Which model and which instruction version ran.

3. Tool call

The name of the tool the agent chose.

4. Arguments

Values sent, with a limited, validated schema.

5. Result

Success, error, or retry, plus the attempt number.

6. Next step

What the agent decided after seeing the result.

7. Effect

What changed in the product, if anything did.

If you change the prompt on Tuesday, you should be able to tell which version was running on each Monday run. The model's "yes" is not the effect: the effect is whether a record was updated, a task was created, an email was sent, or an opportunity changed status.

You do not need an observability product on day one, but you do need not to throw the trail away. A log of loose events ("called the API", "answered") with no identifier tying them together is noise. If you cannot reconstruct that chain, you change the prompt because "it seems better" and you do not know whether failures dropped or the bill went up.

That is what you should be able to open on Monday. At Devic you inspect it in observability: the run, each tool, the arguments, the result, and the error, correlated.

Which tools it called, which version, how many times

The tool is the door into your product. The record is the proof that this door was used, not another.

For each call you want a name, well-defined arguments (a limited schema, not a free-text field), a result or error, and an attempt number. You also want the version of the system that fired it: model, prompt, and agent code. Without a version, on Tuesday you cannot say whether the bug is this prompt or last week's.

Retries belong in the record too. If a tool call returns an error and the agent runs it again, you need to know how many attempts happened and what each one returned, because that is where both cost and possible duplicates show up (two updates to the same record, two emails, two status changes). The record has to say whether that call was the first or the third.

In the pilot, do not just note that "the agent used tools". Record the list: get_account once, update_opportunity zero, or update_opportunity twice, and then you have a different problem.

Where the model got what it read

Context is not memory and it is not state. We already split those on the map. Here the origin matters: which chunk, which source, which tenant, and which date.

If the model summarizes a help article, the record says which article, not "it searched the knowledge base". If it uses information from a conversation thread, you should be able to identify which messages it used. If it loads an order or an account file, you should be able to identify the matching order_id or account_id. Without that, "it made up the amount" and "it read the old record" look the same in the chat, and they do not in the record.

The usual failure is pasting the whole thread into the next prompt and calling it evidence. After that you cannot tell where each fragment came from, and you cannot forget or delete one customer's information selectively. Provenance is an id and a tenant, not a dump.

In the pilot, prioritize the origin of whatever triggers an action. The rest of that turn's context can wait.

When a human approves, that goes in the record too

A human in the loop is not a feeling of control. It is an event: who saw what, what they approved, at what time, and on which resource (opportunity_id, task_id, ticket_id).

In permissions the question was when that person is needed. Here the question is whether you can prove it. "Marta signed off" that is not in the record is a hallway conversation, and on incident day Marta does not remember the amount or the status she approved.

What you store from that approval: who approved, a reference to the content they saw, a hash so you can later check that content did not change, the decision, and the run identifier. The hash does not replace the content: it verifies integrity, it does not reconstruct what was shown. If you do not want to store the full payload, keep the reference and the hash; we do not treat those two as the same thing.

If the flow has no human, the record should say so. It should also record when an action did not need approval, so later there is no ambiguity about who took part in the run.

How to reconstruct a run after it fails

Reconstructing is not asking the model the same thing and hoping for the same text. The model is not deterministic, and external systems may have changed. Replay would mean running the same conditions again, in full or in part, and that does not have to return the same result. What you can (and should) do is open the same identifier and see the same calls, the same context, and the same version: that is reconstructing a past run.

If you cannot do that, you cannot fix the problem on purpose. You argue about the prompt, and the failure was a 500, an id from another tenant, or a retry that applied the change twice.

There are three simple tests that you can reconstruct it: someone who did not write the agent opens the identifier and tells what happened; you change the prompt and old runs still name the old version; and the effect in the external system correlates with the specific call that caused it, not only with the chat prose.

To debug one failed run, the detail of that execution is often more useful than an aggregated dashboard, because the dashboard summarizes and the record tells the story. Both are useful and neither replaces the other. If you export several runs, the risk is not "mixed rows" by itself: it is that one tenant's data becomes visible to another tenant, or to someone who should not see it.

Checklist: can you show how it got there?

Before you open the second tenant, the team should be able to answer these questions:

Does every run have an identifier that ties user, agent, and tenant?

Can you name the prompt, model, and agent version for that run?

Do you list each tool, with arguments, result, and attempt number?

Do you know which source and which tenant the action-triggering context came from?

Is a human approval an event, or only someone's memory?

Can someone open the last problematic run and tell it without having been in the chat?

Does the effect in the product (a record, an email, an opportunity status) show up in the record, not only the model's "yes"?

If you cannot answer several of these, you probably do not have enough traceability to reconstruct a run with any confidence. The output can be good, and it is still not proof of the process.

What not to store: customer data and secrets

The record that saves you on Monday can leak you on Tuesday. OpenTelemetry does not recommend capturing certain sensitive content by default, such as prompts, messages, or tool arguments; that capture has to be turned on explicitly, because those fields can hold customer data, amounts, or credentials.

Three pilot rules, not an eternal compliance program. Do not paste secrets: an API key in the log is a delayed incident. One tenant must not be able to see another tenant's information, and any export has to honor the same access and isolation controls; multi-tenant observability is fine if there is segregation and permissioning, what is not acceptable is a dump in which one customer sees the neighbor. And do not store the body if an id and a reference are enough: the account_id or ticket_id, plus a reference to the payload and its hash, usually get you the correlation. The whole document rarely does.

Retention is a decision too. Different kinds of logs can need different policies, depending on purpose, sensitivity, and the obligations that apply. If you do not date it, you pile it, and what you pile, someone exports one day.

When those lines exist, the rest is engineering. At Devic you can inspect that chain in observability: runs, tool calls, arguments, results, and errors, correlated by an identifier. You can change the model; the proof of how the action was reached stays.

A correct response does not prove the execution was correct.

Alberto Iglesias

CEO

Turn your SaaS AI-Native

Get a free trial just by signing up


Ready to turn your platform AI-Native?

Centralize agents, tools, and flows in one platform and start scaling with less friction.

Build and run agents without friction

Connect your current infrastructure

  • Devic AI

  • Devic AI

  • Devic AI

Ready to turn your platform AI-Native?

Centralize agents, tools, and flows in one platform and start scaling with less friction.

Build and run agents without friction

Connect your current infrastructure

  • Devic AI

  • Devic AI

  • Devic AI