Défaillance d’outil : quand les outils de l’agent tombent en panne

Une défaillance d’outil apparaît quand des API ou outils externes échouent, expirent ou répondent de façon instable. Comment la gérer correctement.
Sur cette page
  1. Problème
  2. Pourquoi cela arrive
  3. Pannes les plus fréquentes
  4. Transient failures
  5. Wrong retry classification
  6. Tool contract drift
  7. Cascading failure
  8. Comment détecter ces problèmes
  9. Comment distinguer tool failure d'une erreur de logique d'agent
  10. Comment arrêter ces pannes
  11. Où c'est implémenté dans l'architecture
  12. Checklist
  13. FAQ
  14. Pages liées

Problème

La demande semble standard : vérifier un paiement et confirmer le statut d'une commande.

Dans les traces, c'est autre chose : en 9 minutes, un run a fait 29 appels d'outils (billing.get_invoice - 18, payments.verify - 11), et la plupart ont fini en timeout ou 5xx. Pour ce type de tâche, cela peut coûter ~$2.50 au lieu des ~$0.12 habituels.

Le service n'est pas formellement "mort" : une partie des appels renvoie 200. Mais l'utilisateur n'obtient pas de réponse finale, et le backlog des runs ainsi que la latence augmentent.

Le système ne crash pas.

Il reste bloqué entre erreurs d'outils et retries, en accumulant progressivement latence et backlog des runs.

Analogie : imagine un coursier qui arrive devant un dépôt fermé, rappelle, attend, rappelle encore et revient toujours à la même porte. Il est en permanence "en cours", mais la commande n'avance pas. Un tool failure chez les agents ressemble à cela : des actions, pas de résultat.

Pourquoi cela arrive

Le tool failure ne vient pas uniquement d'une API instable.

Le plus souvent, le problème principal est l'absence de stratégie claire dans la runtime pour classifier et traiter les erreurs d'outils.

En production, cela ressemble généralement à ceci :

  1. un service externe renvoie timeout, 5xx ou un payload instable ;
  2. la runtime ou le tool gateway retry sans classification claire de l'erreur ;
  3. des erreurs non-retryable entrent aussi dans des boucles de retries ;
  4. sans circuit breaker ni fallback, le run se bloque ou brûle du budget.

Le problème n'est pas une erreur API isolée. Le problème est que le système n'arrête pas la vague d'échecs avant qu'elle ne devienne un incident.

Ce type d'incident est généralement appelé agent tool failure - quand un système d'agents ne peut pas fonctionner de manière stable à cause de l'instabilité ou d'erreurs d'outils externes.

Pannes les plus fréquentes

Pour rester pratique, en production on voit surtout quatre patterns de tool failure.

Transient failures

L'outil renvoie parfois 408/429/5xx. Si le contrôle des retries est faible, une panne courte devient un retry storm.

Cause typique : absence de backoff+jitter et de retry budget.

Wrong retry classification

401, 403, 404, 409, schema validation errors ou policy denials partent en retries, alors qu'il faudrait arrêter immédiatement.

Cause typique : retryable et non-retryable ne sont pas séparés au même endroit.

Tool contract drift

L'outil change le format de réponse ou la structure d'erreur. L'agent n'interprète plus le résultat de façon stable et recommence à "requestionner" le même service.

Cause typique : pas de versioning du contrat et pas de validation de payload dans le gateway.

Cascading failure

Un outil problématique augmente la latence de tout le système : les workers attendent, la file grossit, les autres runs ralentissent aussi.

Cause typique : absence de circuit breaker et de fallback pour des dependencies dégradées.

Comment détecter ces problèmes

Le tool failure est bien visible avec la combinaison des métriques runtime et gateway.

MétriqueSignal de tool failureAction
tool_error_ratehausse brutale des 4xx/5xx/timeoutactiver degraded mode et vérifier la dépendance
retry_attempts_per_calltrop de retries pour un appellimiter le retry budget, ajouter backoff+jitter
non_retryable_retry_rateretries de 401/403/404/409/422arrêter le run immédiatement avec stop reason explicite
circuit_open_ratecircuit breaker s'ouvre fréquemmentvérifier SLA de l'outil et scénario de fallback
queue_backlogla file grossit avec un trafic normalvider les runs bloqués et réduire le fan-out

Comment distinguer tool failure d'une erreur de logique d'agent

Chaque run en échec ne veut pas dire que l'agent "pense mal". Le critère clé : où exactement la boucle se casse.

Normal si :

  • l'erreur est localisée à un outil externe ;
  • le stop reason pointe directement la dépendance (tool_timeout, tool_5xx, circuit_open) ;
  • après fallback, l'utilisateur reçoit un résultat partiel mais correct.

Dangereux si :

  • l'agent retry des erreurs non-retryable comme retryable ;
  • il n'y a pas de stop reasons claires au niveau tool gateway ;
  • l'échec d'un outil entraîne tout le workflow.

Comment arrêter ces pannes

En pratique, cela ressemble à ceci :

  1. classifier les erreurs d'outils en retryable et non-retryable ;
  2. garder retry policy dans un seul tool gateway (backoff+jitter + budget) ;
  3. poser un circuit breaker contre les vagues d'échecs ;
  4. en cas d'outil indisponible, retourner fallback/partial et stop reason.

Garde minimale pour les erreurs d'outils :

PYTHON
from dataclasses import dataclass
import time


RETRYABLE = {408, 429, 500, 502, 503, 504}
NON_RETRYABLE = {400, 401, 403, 404, 409, 422}


@dataclass(frozen=True)
class ToolFailureLimits:
    max_retry: int = 2
    open_circuit_after: int = 3
    circuit_cooldown_s: int = 20


class ToolFailureGuard:
    def __init__(self, limits: ToolFailureLimits = ToolFailureLimits()):
        self.limits = limits
        self.fail_streak = 0
        self.circuit_open_until = 0.0

    def before_call(self) -> str | None:
        if time.time() < self.circuit_open_until:
            return "tool_unavailable:circuit_open"
        return None

    def on_result(self, status_code: int, attempt: int) -> str | None:
        if status_code in NON_RETRYABLE:
            self.fail_streak = 0
            return "tool_failure:non_retryable"

        if status_code in RETRYABLE:
            self.fail_streak += 1
            if self.fail_streak >= self.limits.open_circuit_after:
                self.circuit_open_until = time.time() + self.limits.circuit_cooldown_s
                return "tool_unavailable:circuit_open"
            if attempt >= self.limits.max_retry:
                return "tool_failure:retry_exhausted"
            return "tool_retry:allowed"

        self.fail_streak = 0
        return None

C'est une garde de base. En production, on l'étend généralement avec des limites par outil et un backoff exponentiel avec jitter. attempt est généralement 1-based (1, 2, 3...), et l'état du guard est souvent conservé par tool ou par run.

Où c'est implémenté dans l'architecture

En production, le contrôle des tool failures est presque toujours réparti sur trois couches du système.

Tool Execution Layer est le point de contrôle principal : validation des args et payload, retry policy, classification des erreurs, circuit breaker. Si cette couche est faible, un problème API simple devient vite une cascade.

Agent Runtime gère le cycle de vie du run : stop reasons, timeout, fin contrôlée et réponse fallback. Ici, il est essentiel de ne pas poursuivre un run à tout prix.

Policy Boundaries définit quels outils sont autorisés et quand un run doit se terminer en fail-closed. C'est particulièrement important pour les write-tools et les erreurs de permission.

Checklist

Avant de shipper un agent en production :

  • [ ] les erreurs retryable/non-retryable sont séparées explicitement ;
  • [ ] les retries sont implémentés dans un seul gateway, pas dans plusieurs couches ;
  • [ ] max_retry, backoff+jitter et retry budget sont définis ;
  • [ ] circuit breaker et cooldown sont réglés pour chaque outil critique ;
  • [ ] les stop reasons couvrent timeout, 5xx, non_retryable, circuit_open ;
  • [ ] la réponse fallback/partielle est définie avant incident ;
  • [ ] alertes sur tool_error_rate, retry_attempts_per_call, queue_backlog ;
  • [ ] un runbook existe pour le degraded mode et le rollback des dépendances.

FAQ

Q : Est-ce suffisant d'augmenter le timeout de l'outil problématique ?
R : Non. Cela masque souvent le problème et augmente la latence. Il faut error classification, retry budget et circuit breaker.

Q : Où doivent vivre les retries ?
R : Dans un choke point unique, généralement le tool gateway. Des retries dans plusieurs couches créent presque toujours de l'amplification.

Q : Quelles erreurs sont généralement non-retryable ?
R : 401, 403, 404, 409, 422, schema validation errors et policy denials. Ces runs doivent en général être stoppés immédiatement avec stop reason explicite.

Q : Que montrer à l'utilisateur quand un outil est indisponible ?
R : La raison de l'arrêt, ce qui a déjà été vérifié, et la prochaine étape sûre : fallback, résultat partiel ou escalade manuelle.


Un tool failure ressemble rarement à une grosse panne unique. Le plus souvent, c'est une série de petits échecs qui s'accumulent en boucles de retries et en file d'attente. C'est pourquoi les agents de production ont besoin non seulement d'outils, mais aussi d'une discipline stricte d'exécution.

Pages liées

Si ce problème apparaît en production, il est aussi utile de voir :

⏱️ 8 min de lectureMis à jour 12 mars 2026Difficulté: ★★☆
Implémenter dans OnceOnly
Guardrails for loops, retries, and spend escalation.
Utiliser dans OnceOnly
# onceonly guardrails (concept)
version: 1
budgets:
  max_steps: 25
  max_tool_calls: 12
  max_seconds: 60
  max_usd: 1.00
policy:
  tool_allowlist:
    - search.read
    - http.get
controls:
  loop_detection:
    enabled: true
    dedupe_by: [tool, args_hash]
  retries:
    max: 2
    backoff_ms: [200, 800]
stop_reasons:
  enabled: true
logging:
  tool_calls: { enabled: true, store_args: false, store_args_hash: true }
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)
  • Kill switch & arrêt incident
  • Audit logs & traçabilité
  • Idempotence & déduplication
  • Permissions outils (allowlist / blocklist)
Mention intégrée : OnceOnly est une couche de contrôle pour des systèmes d’agents en prod.
Exemple de policy (concept)
# Example (Python — conceptual)
policy = {
  "budgets": {"steps": 20, "seconds": 60, "usd": 1.0},
  "controls": {"kill_switch": True, "audit": True},
}
Auteur

Cette documentation est organisée et maintenue par des ingénieurs qui déploient des agents IA en production.

Le contenu est assisté par l’IA, avec une responsabilité éditoriale humaine quant à l’exactitude, la clarté et la pertinence en production.

Les patterns et recommandations s’appuient sur des post-mortems, des modes de défaillance et des incidents opérationnels dans des systèmes déployés, notamment lors du développement et de l’exploitation d’une infrastructure de gouvernance pour les agents chez OnceOnly.