Quand un agent IA fait une erreur — envoi à un mauvais destinataire, suppression non voulue, fuite involontaire de contenu — la question critique est : "comment c'est arrivé ?". Sans audit log structuré, la réponse honnête est "on ne sait pas". Et sans cette réponse, vous ne pouvez ni corriger, ni convaincre un régulateur, ni rassurer un client.
L'audit log d'un agent n'est pas un "nice to have" opérationnel. C'est le prérequis à toute mise en production sérieuse en 2026. Voici ce qui doit y figurer.
Les 12 champs minimaux par tool call
Pour chaque appel d'outil par l'agent :
- timestamp — ISO 8601 avec timezone et milliseconde.
- session_id — identifiant unique de la conversation.
- user_id — identifiant de l'utilisateur final (anonymisé/hashé si nécessaire RGPD).
- agent_version — version du code de l'agent + version du prompt système.
- model_id — modèle utilisé pour cette inférence (provider + nom + version).
- tool_name — nom de l'outil appelé.
- tool_input — paramètres complets passés à l'outil.
- tool_output — réponse complète de l'outil (tronquée si très long, avec hash de l'original).
- decision_rationale — extrait de la réponse du modèle qui explique pourquoi cet outil a été choisi.
- prior_context_hash — hash du contexte au moment de l'appel (pour reproduire l'état).
- outcome — succès / échec / refusé par broker.
- latency_ms — temps d'exécution.
C'est verbeux. C'est aussi ce qui permet de reconstituer après coup ce qui s'est passé.
Ce qu'il faut tracer en plus, au-delà des tool calls
Le prompt complet envoyé au modèle
Pas juste l'input utilisateur, le prompt système + le contexte assemblé + l'historique. C'est gros, ça remplit du disque. C'est aussi ce qui permet de répondre à "pourquoi le modèle a fait ça".
Coût typique : 5 à 20 KB par tour de conversation. Sur 100 000 tours / mois, ça fait ~10 GB / mois de log brut. À budget par compression et rétention.
Les décisions des guardrails et brokers
Quand un guardrail refuse une action, ou quand un broker rejette un appel : logger pourquoi. C'est aussi précieux que les actions effectuées. Beaucoup d'attaques laissent une trace dans les refus avant de réussir.
Les modifications de mémoire de l'agent
Chaque écriture en mémoire long-terme : qui (utilisateur), quoi (contenu), validé par quoi (auto / humain), source (input utilisateur direct / résumé d'output / auto-écriture par l'agent).
Les évolutions de version
Quand vous déployez une nouvelle version d'un agent (code, prompt système, outils disponibles, modèle), le log doit refléter clairement la transition. Sinon un incident chevauche deux versions et devient impossible à attribuer.
Le format qui marche en pratique
JSON structuré, pas du texte
Beaucoup d'équipes loggent en texte libre lisible. "L'agent a appelé l'outil X avec Y, résultat Z". C'est confortable à l'œil, inexploitable au scan automatique. Toujours JSON.
Un événement par ligne (NDJSON)
`` {"ts":"2026-05-12T14:30:01.123Z","type":"tool_call","session":"...","user":"...","tool":"send_email","input":{...},"output":{...},...} ``
NDJSON s'intègre directement à Loki, Elasticsearch, BigQuery, ClickHouse, Splunk, Datadog. Tous les outils de log savent le manger.
Stockage immuable
Logs en append-only, idéalement avec un mécanisme de chaînage (hash de l'événement précédent dans l'événement courant). Si un attaquant compromet le runtime de l'agent et essaie de falsifier les logs après coup, le chaînage casse.
C'est aussi ce que demandent de plus en plus d'auditeurs SOC 2 et ISO 27001 / 42001 — la non-répudiation des logs critiques.
Rétention différenciée
- 90 jours en chaud (interrogeable rapidement).
- 12 mois en tiède (archive accessible mais plus lente).
- 3 à 5 ans en froid (objet storage, accessibles sur demande).
La rétention longue est nécessaire pour les incidents découverts tardivement (memory poisoning, par exemple, peut prendre des mois à se manifester).
Ce qu'il NE faut PAS faire
Logger les PII en clair
Si un utilisateur tape son numéro de carte dans le prompt et que vous loggez le prompt complet, vous stockez maintenant des PCI data dans vos logs. La majorité des incidents Plaid / Stripe / autre des dernières années sont passés par là.
Pattern : scrubber au niveau du logger qui détecte et masque les patterns PII connus (cartes, IBAN, numéros de sécu, emails sur certains scopes). Imparfait, indispensable.
Logger les secrets
Si l'agent reçoit un token dans son contexte, ne pas logger ce token. Les wrappers de clients HTTP ont souvent une option "sanitize" — l'utiliser.
Logger sans limite de volume
Un agent qui se met à boucler peut générer des millions d'événements par minute. Rate-limiter au niveau du logger, avec alerte sur overflow. Sinon le coût d'observabilité explose et vous perdez la visibilité au moment où vous en avez le plus besoin.
L'usage opérationnel des logs
Avoir les logs, c'est 30% du travail. Les utiliser est le reste.
Dashboards en continu
- Taux de refus par guardrail au fil du temps.
- Distribution des outils appelés.
- Top utilisateurs / top sessions par latence ou volume.
- Anomalies de comportement (un agent qui appelle d'un coup 10x plus un outil donné).
Alertes ciblées
- Action à fort impact en dehors des heures normales.
- Confirmation utilisateur refusée plusieurs fois consécutivement par le même user.
- Évolution brutale du vocabulaire dans les prompts (potentielle injection en cours).
Investigations sur demande
Quand un client signale un comportement bizarre : retrouver la session, retrouver le prompt complet, retrouver les outputs des outils. Si vous mettez plus d'une heure à reconstituer une session précise, votre observabilité est sous-investie.
La règle simple
Avant de mettre un agent en prod, posez la question : "si demain je dois expliquer à un client / un régulateur / un juge ce qu'a fait mon agent à 14h27 le 12 mai, est-ce que je peux ?". Si la réponse est non, l'audit log n'est pas suffisant.
Pour la cartographie complète des surfaces, Threat model d'un agent : 7 surfaces. Pour le runbook d'incident, Agent compromis : runbook 0-72h.