Idée en 30 secondes
Le debugging des runs d'agents aide à passer du symptôme à la cause: ce qui a cassé, à quelle étape, et pourquoi.
Pour cela, il faut corréler tracing, logs et métriques d'un run problématique.
Sans cette corrélation, l'équipe voit souvent seulement l'erreur finale et pas tout le chemin qui y mène.
Problème principal
Dans les systèmes d'agents, un incident a rarement une seule cause évidente.
L'erreur finale peut n'être qu'une conséquence: le vrai problème a pu commencer plus tôt, par exemple avec un tool call lent, un retry raté, ou une régression après release. Sans debugging systématique, c'est difficile à localiser rapidement.
Voyons maintenant comment lire ces signaux et trouver la root cause de façon stable.
En production, cela ressemble souvent à ceci:
- les logs contiennent beaucoup d'événements, sans séquence claire;
- la cause se mélange avec des erreurs secondaires;
- l'incident est "corrigé", puis revient après release;
- le MTTR monte, car l'équipe reconstruit le contexte depuis zéro à chaque fois.
C'est pour cela que le debugging d'un run doit être un processus opérationnel à part, pas une recherche manuelle du "premier error".
Comment ça marche
Un debugging run pratique contient généralement trois niveaux:
- contexte du run (
run_id,trace_id,release,workflow); - evidence -> analyse (
spans,logs,metrics,stop_reason); - décision (hypothèse -> fix -> vérification via replay et tests).
Ces niveaux répondent à: où est le problème, pourquoi il est apparu, et si le fix le supprime vraiment. Le tracing montre le chemin, les logs montrent les événements, et les métriques montrent l'ampleur et la tendance.
Beaucoup de logs != debugging rapide. La vitesse ne vient pas du volume de données, mais de leur corrélation autour d'un run.
Signaux de production typiques pour debugging run
| Signal | Où regarder | Pourquoi c'est utile |
|---|---|---|
| first_error_span | tracing | trouver le point où l'erreur apparaît en premier |
| slowest_span | tracing + métriques | candidat bottleneck (à vérifier) |
| stop_reason | log run_finished | comprendre comment le run s'est terminé |
| error_class | logs tool_result / llm_result | séparer timeout et erreur logique |
| repeated_tool_calls | logs tool_call + tool metrics | détecter des appels répétés (loops, retries, tool spam) |
| run_latency_p95 | métriques | vérifier si l'incident est déjà systémique |
| release_diff | dashboard de comparaison des releases | détecter une régression après changements |
| synthetic_run_status | health checks | vérifier l'impact sur le workflow critique |
Pour garder un debugging stable, ces signaux sont généralement segmentés par release, workflow, model et tool.
Important: n'ajoute pas de labels à haute cardinalité (run_id, request_id, user_id) dans les métriques. Pour cela, il vaut mieux utiliser logs et tracing.
Comment lire le debugging-layer
Quel run a cassé -> à quelle étape -> pourquoi exactement. Ces trois niveaux doivent toujours être lus ensemble.
Il faut regarder les tendances et les écarts entre releases, pas seulement un événement isolé.
Combinaisons de signaux fréquentes:
first_error_span=tool_call+tool_error_rateen hausse -> problème dans un tool-layer précis;run_latency_p95en hausse +tool_latency_p95stable -> problème probable côté LLM ou logique runtime;repeated_tool_callsen hausse +stop_reason=max_steps-> l'agent est bloqué en boucle;error_rateen hausse après release +release_diffpositif -> régression de changement, pas incident ponctuel;synthetic_run_status=fail+health_scoreen baisse -> le problème impacte déjà le workflow critique.
Quand l'utiliser
Un debugging-flow formel n'est pas toujours nécessaire.
Pour un scénario simple single-shot sans tools, un logging de base et une revue manuelle de l'erreur peuvent suffire.
Mais une approche systémique du debugging devient critique quand:
- le run contient plusieurs étapes de reasoning et des tool calls;
- les incidents impactent latence, coût ou SLO;
- les releases sont fréquentes et il faut capter les régressions vite;
- l'équipe a un processus on-call et a besoin d'un MTTR prévisible.
Exemple d'implémentation
Ci-dessous, une fonction simplifiée qui collecte l'evidence pour un run et forme une hypothèse de base. Ce n'est pas un remplacement du incident tooling complet, mais cela montre un processus de debugging pratique.
from collections import Counter
def debug_run(run_id, trace_events, log_events, debug_metrics_snapshot):
run_spans = sorted(
[s for s in trace_events if s.get("run_id") == run_id],
key=lambda s: s.get("started_at_ms", 0),
)
run_logs = [e for e in log_events if e.get("run_id") == run_id]
first_error_span = next((s for s in run_spans if s.get("status") == "error"), None)
# slowest_span peut être None si le run ne contient pas de spans
slowest_span = max(run_spans, key=lambda s: s.get("latency_ms", 0), default=None)
stop_reason = "unknown"
for event in reversed(run_logs):
if event.get("event") == "run_finished":
stop_reason = event.get("stop_reason", "unknown")
break
seen_signatures = set()
repeated_tools = Counter()
for event in run_logs:
if event.get("event") != "tool_call":
continue
signature = (event.get("tool"), event.get("args_hash"))
if signature in seen_signatures:
repeated_tools[event.get("tool")] += 1
else:
seen_signatures.add(signature)
hypotheses = []
if first_error_span and first_error_span.get("step_type") == "tool_call":
hypotheses.append("Défaillance probable du tool-layer: vérifier disponibilité de l'outil et timeout policy.")
if repeated_tools:
hypotheses.append("Des tool calls répétés sont détectés: vérifier dedupe/cache et stop conditions.")
if slowest_span and debug_metrics_snapshot.get("run_latency_p95_ms", 0) > debug_metrics_snapshot.get("slo_latency_ms", 2500):
hypotheses.append("La p95 latency est au-dessus du SLO: localiser le bottleneck via slowest_span.")
if debug_metrics_snapshot.get("release_error_rate_delta", 0) > 0:
hypotheses.append("error_rate a augmenté après release: vérifier les changements prompt/runtime/tool routing.")
return {
"run_id": run_id,
"first_error_span": first_error_span,
"slowest_span": slowest_span,
"stop_reason": stop_reason,
"repeated_tools": dict(repeated_tools),
"hypotheses": hypotheses,
}
Le debugging n'est pas considéré terminé tant que le problème n'est pas reproductible (replay) et que le fix n'est pas confirmé comme stable. Si le problème ne peut pas être reproduit, le debugging passe en mode hypothèse, pas en mode preuve.
Replay != optional.
Sans replay, c'est une hypothèse.
Avec replay, c'est une preuve.
Voici à quoi peut ressembler un debugging snapshot court:
| Run | first_error_span | slowest_span | stop_reason | Conclusion |
|---|---|---|---|---|
| run_9fd2 | tool_call: search_docs | tool_call: search_docs (1.8s) | tool_error | tool dégradé + retries |
| run_a113 | llm_generate | llm_generate (2.4s) | step_error | défaillance modèle après release |
| run_d77c | — | reasoning (3.1s) | max_steps | boucle sans erreur explicite |
Investigation
Quand un signal d'incident se déclenche:
- capturer
run_id,trace_id,releaseet workflow concerné; - trouver
first_error_spanetslowest_spandans le tracing; - vérifier
stop_reason,error_class,repeated_tool_callsdans les logs; - confirmer l'ampleur du problème dans les métriques (spike ou tendance) et comparer les écarts entre releases.
Erreurs fréquentes
Même avec observability en place, le debugging échoue souvent à cause d'erreurs classiques.
Commencer l'analyse par "n'importe quelle" erreur de log
Sans rattacher l'analyse à une run_id précise, l'équipe mélange des symptômes de différents incidents.
Dans ce mode, il est difficile de distinguer un problème local d'un échec en cascade.
Pas de corrélation trace + logs + metrics
Si tracing, logs et métriques sont analysés séparément, les hypothèses se contredisent souvent. Résultat: le MTTR augmente même pour des pannes d'outil simples.
Ignorer repeated calls et stop_reason
Sans ces signaux, on rate facilement loops et retry storms. Cela masque souvent la phase précoce de spam d'outils.
Ne pas comparer avec la release précédente
Sans release_diff, l'équipe ne voit pas si le problème est apparu après changement.
La régression reste donc plus longtemps en production.
Clore l'incident sans replay et vérification
Un fix peut supprimer le symptôme, pas la cause. Cela augmente le risque de panne partielle répétée.
Auto-vérification
Checklist courte de debugging-flow baseline avant release.
Progression: 0/9
⚠ L'observability de base manque
Le système sera difficile à déboguer en production. Commencez par run_id, structured logs et tracing des tool calls.
FAQ
Q: Par où commencer le debugging d'un run problématique?
A: Commence par run_id et trace_id: trouve first_error_span, vérifie stop_reason, puis confirme l'ampleur dans les métriques. first_error_span est le moyen le plus rapide de trouver le point de panne.
Q: Qu'est-ce qui est le plus important pour le debugging: tracing ou logs?
A: Les deux ensemble: le tracing montre le chemin des étapes, les logs donnent les détails d'événements (error_class, args_hash, policy decision).
Q: Comment savoir si c'est une régression de release, pas une panne ponctuelle?
A: Compare error_rate, latency_p95, repeated_tool_calls entre releases. Si le signal est durablement pire après release, c'est une régression.
Q: Quel est le minimum de données pour déboguer en 10-15 minutes?
A: Minimum: run_id, trace_id, first_error_span, stop_reason, error_class, latency_p95 et contexte de release.
Pages liées
Pour continuer:
- Tracing d'agent — voir le chemin d'un run étape par étape.
- Logging d'agents — événements nécessaires pour l'analyse d'incident.
- Métriques d'agents — distinguer panne ponctuelle et tendance.
- Health checks d'agents — signaux précoces de dégradation avant incident.
- Alerting des défaillances d'agents — déclencher l'investigation au bon moment.