Latency Monitoring pour agents

Aide a suivre le temps de reponse et les retards d'execution.
Sur cette page
  1. Idee en 30 secondes
  2. Probleme principal
  3. Comment ca fonctionne
  4. Metriques de latency production typiques
  5. Comment lire la latency-layer
  6. Quand l'utiliser
  7. Exemple d'implementation
  8. Investigation
  9. Erreurs typiques
  10. On regarde seulement la latency moyenne
  11. Pas de decoupage de latency par tools et step type
  12. Queue time est ignoree
  13. Pas de metriques timeout-rate et retry-overhead
  14. Pas d'alertes sur p95/p99 et timeout spikes
  15. Auto-verification
  16. FAQ
  17. Pages liees

Idee en 30 secondes

Le latency monitoring pour les agents IA montre ou le systeme ralentit : dans les etapes LLM, les tools, les files d'attente ou les iterations repetees.

Sans cela, il est difficile de comprendre pourquoi les utilisateurs attendent plus longtemps, meme quand un run se termine formellement avec succes.

Probleme principal

Un run peut se terminer correctement, mais rester trop lent pour la production.

Deux requetes avec la meme reponse peuvent avoir une latency differente : a cause d'une chaine de reasoning plus longue, d'un tool lent ou de retries. Sans latency monitoring, cela se voit souvent seulement apres les plaintes utilisateurs.

Voyons ensuite comment lire ces signaux et trouver ce qui ralentit exactement un run.

En production, cela ressemble souvent a :

  • la latency moyenne semble normale, mais p95 monte deja ;
  • un tool devient discretement un bottleneck ;
  • les retries ajoutent des secondes sans hausse visible du trafic ;
  • l'equipe voit le probleme seulement apres panne partielle.

C'est pourquoi la latency-layer doit etre surveillee separement, et pas seulement via des metriques globales de run.

Comment ca fonctionne

Le monitoring de latency repose sur deux types de signaux :

  • runtime signals (queue_time, step_latency, tool_latency, ttft) ;
  • service signals (run_latency_p50/p95/p99, timeout_rate, retry_overhead_ms).

Ces metriques repondent a la question "ou et pourquoi le systeme ralentit dans le temps". Logs et tracing sont necessaires pour expliquer un run lent concret.

Latency != user experience. Les utilisateurs ne ressentent pas la moyenne - ils ressentent p95/p99. Ce sont les requetes lentes qui definissent la perception. Latency est souvent liee directement au cost. Des runs plus longs impliquent plus de tokens, plus d'appels tools et plus de retries, ce qui augmente directement le cost.

Metriques de latency production typiques

MetriqueCe qu'elle montrePourquoi elle est utile
run_latency_p50temps d'execution typique d'un runcontrole de base de la vitesse
run_latency_p95 / p99longue queue et runs les plus lentsdetection precoce de degradation
step_latency_p95quelles etapes agent ralentissentlocalisation de l'etape problematique
tool_latency_p95latency de tools specifiquesrecherche de bottlenecks externes
ttft_p95time-to-first-token pour LLMcontrole de vitesse de premiere reponse
queue_time_p95combien de temps un run attend avant de demarrercontrole de charge et capacity
timeout_ratepart des etapes finissant en timeoutsignal precoce d'instabilite
retry_overhead_mstemps ajoute par les retriesimpact de la recuperation sur latency

run_latency_p95 et run_latency_p99 sont generalement calcules au niveau dashboard/requetes, pas comme compteur separe dans le code.

Pour garder des metriques pratiques, on segmente souvent par release, model, tool et type de workflow.

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.

Comment lire la latency-layer

Ou apparait le delai -> comment l'agent se comporte -> ce qui ralentit exactement le run. Ces trois niveaux doivent etre lus ensemble.

Il faut regarder les tendances dans le temps et les differences entre releases, pas des valeurs isolees.

Ensuite, lire les combinaisons de signaux :

  • run_latency_p95 up + tool_latency_p95 up -> bottleneck dans les tools externes ;
  • run_latency_p95 up + step_count up -> l'agent fait des iterations inutiles ;
  • ttft_p95 up + tool_latency_p95 ~= stable -> probleme dans la couche LLM, pas tools ;
  • timeout_rate up + retry_overhead_ms up -> retries masquent l'instabilite et ajoutent de la latency ;
  • queue_time_p95 up + run_count up -> manque de capacity dans le systeme.

Quand l'utiliser

Un latency monitoring complet n'est pas toujours necessaire.

Pour un prototype simple, un temps de reponse de base peut suffire.

Mais le monitoring detaille des latences devient critique quand :

  • le systeme est deja en production avec SLO/SLA de vitesse ;
  • l'agent utilise plusieurs tools externes et dependances ;
  • les releases sont frequentes et les regressions de latency doivent etre visibles ;
  • le workflow contient des files, retries ou boucles de reasoning multi-etapes.

Exemple d'implementation

Ci-dessous un exemple simplifie d'instrumentation Prometheus des metriques de latency. Il montre le controle de base : run latency, etapes, tools, timeouts et retry overhead.

PYTHON
import time
from prometheus_client import Counter, Histogram

# perf_counter() est utilise au lieu de time.time()
# pour obtenir des mesures de latency monotones et precises
RUN_TOTAL = Counter(
    "agent_run_total",
    "Total number of agent runs",
    ["status", "stop_reason", "release"],
)

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

STEP_LATENCY_MS = Histogram(
    "agent_step_latency_ms",
    "Latency by step type in milliseconds",
    ["step_type", "release"],
    buckets=(20, 50, 100, 250, 500, 1000, 2000, 5000),
)

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

QUEUE_TIME_MS = Histogram(
    "agent_queue_time_ms",
    "Queue wait time before run start",
    ["release"],
    buckets=(0, 20, 50, 100, 250, 500, 1000, 2000),
)

TTFT_MS = Histogram(
    "agent_ttft_ms",
    "Time to first token in milliseconds",
    ["model", "release"],
    buckets=(50, 100, 200, 400, 800, 1500, 3000),
)

TIMEOUT_TOTAL = Counter(
    "agent_timeout_total",
    "Total timeout errors by layer",
    ["layer", "release"],
)

RETRY_OVERHEAD_MS = Histogram(
    "agent_retry_overhead_ms",
    "Added latency from retries",
    ["release"],
    buckets=(0, 50, 100, 250, 500, 1000, 2000, 5000),
)


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

    if queue_time_ms > 0:
        QUEUE_TIME_MS.labels(release=release).observe(queue_time_ms)

    try:
        for step in agent.iter(task):
            step_type = step.type
            step_started_at = time.perf_counter()

            try:
                result = step.execute()
            except TimeoutError:
                run_status = "error"
                if step_type == "tool_call":
                    stop_reason = "tool_timeout"
                elif step_type == "llm_generate":
                    stop_reason = "llm_timeout"
                else:
                    stop_reason = "step_timeout"
                layer = (
                    "tool"
                    if step_type == "tool_call"
                    else "llm"
                    if step_type == "llm_generate"
                    else "runtime"
                )
                TIMEOUT_TOTAL.labels(layer=layer, release=release).inc()
                raise
            except Exception:
                run_status = "error"
                if step_type == "tool_call":
                    stop_reason = "tool_error"
                elif step_type == "llm_generate":
                    stop_reason = "llm_error"
                else:
                    stop_reason = "step_error"
                raise
            finally:
                step_latency_ms = (time.perf_counter() - step_started_at) * 1000
                STEP_LATENCY_MS.labels(step_type=step_type, release=release).observe(step_latency_ms)
                if step_type == "tool_call":
                    TOOL_LATENCY_MS.labels(
                        tool=getattr(step, "tool_name", "unknown"),
                        release=release,
                    ).observe(step_latency_ms)
                # retry overhead peut exister meme si l'etape echoue
                retry_overhead_ms = float(getattr(step, "retry_overhead_ms", 0) or 0)
                if retry_overhead_ms > 0:
                    RETRY_OVERHEAD_MS.labels(release=release).observe(retry_overhead_ms)

            if step_type == "llm_generate":
                model = getattr(step, "model", "unknown")
                ttft_ms = float(getattr(result, "ttft_ms", 0) or 0)
                if ttft_ms > 0:
                    TTFT_MS.labels(model=model, release=release).observe(ttft_ms)

            if result and result.is_final:
                stop_reason = "completed"
                break
    finally:
        run_latency_ms = (time.perf_counter() - started_at) * 1000
        RUN_LATENCY_MS.labels(release=release).observe(run_latency_ms)
        RUN_TOTAL.labels(status=run_status, stop_reason=stop_reason, release=release).inc()

# run_latency_p95 et run_latency_p99 sont generalement calcules au niveau dashboard :
# histogram_quantile(...) sur les bucket-metrics agent_run_latency_ms.

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

Segmentp50 latencyp95 latencytimeout_rateStatut
gpt-4.1 + tools1.1s4.8s2.9%critical: SLO risk
mini-model + cache420ms1.2s0.4%ok
research workflow1.7s6.1s1.8%warning: p95 augmente

Investigation

Quand une alerte de latency se declenche :

  1. trouver le segment anormal (release, tool, model) ;
  2. regarder les runs lents dans le tracing ;
  3. verifier retries, timeout et stop_reason dans les logs ;
  4. trouver la root cause (tool, LLM, queue, logique agent, service externe).

Erreurs typiques

Meme si les metriques de latency existent, elles apportent souvent peu de valeur a cause des erreurs ci-dessous.

On regarde seulement la latency moyenne

La moyenne cache souvent la degradation. Pour la production, le minimum est p50 et p95, et pour les cas critiques aussi p99.

Pas de decoupage de latency par tools et step type

Sans cela, il est difficile de savoir ce qui est lent : LLM, tool ou boucle agent elle-meme. Dans ce cas, localiser vite un echec d'outil devient difficile.

Queue time est ignoree

Un run peut etre lent avant meme de commencer l'execution. Sans queue_time_p95, on rate facilement les problemes de capacity.

Pas de metriques timeout-rate et retry-overhead

Les retries peuvent masquer l'instabilite et gonfler artificiellement la latency. Cela arrive souvent avec spam d'outils.

Pas d'alertes sur p95/p99 et timeout spikes

Sans alertes, l'equipe apprend les problemes trop tard, quand le SLO est deja viole.

Auto-verification

Ci-dessous une checklist courte du latency monitoring 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 latency monitoring differe du monitoring classique de vitesse API ?
R : Pour les agents, il faut monitorer non seulement le temps de reponse global, mais aussi les etapes internes : reasoning, tools, retries, queue time.

Q : Quel minimum de metriques de latency faut-il au demarrage ?
R : Commencer avec run_latency_p50/p95, tool_latency_p95, timeout_rate et queue_time_p95.

Q : Pourquoi p95 est plus important que la latency moyenne ?
R : Parce que p95 montre ce qui se passe pour les requetes lentes, celles que les utilisateurs remarquent le plus.

Q : Comment separer un probleme de latency tools d'un probleme de latency LLM ?
R : Comparer tool_latency_p95 et ttft_p95 : si seule la tool-latency monte, le bottleneck est dans les tools ; si ttft monte, le probleme est dans la couche LLM.

Pages liees

Suite du sujet :

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