Votre agent appelle une API. L'API renvoie un 429. Votre agent réessaie immédiatement, obtient un autre 429, réessaie encore, et vous vous retrouvez avec une boucle qui martèle un service ralenti jusqu'à ce que l'exécution s'arrête ou que la facture explose. Personne n'a créé cette boucle intentionnellement. Elle découle de la version naïve de « gérer l'erreur », et c'est la chose la plus courante dont les développeurs parlent sur le forum de discussion du SDK Anthropic.
La récupération d'erreurs est la partie de la construction d'agents qui sépare une démo propre de quelque chose pour lequel vous devrez appeler quelqu'un. Le modèle n'est pas le problème. Le problème est ce que votre code fait lorsqu'un appel d'outil est lent, ralenti ou défectueux. Réussissez la récupération et une dépendance instable devient une courte pause que l'utilisateur ne remarque jamais. Échouez, et une seule erreur 500 se transforme en incident. Ce guide couvre les quatre modèles qui gèrent la majeure partie de la charge : les réessais avec backoff, les délais d'attente, les disjoncteurs et les clés d'idempotence. Il montre ensuite comment les tester contre un mock, avant qu'un utilisateur ne trouve les failles pour vous. Pour une vue d'ensemble de la manière dont les agents échouent, commencez par pourquoi les agents d'IA tombent en panne en production.
Vous ne pouvez pas tester la récupération contre une API saine
Voici le piège. Votre dépendance fonctionne très bien en développement. Vous écrivez votre agent, les appels réussissent, la démo est propre, et vous déployez. Le code de récupération n'a jamais été exécuté, car une API saine ne renvoie jamais les erreurs qu'elle est censée gérer. La première fois que votre logique de backoff s'exécute, c'est en production, lors d'une panne réelle, avec de vrais utilisateurs qui regardent. C'est le pire endroit pour découvrir une faute de frappe dans une boucle de réessai.
La règle est donc simple. Pour tester la récupération, vous provoquez volontairement les échecs. Mettez en place un mock de l'API que l'agent appelle, programmez-le pour qu'il renvoie un 429, un 500, un timeout, ou un corps malformé, dirigez l'agent vers lui, et observez ce qu'il fait. L'échec devient quelque chose que vous déclenchez lors d'un test au lieu de quelque chose qui vous déclenche à 3h du matin. Apidog met en place ce mock et script les réponses, et cela est abordé dans la section de test à la fin.
Réessai avec backoff exponentiel et jitter
Un réessai est la première ligne de défense, et la version naïve est le piège. Attrapez l'erreur, rappelez immédiatement. Contre un problème transitoire, cela fonctionne. Contre un service sous charge, cela aggrave les choses, car chaque client en échec réessaie au même instant et la ruée maintient le service en panne.
Deux corrections s'empilent. Le backoff exponentiel espace les tentatives : attendez 1 seconde, puis 2, puis 4, puis 8, en doublant jusqu'à un plafond. Le service a le temps de récupérer au lieu d'un mur de réessais immédiats. Le jitter ajoute un décalage aléatoire à chaque attente afin que mille clients qui ont tous échoué au même moment ne réessaient pas tous au même moment. Sans cela, le backoff produit toujours des vagues synchronisées.
Limitez deux choses : le délai, pour ne pas attendre des minutes entre les tentatives, et le nombre de tentatives, de sorte qu'un échec permanent abandonne au lieu de réitérer indéfiniment. Trois à cinq tentatives couvrent presque toutes les erreurs transitoires. Au-delà, vous réessayez généralement quelque chose qui ne réussira pas. Le SDK Anthropic effectue une partie de cela pour ses propres appels : il réessaie les erreurs de connexion et les codes d'état spécifiques avec un backoff exponentiel, et vous définissez le plafond avec une option `max-retries`. Il ne couvre pas les autres API que les outils de votre agent utilisent, vous devez donc les encapsuler vous-même. Les équipes qui gèrent de l'argent via leurs réessais l'apprennent tôt, et notre analyse de la logique de réessai pour les API à enjeux élevés montre où un réessai négligent cause de réels dommages.
Définir un délai d'attente pour chaque appel
Un réessai n'aide que si la requête échoue. Le cas le plus désagréable est une requête qui ne revient jamais : une dépendance accepte votre connexion, puis se bloque. Sans délai d'attente, l'appel d'outil se bloque et toute l'exécution est bloquée derrière une seule socket morte. Pas d'erreur, pas de récupération, seulement un agent bloqué qui brûle du temps réel et du budget de jetons pour rien.
Chaque appel sortant nécessite un délai d'attente. Définissez un délai de connexion pour établir la connexion et un délai de lecture pour attendre la réponse, puis un budget total pour l'exécution complète de l'agent afin qu'une chaîne d'appels lents mais légaux ne puisse pas dépasser la patience de l'utilisateur. Lorsqu'un délai d'attente se déclenche, traitez-le comme toute autre erreur réessayable : attendez et réessayez, jusqu'à votre limite.
Choisissez les chiffres à partir de la latence réelle, pas d'une estimation. Définissez chaque délai au-dessus du p99 de la dépendance avec une marge de sécurité. Trop serré et vous avortez des appels qui auraient réussi. Trop lâche et une dépendance bloquée retient l'agent bien au-delà du point d'utilité. Accordez aux réponses en streaming leur propre budget, car une longue complétion est légitimement lente et un court délai fixe la tue en plein milieu du flux.
Déclencher un disjoncteur lorsqu'une dépendance est en panne
Le backoff gère un service brièvement occupé. Ce n'est pas le bon outil pour un service qui est complètement en panne. Si une dépendance est en panne depuis une minute, la prochaine requête échouera presque certainement aussi, et la réessayer ajoute plus de charge à quelque chose déjà cassé pendant que l'utilisateur attend un échec que vous auriez pu prédire.
Un disjoncteur corrige cela avec trois états. Fermé est normal : les requêtes circulent et le disjoncteur compte les échecs. Lorsque les échecs dépassent un seuil, il passe à ouvert : il arrête d'envoyer des requêtes et échoue rapidement pendant une fenêtre de refroidissement, de sorte que vous ne payez pas le délai d'attente sur chaque appel à un service mort. Après la fenêtre, il passe à semi-ouvert et laisse passer une seule sonde. Si la sonde réussit, le disjoncteur se ferme et le trafic reprend ; si elle échoue, il s'ouvre à nouveau et attend.
Pour un agent, le disjoncteur transforme « l'API de paiement est en panne » en un échec rapide et propre que l'agent peut comprendre, au lieu de quarante délais d'attente lents qui épuisent le budget de jetons et le temps. Connectez-le par dépendance, pas globalement, afin qu'une API de recherche en panne n'empêche pas l'agent d'utiliser une API de facturation saine.
Sécuriser les réessais avec des clés d'idempotence
Chaque modèle jusqu'à présent suppose que la réinitialisation est sûre. Souvent, elle ne l'est pas. Votre agent envoie `POST /charge`, le serveur le traite, et la réponse expire en revenant. L'agent n'a jamais vu le succès, il réessaie donc, et maintenant le client est facturé deux fois. Le réessai a fait exactement ce que vous avez demandé. La conception était le bug.
Une clé d'idempotence comble cette lacune. Le client génère une clé unique par action logique et l'envoie avec la requête, généralement sous la forme d'un en-tête `Idempotency-Key`. Le serveur enregistre la clé lors de la première réception et, s'il voit la même clé à nouveau, renvoie le résultat original au lieu de faire le travail deux fois. Désormais, un réessai est sûr par construction : le deuxième `POST /charge` avec la même clé est une opération nulle qui renvoie la première charge.
La clé doit rester stable lors des réessais de la même action et changer entre différentes actions. Générez-la une seule fois lorsque vous construisez la requête, pas à l'intérieur de la boucle de réessai, sinon chaque tentative obtiendra une nouvelle clé et la déduplication ne se déclenchera jamais. Tout appel d'outil qui crée ou modifie un état (charges, commandes, e-mails, enregistrements) en a besoin. Notre guide sur les clés d'idempotence couvre en détail la génération et la gestion côté serveur.
Survivre aux limites de débit et à la boucle RateLimitError
Les limites de débit méritent une gestion spécifique car elles sont accompagnées d'instructions. Une réponse d'excès de limite de débit arrive généralement sous la forme d'un 429 avec un en-tête `Retry-After` qui vous indique exactement combien de temps attendre, en secondes ou sous forme de date. Respectez-la. Si le serveur dit d'attendre 30 secondes et que vous réessayez en 2 secondes, vous obtenez un autre 429, et vous avez créé la boucle RateLimitError qui remplit le forum de discussion du SDK : attrapez la limite, réessayez trop tôt, soyez plus sévèrement limité, répétez jusqu'à ce que l'exécution s'arrête. Un fil de discussion SDK distinct couvre le même problème que les développeurs rencontrent ici.
La solution est de laisser le serveur définir le rythme. Lorsque vous obtenez un 429, lisez `Retry-After` et attendez au moins cette durée avant de réessayer. Si l'en-tête est manquant, revenez au backoff exponentiel avec jitter. Limitez les tentatives afin qu'une limite soutenue se termine par un échec propre au lieu d'une attente infinie. Le SDK Anthropic respecte déjà `Retry-After` pour ses propres appels ; le travail consiste à appliquer la même règle aux autres API à débit limité que votre agent touche.
Il y a aussi un aspect proactif. Si un fournisseur autorise un certain nombre de requêtes par minute, mesurez vos propres appels avec un seau de jetons pour rester sous le plafond au lieu de le trouver en étant limité. La récupération gère les limites que vous atteignez ; le rythme vous empêche de les atteindre.
Comment tester le chemin de récupération
Maintenant, mettons tout cela ensemble. Les modèles ci-dessus ne sont valables que si vous avez la preuve qu'ils fonctionnent, et cette preuve est un test qui force les défaillances qu'une API saine ne vous donnera pas. La forme se répète dans chaque scénario :
- Mockez la dépendance. Mettez en place un mock de l'API que l'outil de votre agent appelle, afin de contrôler chaque code d'état, en-tête, corps et délai, et qu'aucune charge ou e-mail réel ne soit déclenché pendant le test.
- Programmez une séquence. Scriptez le mock pour répondre à une série d'appels dans l'ordre : d'abord un 429 avec `Retry-After: 2`, puis un 500, puis un 200 avec un corps valide. Un point de terminaison, trois réponses scriptées, un arc de récupération complet en une seule exécution.
- Dirigez l'agent vers le mock. Pointez l'outil de l'agent vers l'URL du mock au lieu du service réel et exécutez le scénario de bout en bout.
- Affirmez le comportement. Vérifiez ce qui compte : l'agent a attendu au moins 2 secondes après le 429 avant de réessayer, a réessayé après le 500, a réussi au troisième appel et n'a jamais dépassé votre limite de tentatives.
Ce seul scénario prouve le backoff et `Retry-After` en un seul passage. Ajoutez un deuxième scénario pour le chemin d'abandon : scriptez le mock pour qu'il échoue à chaque fois et assurez-vous que l'agent s'arrête à la limite et renvoie une erreur propre au lieu de boucler. Ajoutez un troisième pour le disjoncteur : faites échouer suffisamment d'appels d'affilée et assurez-vous que l'agent se déclenche et échoue rapidement au lieu de payer un délai d'attente à chaque tentative.
La vérification d'idempotence est celle que les gens oublient, et c'est celle qui permet d'économiser de l'argent. Scriptez le mock pour qu'il accepte un appel modificateur, supprimez la réponse afin que l'agent pense qu'il a échoué, puis acceptez le réessai. Maintenant, vérifiez la forme de la requête : les deux requêtes portaient la même `Idempotency-Key`, et le mock a vu une seule action logique, pas deux. Une nouvelle clé lors du réessai, ou un appel en double, signifie que vous avez trouvé un double envoi avant qu'un client ne le fasse. La méthode plus large pour tester les agents qui appellent vos API met en place le harnais de bout en bout.
La liste de contrôle de la récupération d'erreurs
Avant qu'un agent ne passe en production, parcourez cette liste :
- Chaque appel sortant a un délai de connexion, un délai de lecture et un budget d'exécution total.
- Les réessais utilisent un backoff exponentiel avec jitter, plafonné à la fois en délai et en nombre de tentatives.
- Les réponses 429 lisent et respectent `Retry-After`, avec le backoff comme solution de repli.
- Un disjoncteur se déclenche par dépendance afin qu'un service en panne échoue rapidement au lieu de boucler.
- Chaque appel modifiant l'état porte une clé d'idempotence stable qui survit aux réessais.
- Le chemin d'abandon renvoie une erreur propre, pas une attente infinie.
- Chacun de ces points est prouvé par un test qui force la défaillance contre un mock, et non pas supposé.
Cochez les sept points et votre agent se rétablira volontairement au lieu de par chance.
Où Apidog s'intègre (et où il ne s'intègre pas)
Gardez le rôle de l'outil honnête. Apidog n'est pas un framework d'agent, un hébergeur de modèle ou un environnement d'exécution. Il ne construit pas, n'exécute pas ou n'orchestre pas votre agent, et il n'évalue pas la sortie du modèle. Ce qu'il gère, c'est la couche API que votre agent appelle, et c'est précisément là que la récupération est gagnée ou perdue.

Cela lui donne trois fonctions. Il simule les dépendances que votre agent utilise, de sorte que vous obtenez un substitut contrôlable au lieu du service en direct. Il programme les réponses d'échec (429 avec `Retry-After`, 500, timeout, corps malformé) qu'une API réelle ne produira pas sur commande, afin que vous puissiez répéter la récupération. Et il valide les requêtes que le mock reçoit (clé d'idempotence présente et stable, forme correcte, nombre d'appels attendu) afin qu'un double envoi ou un en-tête manquant échoue à un test au lieu d'un client. C'est l'intégration honnête : Apidog simule les échecs auxquels votre agent doit survivre et vérifie ce qu'il renvoie.
Foire aux questions
Le SDK Anthropic ne gère-t-il pas les réessais pour moi ? Pour ses propres appels, oui. Le SDK réessaie certaines erreurs avec un backoff exponentiel et respecte `Retry-After`, et vous définissez le plafond avec une option `max-retries`. Il ne couvre pas les autres API que les outils de votre agent appellent. Ces dernières nécessitent l'application des mêmes modèles par vos soins.
Quand ai-je besoin d'une clé d'idempotence ? Sur tout appel qui crée ou modifie un état : charges, commandes, messages envoyés, nouveaux enregistrements. Les appels en lecture seule peuvent être réessayés en toute sécurité sans clé. Générez la clé une fois par action afin qu'elle reste stable lors des réessais.
Répétez un échec cette semaine
Vous n'avez pas à construire les quatre modèles à la fois. Choisissez celui qui ferait le plus de dégâts, généralement la boucle de limite de débit ou un réessai non-idempotent, et répétez-le contre un mock. Programmez le 429, supprimez une réponse, et observez ce que l'agent envoie. La première fois que vous verrez un backoff propre et une seule clé d'idempotence là où vous craigniez un double paiement, vous ferez confiance à l'agent pour une meilleure raison qu'une démo réussie.
Téléchargez Apidog pour simuler les échecs, script les séquences et vérifier ce que fait votre agent lorsque l'API résiste.
