Diseña errores de API sobre los que los agentes puedan actuar
Tu API devuelve 400 Bad Request con el cuerpo {"error": "invalid input"}. Un desarrollador humano abre la documentación, revisa la carga útil, detecta el campo que falta y lo corrige en un minuto. Un agente lee las mismas dos palabras, no tiene nada sobre lo que actuar y hace lo único que puede: envía la misma solicitud de nuevo. Y otra vez. Luego se rinde y le dice al usuario que la API está rota.
Las respuestas de error son la parte de una API de la que los agentes dependen más y que los equipos suelen diseñar al final. Un buen error explica qué salió mal, si reintentarlo podría ayudar y qué debe cambiar. Un error vago convierte un problema recuperable en una tarea fallida.
Esta guía cubre el lado de la API. La guía sobre recuperación de errores del agente explica lo que debe hacer el cliente con los reintentos, el retroceso y los interruptores de circuito. Aquí veremos qué debe devolver tu API para que esa lógica funcione.
Las respuestas de error suelen ser la parte menos probada de una API. Con Apidog puedes definirlas en la especificación, simularlas y verificarlas junto al camino feliz.
Las tres preguntas que debe responder un error
Cada error que recibe un agente debe permitirle responder estas preguntas sin adivinar:
¿Es mi culpa o tuya?
Un 4xx indica que la solicitud es incorrecta y repetirla sin cambios volverá a fallar. Un 5xx indica un problema del servidor y la misma solicitud podría funcionar más tarde.¿Debo reintentar y cuándo?
Un 429 se puede reintentar después de esperar. Un 409 puede requerir volver a leer el estado. Un 422 no se puede reintentar sin modificar la carga útil. Indícalo explícitamente.¿Qué debo cambiar exactamente?
Validation failedno basta.The field customer.postal_code is required when country is USsí describe una corrección que el agente puede aplicar.
Incluye estas tres respuestas en cada error y reducirás la mayoría de las tormentas de reintentos.
Usa un formato de error estructurado
No inventes un formato propio si no es necesario. RFC 9457, Problem Details for HTTP APIs, define uno ampliamente compatible:
{
"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."
}
Cuatro campos hacen gran parte del trabajo:
-
detail: una oración completa con el campo y la regla que fallaron en esta solicitud. -
errors: una entrada legible por máquina por cada problema, con una ruta que el agente pueda relacionar con la carga útil. Devuelve todos los fallos a la vez. -
retryable: un booleano explícito. No obligues al agente a inferirlo a partir del código de estado. -
next_action: una instrucción breve y concreta. Los modelos suelen seguir instrucciones explícitas de forma más fiable que deducirlas a partir de un código de error.
La guía de diseño de errores de API de Google llega a una conclusión similar: los detalles deben estar en una lista estructurada, no únicamente en prosa.
Indica cuándo reintentar
Para cualquier error transitorio, especifica el momento del siguiente intento. Un agente que sabe que debe esperar 30 segundos puede hacerlo; uno que no lo sabe elegirá un intervalo arbitrario, normalmente demasiado corto.
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."
}
El encabezado Retry-After acepta un retraso en segundos o una fecha HTTP. Los segundos suelen ser más fáciles de procesar.
Envíalo como encabezado para los clientes estándar y repítelo en el cuerpo para el modelo. La duplicación es barata y sirve a ambos consumidores.
El mismo patrón se aplica a un 503 durante mantenimiento o a un 409 causado por un recurso bloqueado: cualquier error donde esperar sea la respuesta correcta debe incluir una duración.
Consulta también la guía sobre exceder el límite de velocidad y la guía para implementar la limitación de velocidad de API.
Nunca filtres información interna ni devuelvas errores vacíos
Hay dos extremos que perjudican a los agentes.
El primero es el rastreo de la pila. Devolver excepciones internas puede revelar versiones de frameworks, rutas de archivos y fragmentos de consultas. Es un problema de seguridad y además llena la ventana de contexto con información sobre la que el modelo no puede actuar. Las recomendaciones para probar APIs contra entradas no confiables aplican directamente aquí.
El segundo es el error vacío: un 500 sin cuerpo o {"error": true}. El agente no aprende nada y solo puede reintentar o rendirse.
El punto medio es un error público estable con un ID de correlación:
{
"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 frase No order was created es especialmente importante. En una operación de escritura, el agente debe saber si reintentar puede crear un duplicado. Si no puedes garantizar el estado, haz la operación idempotente y documéntalo. Consulta la guía sobre claves de idempotencia para agentes de IA.
request_id permite encontrar la ejecución en los registros cuando un humano revise la transcripción. Combínalo con las prácticas de observabilidad de API.
Documenta los errores en OpenAPI
Si la forma de un error no aparece en tu documento OpenAPI, no existe para los clientes generados, las simulaciones ni las herramientas de agentes. No describas solo el 200: documenta también cada respuesta fallida.
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' }
Estas descripciones no son decoración. Cuando generas herramientas a partir de la especificación, como se explica en cómo convertir una especificación OpenAPI en herramientas de agente, el modelo lee ese texto para decidir qué hacer.
Retryable. Wait for retry_after_seconds before sending again produce un comportamiento mucho mejor que Too many requests.
Prueba los errores, no solo los éxitos
Las rutas de error suelen tener poca cobertura porque activarlas manualmente requiere esfuerzo. La simulación elimina ese obstáculo.
Define cada respuesta de error en tu proyecto de API y simúlala para que el agente pueda encontrarse con cada caso bajo demanda. En Apidog puedes añadir respuestas de fallo a la definición del endpoint y cambiar entre simulaciones de 422, 429 y 500 sin afectar datos reales.
La guía sobre ejecutar agentes contra simulaciones en lugar de producción desarrolla este patrón.
Construye al menos estos cinco escenarios:
- Validación con varios campos incorrectos: devuelve todos los problemas en una sola respuesta y comprueba que el siguiente intento los corrige todos.
-
Límite de velocidad: incluye una espera y verifica que el agente espera al menos
retry_after_seconds. - Error del servidor durante una escritura: comprueba que un reintento no crea un duplicado silenciosamente.
- Fallo de autenticación: verifica que el agente se detiene; esperar no arregla un token incorrecto. Consulta también la guía sobre claves de API de menor privilegio para agentes.
- Cuerpo de error mal formado: devuelve algo que no sea JSON válido y confirma que el agente se degrada correctamente. Los proxies ascendentes pueden producir este caso.
Guarda estos escenarios y ejecútalos en CI. El manejo de errores suele romperse al refactorizar un serializador, mientras la suite del camino feliz continúa pasando.
Mide el valor de los mejores errores
Las mejoras aparecen en tres métricas:
Menos reintentos desperdiciados
Ante {"error": "invalid input"}, un agente suele repetir la misma carga útil dos o tres veces antes de rendirse. Cada intento consume un turno de modelo y vuelve a incluir la conversación completa como contexto.
Nombrar el campo que falta suele producir una única solicitud corregida. La diferencia puede ser pasar de cuatro llamadas a dos en un fallo rutinario de validación.
Menos escalaciones
Un agente que no puede recuperarse entrega la tarea a un humano. Cada entrega evitable es un resultado costoso que la automatización debía prevenir. Los errores que explican la solución mantienen la ejecución dentro del flujo automático.
Depuración más rápida
request_id junto con un detail preciso convierte una búsqueda extensa en los registros en una sola consulta.
Hay un beneficio adicional: estas mejoras también ayudan a los desarrolladores humanos. Nadie se queja de que un mensaje de error sea demasiado específico sobre el campo incorrecto.
Diseña también para la escalada humana
Algunos errores son irrecuperables para el agente: un alcance faltante, una cuenta cerrada o una regla que requiere una decisión humana.
En esos casos, el error debe:
- Explicar qué ocurrió.
- Indicar qué debe hacer una persona.
- Incluir el ID de correlación.
- Llegar a un lugar que un humano revise.
Si el agente trabaja en tareas asignadas, la plataforma circundante suele ser el lugar adecuado. Sharkly conserva el resultado y el rastro de ejecución en la tarea y dirige los elementos que necesitan respuesta o revisión a una bandeja de entrada. Así, una ejecución bloqueada se convierte en trabajo visible, no en una línea perdida en un registro.
Un mensaje que dice invalid input no ayuda más al revisor que al agente. Un error específico sí.
No obligues al agente a analizar prosa
Un anti-patrón común es devolver una oración diferente para cada fallo:
{ "message": "Sorry, that didn't work. Please check your details and try again." }
El agente solo puede responder adivinando. El problema empeora si el servidor devuelve un 200 con un error dentro: las bibliotecas cliente, las políticas de reintento, los paneles y las alertas ni siquiera detectan el fallo.
Aplica estas dos reglas:
- Asigna a cada fallo un código estable y legible por máquina, como
insufficient_funds. - Nunca devuelvas un fallo con un código de estado de éxito.
Lista de verificación
- [ ] Todos los errores usan un formato estructurado consistente.
- [ ]
detailnombra el campo o la condición específicos. - [ ] Los errores de validación devuelven todos los problemas a la vez.
- [ ] Cada error incluye
retryable. - [ ] Los errores reintentables incluyen una espera en segundos, en el encabezado y en el cuerpo.
- [ ] Los fallos de escritura indican si algo fue creado o cambiado.
- [ ] Cada respuesta incluye un ID de correlación resoluble en los registros.
- [ ] No hay rastreos de pila, cadenas de framework ni SQL.
- [ ] Las respuestas de error están documentadas en OpenAPI.
- [ ] Existen simulaciones para cada error y las pruebas guardadas se ejecutan en CI.
Los errores son una interfaz. Diseñalos para el interlocutor que realmente tienes: cada vez más, un modelo que hará exactamente lo que le indique el cuerpo de tu respuesta.
Descarga Apidog para definir y simular tus respuestas de error antes de que un agente las encuentre en producción.
Preguntas frecuentes
¿Debo usar RFC 9457 o mi propio formato?
Usa RFC 9457, salvo que ya tengas un formato consistente en producción. La consistencia es más importante que cambiar parcialmente de estándar. Añade retryable y next_action al formato que ya utilices.
¿Es seguro incluir next_action en una respuesta de API?
Sí, si el servicio lo genera a partir de un conjunto fijo de plantillas. No repitas contenido proporcionado por el usuario en ese campo: el agente lo interpreta como una instrucción y podría convertirse en una ruta de inyección de prompts.
¿Los errores de validación deben ser 400 o 422?
Usa 400 cuando la solicitud está mal formada, como un JSON inválido, y 422 cuando la solicitud se puede analizar pero incumple reglas de negocio. Si ya utilizas un único código para ambos casos, documéntalo antes de cambiarlo.
¿Cuánto detalle es demasiado?
Incluye lo necesario para actuar: el nombre del campo, la regla y, normalmente, un ejemplo. Los identificadores internos, el texto de consultas y los rastreos de pila superan ese límite.
¿Los mensajes de error cuentan en la ventana de contexto?
Sí. Un error verboso repetido durante varios reintentos se acumula rápidamente. Mantén las respuestas por debajo de unos pocos cientos de tokens. Consulta la guía sobre recortar respuestas de API para agentes.
¿Cómo evito que un agente reintente un error no reintentable?
Establece retryable: false, indícalo en next_action y refuérzalo en el envoltorio de la herramienta. En este caso, la redundancia es una medida de seguridad.


Top comments (0)