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 depuistoken_usagedans 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
| Metrique | Ce qu'elle montre | Pourquoi elle est utile |
|---|---|---|
| run_count | nombre de runs sur une periode | controle de charge et de volume trafic |
| success_rate | part des runs reussis | verification rapide de stabilite |
| latency_p50 / latency_p95 | latence typique et latence de queue | detection de degradation de performance |
| token_usage_per_run | nombre de tokens consommes par run | controle du cout LLM |
| cost_per_run | cout estime d'un run | controle budget et prevision des couts |
| tool_calls_per_run | nombre d'appels d'outils par run | detection d'appels excessifs ou cycliques |
| tool_error_rate | frequence des erreurs d'outils | detection precoce de dependances instables |
| stop_reason_distribution | distribution des causes de fin de run | controle 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.
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 :
| Metrique | Valeur actuelle | Tendance | Statut |
|---|---|---|---|
| latency_p95 | 2.4s | +38% en 30 min | warning: au-dessus du SLO |
| tool_error_rate | 7.2% | +4.1pp en 15 min | critical: alert |
| token_usage_per_run | 8.9k | +22% apres release | warning: anomalie |
| success_rate | 91.4% | -5.3pp en 1 heure | warning: 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 :
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 :
- Observability pour agents IA — modele global de tracing, logging et metriques.
- Logging d'agents — quels evenements capturer dans la runtime.
- Tracing d'agent — comment voir le chemin d'un run etape par etape.
- Logging semantique des agents — comment unifier les evenements pour l'analytique.
- Cost monitoring des agents IA — comment controler les couts en production.