Audit logs and traceability for AI systems

GuideLast reviewed Oct 16, 2026By Himanshu Ramchandani
Short answer

An audit log lets you answer, months later: who asked, what the system retrieved and which document versions, what the model saw and returned, which model and prompt version were used, which tools ran with which arguments, and who approved any action. Store it tamper-evident, with access control and a retention period set by your compliance needs. Traces built for debugging and audit logs built for accountability overlap, and they differ in retention, access and integrity.

Why it matters

A customer disputes an answer from three months ago. A regulator asks how a decision was made. An agent took an action nobody remembers approving. Without an audit trail, nobody can say why the system did what it did, and "the AI decided" isn't an answer anyone accepts.

Traces and audit logs

Traces Audit log
Purpose Debugging, evals Accountability, compliance
Retention Weeks to months As long as rules or contracts require
Access Engineers Restricted, with access itself logged
Integrity Normal storage Append-only or tamper-evident
Content Everything, including full prompts What's needed to reconstruct and justify, with personal data minimised

Many teams generate both from the same events, and store them differently.

What to record

  • Who: the user, their role and tenant, and the agent or service acting for them.
  • When: timestamps for each step.
  • What they asked: the input, masked where needed.
  • What the system used: source document IDs and versions, tool calls with arguments and results.
  • How: model name and version, prompt version, configuration version.
  • What it returned: the output.
  • Who approved: approver identity and time, for actions that needed approval.
  • What happened next: feedback, escalation, corrections.

Tamper evidence

For logs that may be used as evidence, make tampering detectable. A simple method is a hash chain: each entry includes the hash of the previous one, so changing any past entry breaks every hash after it.

import hashlib
import json


def append(log: list[dict], event: dict) -> None:
    prev = log[-1]["hash"] if log else "0" * 64
    body = json.dumps(event, sort_keys=True)
    log.append({"event": event, "prev": prev, "hash": hashlib.sha256((prev + body).encode()).hexdigest()})


def verify(log: list[dict]) -> bool:
    prev = "0" * 64
    for entry in log:
        body = json.dumps(entry["event"], sort_keys=True)
        if entry["prev"] != prev or entry["hash"] != hashlib.sha256((prev + body).encode()).hexdigest():
            return False
        prev = entry["hash"]
    return True


log: list[dict] = []
append(log, {"user": "u_381", "action": "ask", "sources": ["refund-policy@v7"], "model": "small-2026-08"})
append(log, {"user": "u_381", "action": "refund_order", "order": "ORD-1043", "approved_by": "agent_lead_12"})
print("valid:", verify(log))
log[0]["event"]["sources"] = ["refund-policy@v6"]
print("after tampering:", verify(log))

Append-only storage, write-once object storage, or a managed ledger service give stronger guarantees.

Retention and access

  • Set retention from your legal and contractual requirements, not from storage cost.
  • Restrict who can read audit logs, and log access to them.
  • Mask personal data the audit doesn't need, so the audit log doesn't become a new leak.

Test it

Pick one answer from last week and try to reconstruct it fully from your logs: the question, the sources and their versions, the model and prompt, the output. Track the share of answers you can fully reconstruct.

From the floor

In the hallucination citation verifier design, one of the outputs was an audit trail for every verification, with the citations found, the result for each one, the confidence score and the databases checked, because a law firm needs to be able to show exactly what was checked and when.

Sources