Idee en 30 secondes
Les tool usage metrics montrent non seulement si l'agent fonctionne, mais aussi comment il utilise les outils et ou la couche outils casse.
Elles aident a voir quels outils sont les plus appeles, ou la latency augmente, et ou commencent les appels repetes ou en erreur.
Sans ces metriques, il est difficile de detecter a temps la surcharge de la couche outils et la hausse des couts.
Probleme principal
Les metriques globales de run ne montrent pas ce qui se passe exactement au niveau des outils.
Deux runs peuvent avoir une latency globale similaire, mais dans un cas le probleme vient d'un search lent, dans l'autre d'appels fetch repetes.
Sans metriques outils, c'est difficile a voir avant un incident.
Ensuite, on voit comment lire ces signaux et trouver les problemes.
En production, cela ressemble souvent a :
- un outil devient discretement un hot spot ;
- les retries augmentent, mais la cause reste floue ;
- une partie des runs depense trop d'etapes sur les outils ;
- l'equipe voit le probleme seulement quand error rate ou budget monte.
C'est pourquoi la couche outils doit etre surveillee a part, et pas seulement via les metriques globales de run.
Comment ca fonctionne
Les tool usage metrics sont construites autour des evenements tool_call et tool_result.
Les tool metrics se divisent en :
- infra metrics (
tool_latency_p95,tool_error_rate) ; - behavior metrics (
repeated_tool_calls,tool_calls_per_run,unique_tools_per_run).
Ces metriques repondent a "comment la couche outils se comporte dans le temps". Les logs et le tracing restent necessaires pour expliquer un run probleme precis.
Les retries se produisent generalement au niveau runtime, pas au niveau du code : l'agent recoit une erreur d'outil comme observation et essaye a nouveau. Les retries ne sont pas juste des appels repetes, mais un signal que l'agent tente de s'adapter aux erreurs d'outils.
Metriques production typiques sur les tools
| Metrique | Ce qu'elle montre | Pourquoi elle est utile |
|---|---|---|
| tool_calls_total | nombre total d'appels tools | controle de charge de la couche outils |
| tool_calls_per_run | nombre de tool calls par run | detection des appels excessifs ou cycliques |
| unique_tools_per_run | nombre d'outils differents utilises par run | evaluation de la complexite du workflow |
| tool_error_rate | part des tool calls en erreur | detection precoce des outils instables |
| tool_latency_p50 / p95 | latency typique et latency de queue des tools | localisation des dependances lentes |
| repeated_tool_calls | appels repetant le meme tool avec les memes args | detection du spam d'outils |
| tool_cost_per_run | cout estime des tools dans un run | controle budget et detection d'outils couteux |
Pour que les metriques soient vraiment utiles, elles sont generalement segmentees par tool, release et, si besoin, model.
Important : ne pas ajouter de champs a forte cardinalite (run_id, request_id, args_hash) dans les labels, sinon le stockage metriques se surcharge vite.
Comment lire la couche outils
Ce qui est appele -> comment l'agent se comporte -> ce qui evolue dans le temps. Ce sont trois niveaux a regarder ensemble.
Il faut lire les tendances dans le temps et les differences entre releases, pas des valeurs isolees.
Voici les combinaisons de signaux a surveiller :
tool_error_rate↑ +repeated_tool_calls↑ -> tool instable, l'agent retrytool_latency_p95↑ +tool_cost_per_run↑ -> degradation d'un outil couteuxtool_calls_per_run↑ +unique_tools_per_run↑ -> complexite excessive du workflow
Quand l'utiliser
Un ensemble complet de tool-metrics n'est pas toujours necessaire.
Pour un agent simple avec 1-2 outils, tool_calls_total et tool_error_rate peuvent parfois suffire.
Mais des tool usage metrics detaillees deviennent critiques quand :
- l'agent utilise activement des API externes ou une BD ;
- des retries arrivent frequemment ;
- il faut controler les couts lies aux outils ;
- il faut detecter le tool spam avant impact utilisateur.
Exemple d'implementation
Ci-dessous un exemple simplifie d'instrumentation des tool usage metrics en style Prometheus. L'exemple montre le controle de base : volume d'appels, latency, classes d'erreurs, repetitions et charge outils par run.
import hashlib
import json
import time
from prometheus_client import Counter, Histogram
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"],
)
TOOL_LATENCY_MS = Histogram(
"agent_tool_latency_ms",
"Tool latency in milliseconds",
["tool", "release"],
buckets=(20, 50, 100, 250, 500, 1000, 2000, 5000),
)
TOOL_CALLS_PER_RUN = Histogram(
"agent_tool_calls_per_run",
"Number of tool calls per run",
["release"],
buckets=(0, 1, 2, 4, 8, 12, 16, 24, 32),
)
UNIQUE_TOOLS_PER_RUN = Histogram(
"agent_unique_tools_per_run",
"Number of unique tools used in run",
["release"],
buckets=(0, 1, 2, 3, 4, 6, 8, 12),
)
REPEATED_TOOL_CALL_TOTAL = Counter(
"agent_repeated_tool_call_total",
"Repeated tool calls with same tool+args signature",
["tool", "release"],
)
TOOL_COST_USD_TOTAL = Counter(
"agent_tool_cost_usd_total",
"Estimated total tool cost in USD",
["tool", "release"],
)
STEP_ERROR_TOTAL = Counter(
"agent_step_error_total",
"Total non-tool step errors by type and class",
["step_type", "error_class", "release"],
)
def stable_hash(value):
# default=str donne une compatibilite de base ;
# dans les systemes critiques, une serialisation explicite est preferable (ex. ISO 8601)
payload = json.dumps(value, sort_keys=True, ensure_ascii=False, default=str).encode("utf-8")
return hashlib.sha256(payload).hexdigest()
def run_agent(agent, task, release="2026-03-21"):
tool_calls = 0
unique_tools = set()
seen_signatures = set()
try:
for step in agent.iter(task):
step_type = step.type
result = None
if step_type != "tool_call":
try:
result = step.execute()
except Exception as error:
STEP_ERROR_TOTAL.labels(
step_type=step_type,
error_class=type(error).__name__,
release=release,
).inc()
raise
if result and result.is_final:
break
continue
tool_name = getattr(step, "tool_name", "unknown")
args = getattr(step, "args", {})
tool_calls += 1
unique_tools.add(tool_name)
signature = (tool_name, stable_hash(args))
if signature in seen_signatures:
REPEATED_TOOL_CALL_TOTAL.labels(tool=tool_name, release=release).inc()
else:
seen_signatures.add(signature)
started_at = time.time()
try:
result = step.execute()
TOOL_CALL_TOTAL.labels(tool=tool_name, status="ok", release=release).inc()
cost_usd = getattr(result, "cost_usd", None)
if cost_usd:
TOOL_COST_USD_TOTAL.labels(tool=tool_name, release=release).inc(cost_usd)
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()
# Cet exemple fait raise.
# Dans les agents reels, l'erreur est souvent passee au LLM comme observation pour retry.
raise
finally:
TOOL_LATENCY_MS.labels(tool=tool_name, release=release).observe(
(time.time() - started_at) * 1000
)
if result and result.is_final:
break
finally:
TOOL_CALLS_PER_RUN.labels(release=release).observe(tool_calls)
UNIQUE_TOOLS_PER_RUN.labels(release=release).observe(len(unique_tools))
# tool_cost_per_run est generalement calcule au niveau dashboard :
# sum(agent_tool_cost_usd_total) / run_count
Voici a quoi ces metriques peuvent ressembler ensemble dans un dashboard reel :
| Tool | calls/min | error_rate | p95 latency | Statut |
|---|---|---|---|---|
| search_docs | 320 | 6.8% | 1.9s | critical: alert |
| fetch_url | 180 | 1.4% | 680ms | warning: p95 en hausse |
| db_lookup | 95 | 0.3% | 120ms | ok |
Pour error_class, il vaut mieux utiliser un dictionnaire de valeurs normalisees pour eviter une cardinalite inutile.
Investigation
Quand une alerte se declenche :
- trouver l'outil anormal via les metriques ;
- regarder les runs concrets dans le tracing ;
- verifier arguments et reponses dans les logs ;
- identifier la root cause (tool, logique agent, ou API externe).
Erreurs typiques
Meme si les tool metrics sont deja en place, elles ne fonctionnent souvent pas comme attendu a cause des erreurs ci-dessous.
Il y a un volume global d'appels, mais pas de detail par tool
tool_calls_total sans detail par outil aide tres peu en incident.
Dans ce cas, il est difficile de trouver vite la source d'un echec d'outil.
Les appels repetes ne sont pas suivis
Sans repeated_tool_calls, il est difficile de voir que l'agent appelle le meme tool avec les memes args.
Cela masque souvent la phase precoce de spam d'outils.
Pas de p95 latency par outil
Le systeme peut sembler stable alors qu'une partie des utilisateurs attend deja 5+ secondes.
Pour la couche outils, le minimum est p50 et p95.
Labels a forte cardinalite
Ajouter run_id, request_id ou args_hash dans les labels surcharge vite le backend metriques.
Mieux vaut garder ces donnees dans les logs, pas dans les labels.
Pas d'alertes sur la couche outils
Sans alertes, les metriques restent une telemetrie passive. On peut alors rater les premiers signaux d'explosion budgetaire due a des appels excessifs d'API externes.
Auto-verification
Ci-dessous une checklist courte des tool usage metrics 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 tool usage metrics different des metriques globales d'agent ?
R : Les metriques globales montrent l'etat du systeme dans son ensemble. Les tool usage metrics montrent ce qui se passe precisement au niveau outils.
Q : Quel minimum de tool-metrics faut-il au demarrage ?
R : Commence par tool_calls_total, tool_error_rate, tool_latency_p95 et tool_calls_per_run.
Q : Faut-il ajouter args_hash dans les labels ?
R : Non. Cela cree presque toujours une forte cardinalite. Pour ces donnees, mieux vaut des logs structures.
Q : Comment separer un echec ponctuel d'un probleme systemique de couche outils ?
R : Verifie si le probleme se repete pour un outil donne sur plusieurs runs et releases. Si les memes signaux (error_class, latency, repeated_tool_calls) reviennent, c'est systemique.
Pages liees
Suite du sujet :
- Metriques d'agents — modele global des metriques pour systemes agentiques.
- Logging d'agents — evenements utiles pour l'analyse d'incident.
- Tracing d'agent — chemin d'un run etape par etape.
- Logging semantique des agents — vocabulaire d'evenements stable pour l'analytique.
- Cost monitoring des agents IA — controle des couts en production.