Debugging des runs d'agents

Le debugging des runs aide à comprendre pourquoi un agent a pris une décision donnée.
Sur cette page
  1. Idée en 30 secondes
  2. Problème principal
  3. Comment ça marche
  4. Signaux de production typiques pour debugging run
  5. Comment lire le debugging-layer
  6. Quand l'utiliser
  7. Exemple d'implémentation
  8. Investigation
  9. Erreurs fréquentes
  10. Commencer l'analyse par "n'importe quelle" erreur de log
  11. Pas de corrélation trace + logs + metrics
  12. Ignorer repeated calls et stop_reason
  13. Ne pas comparer avec la release précédente
  14. Clore l'incident sans replay et vérification
  15. Auto-vérification
  16. FAQ
  17. Pages liées

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

SignalOù regarderPourquoi c'est utile
first_error_spantracingtrouver le point où l'erreur apparaît en premier
slowest_spantracing + métriquescandidat bottleneck (à vérifier)
stop_reasonlog run_finishedcomprendre comment le run s'est terminé
error_classlogs tool_result / llm_resultséparer timeout et erreur logique
repeated_tool_callslogs tool_call + tool metricsdétecter des appels répétés (loops, retries, tool spam)
run_latency_p95métriquesvérifier si l'incident est déjà systémique
release_diffdashboard de comparaison des releasesdétecter une régression après changements
synthetic_run_statushealth checksvé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_rate en hausse -> problème dans un tool-layer précis;
  • run_latency_p95 en hausse + tool_latency_p95 stable -> problème probable côté LLM ou logique runtime;
  • repeated_tool_calls en hausse + stop_reason=max_steps -> l'agent est bloqué en boucle;
  • error_rate en hausse après release + release_diff positif -> régression de changement, pas incident ponctuel;
  • synthetic_run_status=fail + health_score en 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.

PYTHON
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.

Insight

Replay != optional.

Sans replay, c'est une hypothèse.
Avec replay, c'est une preuve.

Voici à quoi peut ressembler un debugging snapshot court:

Runfirst_error_spanslowest_spanstop_reasonConclusion
run_9fd2tool_call: search_docstool_call: search_docs (1.8s)tool_errortool dégradé + retries
run_a113llm_generatellm_generate (2.4s)step_errordéfaillance modèle après release
run_d77creasoning (3.1s)max_stepsboucle sans erreur explicite

Investigation

Quand un signal d'incident se déclenche:

  1. capturer run_id, trace_id, release et workflow concerné;
  2. trouver first_error_span et slowest_span dans le tracing;
  3. vérifier stop_reason, error_class, repeated_tool_calls dans les logs;
  4. 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:

⏱️ 8 min de lectureMis à jour 23 mars 2026Difficulté: ★★★
Intégré : contrôle en productionOnceOnly
Ajoutez des garde-fous aux agents tool-calling
Livrez ce pattern avec de la gouvernance :
  • Budgets (steps / plafonds de coût)
  • Permissions outils (allowlist / blocklist)
  • Kill switch & arrêt incident
  • Idempotence & déduplication
  • Audit logs & traçabilité
Mention intégrée : OnceOnly est une couche de contrôle pour des systèmes d’agents en prod.

Auteur

Nick — ingénieur qui construit une infrastructure pour des agents IA en production.

Focus : patterns d’agents, modes de défaillance, contrôle du runtime et fiabilité des systèmes.

🔗 GitHub: https://github.com/mykolademyanov


Note éditoriale

Cette documentation est assistée par l’IA, avec une responsabilité éditoriale humaine pour l’exactitude, la clarté et la pertinence en production.

Le contenu s’appuie sur des défaillances réelles, des post-mortems et des incidents opérationnels dans des systèmes d’agents IA déployés.