Concevoir des erreurs d’API exploitables par les agents IA
Votre API renvoie 400 Bad Request avec {"error": "invalid input"}. Un développeur humain ouvre la documentation, trouve le champ manquant et corrige la requête. Un agent, lui, ne peut pas agir : il répète la même requête, échoue encore, puis déclare que l’API est cassée.
Essayez Apidog dès aujourd’hui
Les erreurs sont l’interface dont les agents dépendent le plus — et que les API documentent souvent le moins. Une réponse utile doit indiquer :
-
Qui doit corriger le problème ?
-
4xx: la requête doit changer. -
5xx: le serveur a échoué ; une nouvelle tentative peut réussir.
-
-
Faut-il réessayer, et quand ?
-
429: réessayer après un délai. -
409: relire l’état avant de réessayer. -
422: modifier la charge utile avant de renvoyer la requête.
-
Que faut-il modifier exactement ?
Ne dites pas seulement « validation failed ». Dites :
customer.postal_code est requis lorsque country vaut US.
Pour la logique côté client — nouvelles tentatives, backoff et coupe-circuits — consultez notre guide sur la récupération d’erreurs d’agent. Cet article traite du contrat que votre API doit fournir.
Utilisez un format d’erreur structuré
N’inventez pas une structure différente par endpoint. Adoptez RFC 9457 — Problem Details for HTTP APIs, puis ajoutez les champs dont un agent a besoin :
{
"type": "https://api.example.com/errors/validation-failed",
"title": "Validation failed",
"status": 422,
"detail": "The field 'customer.postal_code' is required when 'country' is 'US'.",
"instance": "/v1/orders",
"errors": [
{
"field": "customer.postal_code",
"code": "required_conditional",
"message": "Required when country is US. Provide a 5-digit or 9-digit US postal code.",
"example": "94107"
}
],
"retryable": false,
"next_action": "Add customer.postal_code to the request body and send again."
}
Les champs les plus importants sont les suivants :
-
detail: une phrase complète qui décrit la règle réellement violée. -
errors: une liste structurée, avec un chemin de champ par problème. Retournez toutes les erreurs de validation en une réponse. -
retryable: un booléen explicite. Ne forcez pas l’agent à déduire ce comportement à partir du statut HTTP. -
next_action: une instruction directe indiquant la prochaine action.
Le guide de conception des erreurs d’API de Google recommande également d’exposer les détails dans une structure lisible par machine plutôt que dans une phrase ambiguë.
Indiquez précisément quand réessayer
Pour tout problème transitoire, fournissez un délai. Sans cela, l’agent choisira un délai arbitraire — souvent trop court.
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/problem+json
{
"type": "https://api.example.com/errors/rate-limited",
"title": "Rate limit exceeded",
"status": 429,
"detail": "You have used 1000 of 1000 requests in the current minute window.",
"retryable": true,
"retry_after_seconds": 30,
"next_action": "Wait 30 seconds before sending this request again. Do not retry sooner."
}
L’en-tête Retry-After accepte un délai en secondes ou une date HTTP. Préférez les secondes : elles sont plus simples à exploiter.
Envoyez le délai à deux endroits :
- dans l’en-tête HTTP pour les clients standards ;
- dans le corps JSON pour l’agent.
Appliquez le même modèle aux 503 de maintenance et aux 409 liés à un verrou. Si attendre est la bonne action, retournez un nombre.
Pour aller plus loin, consultez le guide sur le dépassement de limite de débit et celui expliquant comment implémenter la limitation de débit d’API.
Ne révélez pas l’interne, mais ne renvoyez jamais une erreur vide
Évitez deux extrêmes :
- La trace de pile : elle peut exposer des versions de framework, chemins de fichiers, requêtes ou secrets. Elle encombre aussi le contexte de l’agent sans lui donner une action utile.
-
L’erreur vide : un
500sans corps, ou{"error": true}, ne permet ni de récupérer ni d’escalader correctement.
Retournez plutôt une erreur publique stable avec un identifiant de corrélation :
{
"type": "https://api.example.com/errors/internal",
"title": "Internal error",
"status": 500,
"detail": "The order could not be created due to an internal error. No order was created.",
"retryable": true,
"retry_after_seconds": 5,
"request_id": "req_01J8ZK3M2Q",
"next_action": "Retry once after 5 seconds. If it fails again, stop and report request_id req_01J8ZK3M2Q."
}
La phrase « No order was created » est essentielle. Lorsqu’une écriture échoue de manière ambiguë, l’agent doit savoir si une nouvelle tentative risque de créer un doublon.
Si vous ne pouvez pas garantir l’état final, rendez l’opération idempotente et documentez-le. Le modèle est détaillé dans notre article sur les clés d’idempotence pour les agents IA.
Le champ request_id doit correspondre à vos journaux et traces. Reliez-le à une stratégie d’observabilité des API afin qu’une personne puisse diagnostiquer l’échec rapidement.
Documentez les erreurs dans OpenAPI
Une erreur absente de votre document OpenAPI est invisible pour les clients générés, les mocks et les outils d’agent.
responses:
'201':
description: Order created
content:
application/json:
schema: { $ref: '#/components/schemas/Order' }
'422':
description: >
Validation failed. Not retryable without changing the request body.
The errors array names each invalid field.
content:
application/problem+json:
schema: { $ref: '#/components/schemas/Problem' }
'429':
description: >
Rate limited. Retryable. Wait for retry_after_seconds before sending again.
content:
application/problem+json:
schema: { $ref: '#/components/schemas/Problem' }
Ces descriptions guident directement le comportement du modèle lorsque vous générez des outils depuis une spécification. Une explication telle que « retryable, wait first » est plus utile que « Too many requests ».
Consultez notre guide sur la transformation d’une spécification OpenAPI en outils d’agent.
Testez les erreurs aussi systématiquement que les succès
Les chemins d’erreur régressent facilement : un refactoring de sérialiseur peut casser un champ critique sans affecter le chemin nominal.
Définissez les réponses d’échec dans votre projet Apidog, simulez-les, puis enregistrez les scénarios pour la CI. Exécutez au minimum ces cinq cas :
Validation multi-champs
Vérifiez que tous les problèmes sont retournés dans une seule réponse et corrigés en une seule nouvelle tentative.Limite de débit
Vérifiez que l’agent attend au moinsretry_after_seconds.Erreur serveur pendant une écriture
Vérifiez qu’une nouvelle tentative ne crée pas silencieusement de doublon.Échec d’authentification
Vérifiez que l’agent s’arrête : attendre ne réparera jamais un jeton invalide. Consultez le guide sur les clés API à privilège minimum pour les agents IA.Corps d’erreur malformé
Retournez un corps non JSON et vérifiez que l’agent se dégrade proprement. Les proxys en amont finiront par produire ce cas.
L’exécution d’agents contre des mocks plutôt que contre la production est détaillée dans notre article sur les agents IA et les API simulées.
Ne forcez pas l’agent à interpréter de la prose
Cet anti-modèle est courant :
{ "message": "Sorry, that didn't work. Please check your details and try again." }
Il oblige l’agent à deviner la cause et la correction. Pire : certaines API retournent cette erreur avec un statut 200, ce qui masque l’échec aux politiques de retry, aux tableaux de bord et aux alertes.
Appliquez deux règles :
- Donnez à chaque échec un code stable et lisible par machine, comme
insufficient_fundsourequired_conditional. - Ne retournez jamais une erreur avec un statut de succès.
Concevez aussi l’escalade humaine
Certaines erreurs ne sont pas récupérables : portée manquante, compte fermé, politique nécessitant une décision humaine. Dans ce cas, l’erreur doit :
- expliquer le blocage ;
- indiquer l’action humaine attendue ;
- fournir un
request_id.
Cette réponse doit apparaître là où une personne la consultera. Par exemple, Sharkly conserve le résultat et la trace d’exécution d’un agent sur la tâche, puis dirige les cas nécessitant une réponse ou une revue vers une boîte de réception. Une erreur précise transforme alors l’escalade en travail actionnable plutôt qu’en recherche dans les logs.
Liste de contrôle
- [ ] Toutes les erreurs utilisent une structure cohérente.
- [ ]
detailcite le champ ou la condition exacte. - [ ] Les erreurs de validation retournent tous les problèmes, avec leurs chemins de champs.
- [ ] Chaque erreur contient
retryable. - [ ] Les erreurs récupérables donnent un délai, dans l’en-tête et dans le corps.
- [ ] Les échecs d’écriture indiquent si une ressource a été créée ou modifiée.
- [ ] Chaque réponse contient un identifiant de corrélation exploitable dans les journaux.
- [ ] Aucune trace de pile, chaîne de framework ou requête SQL n’est exposée.
- [ ] Les réponses d’erreur sont décrites dans OpenAPI.
- [ ] Chaque erreur importante possède un mock et un test CI.
De meilleures erreurs réduisent les tentatives inutiles, les escalades et le temps de débogage. Elles aident aussi les développeurs humains.
Téléchargez Apidog pour définir, simuler et tester vos réponses d’erreur avant qu’un agent ne les rencontre en production.
Questions fréquentes
Dois-je utiliser RFC 9457 ou mon propre format d’erreur ?
Utilisez RFC 9457, sauf si vous possédez déjà un format cohérent en production. La cohérence est plus importante que la standardisation partielle. Ajoutez retryable et next_action au format existant si nécessaire.
Le champ next_action est-il sûr ?
Oui, s’il est généré par votre service à partir de modèles fixes. N’y reproduisez jamais du contenu fourni par l’utilisateur : un agent pourrait l’interpréter comme une instruction. Consultez notre guide sur le test d’API contre les entrées non fiables.
Dois-je utiliser 400 ou 422 pour la validation ?
Utilisez 400 pour une requête mal formée, comme un JSON invalide. Utilisez 422 lorsque la requête est correctement analysée mais viole une règle métier. Si votre API utilise déjà un seul code pour les deux, documentez clairement cette convention.
Quel niveau de détail est acceptable ?
Donnez suffisamment d’informations pour agir : nom du champ, règle et exemple de valeur. N’exposez pas d’identifiants internes, de texte de requête ni de pile d’exécution.
Les erreurs comptent-elles dans la fenêtre de contexte ?
Oui. Une erreur longue et répétée lors de plusieurs tentatives consomme rapidement le contexte. Gardez-la sous quelques centaines de jetons. Consultez notre guide sur la réduction des réponses d’API pour les agents.
Comment empêcher un agent de réessayer une erreur définitive ?
Retournez retryable: false, expliquez-le dans next_action, puis appliquez cette règle dans l’enveloppe de l’outil. Ne vous reposez pas uniquement sur le jugement du modèle.


Top comments (0)