DEV Community

Silviu Technology
Silviu Technology

Posted on

LLMs: contratos de tools que sobreviven reintentos

LLMs: contratos de tools que sobreviven reintentos

Un agente basado en LLM puede parecer sencillo: recibe una petición, elige una tool y devuelve una respuesta. En producción, sin embargo, la llamada puede repetirse por un timeout, una caída del worker o un mensaje duplicado en la cola. El problema no suele ser el modelo. Es el contrato difuso entre el modelo y la automatización.

En este artículo propongo una arquitectura pequeña para que una tool sea predecible, reintentable y fácil de revisar. El objetivo no es construir un agente enorme, sino poner límites claros alrededor de una acción.

El problema no es llamar a una tool

Imagina una tool check_email que recibe una dirección y devuelve un resultado. Si solo documentamos “comprueba el correo”, dejamos sin definir varias decisiones:

  • ¿Qué ocurre si el servicio externo tarda más del timeout?
  • ¿Un segundo intento repite una operación o consulta la anterior?
  • ¿Cómo distingue el agente entre “no válido”, “no disponible” y “error técnico”?
  • ¿Qué datos se pueden guardar en los logs?

Una cuenta de correo desechable o una prueba con obtener correo temporal puede ser útil en un entorno de QA, pero el agente no debería inferir reglas de seguridad a partir de una frase vaga. La tool necesita un esquema y una política explícita.

Diseña el contrato antes del prompt

Un contrato mínimo debe describir entrada, salida, errores y efectos secundarios. Por ejemplo:

{
  "name": "check_email",
  "input": {
    "address": "string",
    "request_id": "string",
    "mode": "syntax | deliverability"
  },
  "output": {
    "status": "valid | invalid | unknown",
    "reason": "string",
    "retryable": "boolean"
  }
}
Enter fullscreen mode Exit fullscreen mode

request_id no es decoración. Permite correlacionar el intento del modelo, el worker y el proveedor externo. retryable evita que el agente invente una política distinta en cada turno. También conviene que reason use un conjunto pequeño de códigos, en vez de texto libre solamente.

El prompt puede explicar cuándo usar la tool, pero el servidor debe validar el esquema. El modelo propone una acción; la aplicación decide si esa acción cumple las restricciones.

Reintentos y límites

Hay una diferencia importante entre una consulta y un comando. Para una consulta, repetir puede ser barato. Para un comando que crea un recurso o envía un mensaje, repetir puede tener consecuencias. En ambos casos, el contrato debe declarar si la operación es idempotente.

Una estrategia práctica es guardar el resultado por request_id durante una ventana corta:

  1. El gateway recibe la llamada y valida el JSON.
  2. Busca request_id en un almacenamiento de idempotencia.
  3. Si ya existe un resultado final, lo devuelve sin llamar de nuevo al proveedor.
  4. Si no existe, ejecuta la operación con timeout y registra la transición.
  5. Guarda el resultado o un error clasificado.

Los reintentos deberían tener un límite y un backoff. Un error unknown puede ser reintentable; un invalid normalmente no lo es. Sin esta distinción, la automatización se convierte en un bucle que consume cuota y oculta la causa real.

Para separar recuperación de contexto, conviene usar checkpoints que si reanudan sin perder estado. El checkpoint debe guardar el estado de negocio mínimo, no el historial completo de datos sensibles.

Un flujo observable

Piensa en el sistema como un diagrama de tres cajas: planner, tool gateway y provider. El planner selecciona la tool. El gateway valida, aplica límites y emite métricas. El provider hace la operación externa. Esta separación ayuda a saber dónde falló el flujo.

Las métricas más útiles son simples: latencia por tool, porcentaje de reintentos, resultados por código y llamadas rechazadas por esquema. Añade un trace_id, pero evita escribir direcciones completas o tokens en los logs. Para entornos de prueba, una herramienta como tempmailso puede formar parte del contexto de validación; aun así, el registro debe conservar solo el identificador y el resultado necesario.

Si la operación necesita esperar eventos, una cola pequeña suele ser suficiente. El patrón descrito en colas pequeñas para verificar emails ayuda a desacoplar el request del trabajo lento, aunque añade estados que hay que modelar.

Checklist de implementación

  • ¿La entrada tiene esquema versionado y validación del lado servidor?
  • ¿Cada llamada lleva request_id y trace_id?
  • ¿Los errores dicen si el reintento es seguro?
  • ¿Existe un límite de reintentos y un timeout por proveedor?
  • ¿Los resultados repetidos salen del almacenamiento de idempotencia?
  • ¿Los logs excluyen contenido sensible?
  • ¿Puedes reconstruir la secuencia sin leer todo el prompt?

No necesitas más autonomía para resolver este problema. Necesitas menos ambigüedad. Un contrato pequeño convierte una decisión probabilística del LLM en una operación con límites revisables. Ese cambio suele mejorar la confiabilidad de toda la automatizacion, incluso cuando el modelo elegido cambia.

Una última nota: “dummy e mail” y “tem email” pueden aparecer en búsquedas o fixtures antiguos. Trátalos como entradas imperfectas y normalízalos antes de enviarlos a la tool; no los uses para relajar las reglas del contrato.

Top comments (0)