Metriques d'agents

Les metriques montrent la reussite, les appels d'outils et les etapes d'execution de l'agent.
Sur cette page
  1. Idee en 30 secondes
  2. Probleme principal
  3. Comment ca fonctionne
  4. Metriques production typiques pour les agents
  5. Quand l'utiliser
  6. Exemple d'implementation
  7. Erreurs typiques
  8. Seulement des moyennes, sans p95/p99
  9. Labels a forte cardinalite
  10. Absence de metriques sur stop_reason
  11. Absence d'alertes sur les anomalies cles
  12. Auto-verification
  13. FAQ
  14. Pages liees

Idee en 30 secondes

Les metriques d'agents montrent l'etat du systeme sur de nombreux runs, pas un seul cas.

Elles repondent a ces questions : le systeme est-il stable, les couts augmentent-ils, et ou la degradation commence-t-elle.

Sans metriques, les problemes apparaissent generalement trop tard : apres des plaintes utilisateur ou un depassement de budget.

Probleme principal

Les logs et le tracing expliquent bien un incident precis.

Mais en production, il faut voir les tendances : ce qui se passe avec latency, token usage, error rate et tool calls entre les releases. Sans metriques, le systeme peut se degrader progressivement et rester longtemps invisible.

En production, cela ressemble souvent a :

  • le temps de reponse moyen semble normal, mais p95 monte deja ;
  • les couts tokens augmentent par vagues apres une release ;
  • le nombre de tool calls par run augmente ;
  • l'equipe apprend le probleme seulement apres un incident.

C'est pour cela que les metriques sont un signal d'observability distinct : elles permettent de detecter les anomalies plus tot et d'agir avant des pannes majeures.

Comment ca fonctionne

Les metriques sont des signaux numeriques agreges qui montrent le comportement du systeme dans le temps.

Le plus souvent, on suit trois niveaux de metriques :

  • niveau run (run_count, success_rate, stop_reason) ;
  • etapes et outils (tool_calls_per_run, tool_error_rate, step_count) ;
  • cout et vitesse (token_usage, cost_per_run (calcule depuis token_usage dans les dashboards ou les requetes metriques), latency_p50/p95).

Les metriques donnent un signal precoce quand le systeme commence a se degrader. Les logs repondent a "que s'est-il passe", et le tracing repond a "comment exactement cela s'est passe dans un run precis".

Metriques production typiques pour les agents

MetriqueCe qu'elle montrePourquoi elle est utile
run_countnombre de runs sur une periodecontrole de charge et de volume trafic
success_ratepart des runs reussisverification rapide de stabilite
latency_p50 / latency_p95latence typique et latence de queuedetection de degradation de performance
token_usage_per_runnombre de tokens consommes par runcontrole du cout LLM
cost_per_runcout estime d'un runcontrole budget et prevision des couts
tool_calls_per_runnombre d'appels d'outils par rundetection d'appels excessifs ou cycliques
tool_error_ratefrequence des erreurs d'outilsdetection precoce de dependances instables
stop_reason_distributiondistribution des causes de fin de runcontrole des limites et pannes typiques

Pour que les metriques soient utiles, on les segmente generalement par release, model ou tool.

Important : ne pas ajouter de champs a forte cardinalite (run_id, request_id, user_id) dans les labels, sinon le stockage metriques se surcharge vite.

Quand l'utiliser

Un large jeu de metriques n'est pas toujours necessaire.

Pour un prototype initial, des compteurs de base de runs et d'erreurs peuvent suffire.

Mais les metriques deviennent critiques quand :

  • le systeme d'agents est deja en production ;
  • il y a des SLO de latency ou de qualite ;
  • il faut controler les couts tokens et tool calls ;
  • les releases sont frequentes et les regressions doivent etre visibles avant les incidents.

Exemple d'implementation

Ci-dessous un exemple simplifie d'instrumentation runtime au style Prometheus. Dans les systemes reels, les memes principes fonctionnent pour Datadog, Grafana Cloud, CloudWatch et d'autres plateformes.

PYTHON
import time
from prometheus_client import Counter, Histogram

RUN_TOTAL = Counter(
    "agent_run_total",
    "Total number of agent runs",
    ["status", "stop_reason", "release"],
)
# success_rate = RUN_TOTAL{status="ok"} / RUN_TOTAL

RUN_LATENCY_MS = Histogram(
    "agent_run_latency_ms",
    "Run latency in milliseconds",
    ["release"],
    buckets=(100, 250, 500, 1000, 2000, 5000, 10000),
)

STEP_COUNT = Histogram(
    "agent_steps_per_run",
    "Number of steps per run",
    ["release"],
    buckets=(1, 2, 4, 8, 12, 16, 24, 32),
)

TOOL_CALL_TOTAL = Counter(
    "agent_tool_call_total",
    "Total tool calls",
    ["tool", "status", "release"],
)

TOOL_ERROR_TOTAL = Counter(
    "agent_tool_error_total",
    "Total tool errors by class",
    ["tool", "error_class", "release"],
)

LLM_ERROR_TOTAL = Counter(
    "agent_llm_error_total",
    "Total LLM step errors by model and class",
    ["model", "error_class", "release"],
)

TOOL_LATENCY_MS = Histogram(
    "agent_tool_latency_ms",
    "Tool call latency in milliseconds",
    ["tool", "release"],
    buckets=(20, 50, 100, 250, 500, 1000, 2000, 5000),
)

TOKEN_USAGE_TOTAL = Counter(
    "agent_token_usage_total",
    "Total LLM tokens",
    ["model", "token_type", "release"],
)


def observe_llm_usage(model, token_usage, release):
    # la plupart des fournisseurs LLM retournent token usage dans la reponse
    if not token_usage:
        return
    TOKEN_USAGE_TOTAL.labels(model=model, token_type="prompt", release=release).inc(
        token_usage.get("prompt_tokens", 0)
    )
    TOKEN_USAGE_TOTAL.labels(model=model, token_type="completion", release=release).inc(
        token_usage.get("completion_tokens", 0)
    )


def run_agent(agent, task, release="2026-03-21"):
    started_at = time.time()
    steps = 0
    stop_reason = "max_steps"
    run_status = "ok"

    try:
        for step in agent.iter(task):
            steps += 1
            step_type = step.type
            result = None  # peut rester None pour des types d'etapes inconnus (protege par le check ci-dessous)

            if step_type == "tool_call":
                tool_name = getattr(step, "tool_name", "unknown")
                tool_started_at = time.time()
                try:
                    result = step.execute()
                    TOOL_CALL_TOTAL.labels(tool=tool_name, status="ok", release=release).inc()
                    TOOL_LATENCY_MS.labels(tool=tool_name, release=release).observe(
                        (time.time() - tool_started_at) * 1000
                    )
                except Exception as error:
                    TOOL_CALL_TOTAL.labels(tool=tool_name, status="error", release=release).inc()
                    TOOL_ERROR_TOTAL.labels(
                        tool=tool_name,
                        error_class=type(error).__name__,
                        release=release,
                    ).inc()
                    TOOL_LATENCY_MS.labels(tool=tool_name, release=release).observe(
                        (time.time() - tool_started_at) * 1000
                    )
                    run_status = "error"
                    stop_reason = "tool_error"
                    raise
            else:
                try:
                    result = step.execute()
                    observe_llm_usage(
                        model=getattr(step, "model", "unknown"),
                        token_usage=getattr(result, "token_usage", None),
                        release=release,
                    )
                except Exception as error:
                    LLM_ERROR_TOTAL.labels(
                        model=getattr(step, "model", "unknown"),
                        error_class=type(error).__name__,
                        release=release,
                    ).inc()
                    run_status = "error"
                    stop_reason = "step_error"
                    raise

            if result and result.is_final:
                stop_reason = "completed"
                break

    finally:
        RUN_TOTAL.labels(status=run_status, stop_reason=stop_reason, release=release).inc()
        RUN_LATENCY_MS.labels(release=release).observe((time.time() - started_at) * 1000)
        STEP_COUNT.labels(release=release).observe(steps)

En production, ces metriques alimentent generalement dashboards et alertes.

Voici a quoi ces metriques peuvent ressembler ensemble sur un dashboard reel :

MetriqueValeur actuelleTendanceStatut
latency_p952.4s+38% en 30 minwarning: au-dessus du SLO
tool_error_rate7.2%+4.1pp en 15 mincritical: alert
token_usage_per_run8.9k+22% apres releasewarning: anomalie
success_rate91.4%-5.3pp en 1 heurewarning: baisse

Pour error_class, il vaut mieux utiliser un dictionnaire de valeurs normalisees afin d'eviter une cardinalite inutile.

Par exemple, une ligne de metrique peut ressembler a :

TEXT
agent_tool_call_total{tool="search_docs",status="error",release="2026-03-21"} 47

Erreurs typiques

Meme si les metriques existent, elles sont souvent peu utiles a cause des erreurs ci-dessous.

Seulement des moyennes, sans p95/p99

La moyenne cache la longue queue des runs lents. Pour la production, le minimum est p50 et p95.

Labels a forte cardinalite

Des labels comme run_id ou user_id augmentent fortement la charge du backend metriques. Mieux vaut segmenter par release, model, tool.

Absence de metriques sur stop_reason

Sans distribution stop_reason, il est difficile de comprendre pourquoi les runs finissent par max_steps ou tool_error. Cela masque souvent un echec d'outil et les premiers signaux d'explosion budgetaire.

Absence d'alertes sur les anomalies cles

Des metriques sans alertes deviennent des graphiques passifs. Sans cela, on peut manquer un spam d'outils ou une chute brutale du taux de succes apres une release.

Auto-verification

Ci-dessous une checklist courte des metriques agent de base 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 : En quoi les metriques different des logs et du tracing ?
R : Les metriques montrent les tendances et l'etat du systeme dans le temps. Les logs expliquent les evenements, et le tracing montre le chemin d'un run precis.

Q : Quel minimum de metriques faut-il pour une premiere release production ?
R : Commencer avec run_count, success_rate, latency_p95, tool_error_rate, token_usage_per_run et stop_reason_distribution.

Q : Pourquoi la latency moyenne ne suffit pas ?
R : La moyenne cache les runs longs et lents. p95 montre la degradation reelle cote utilisateur plus vite.

Q : Quels labels cassent le plus souvent le stockage metriques ?
R : Tout ce qui a une forte cardinalite : run_id, request_id, user_id, prompts complets ou raw args.

Pages liees

Pour continuer :

⏱️ 8 min de lectureMis à jour 21 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.