DEV Community

Silviu Technology
Silviu Technology

Posted on

Agentes LLM: presupuesto para cada herramienta

Un agente LLM puede parecer rápido en una demo porque solo llama una herramienta y termina. En producción, la misma tarea puede consultar un API, esperar un correo de verificación, reintentar y pedir una segunda validación. El problema ya no es solamente qué herramienta elegir: es cuánto presupuesto puede consumir cada llamada.

En mis automatizaciones prefiero tratar ese presupuesto como un contrato visible. El agente recibe un límite de tiempo, intentos y coste aproximado; el adaptador de herramientas decide cómo aplicarlo. Así un modelo puede razonar sobre una tarea sin tener permiso implícito para consumir recursos sin fin.

El problema: herramientas sin presupuesto

Imagina un agente que crea una cuenta de prueba y espera un mensaje. El recorrido es parecido a este:

modelo → crear identidad → esperar inbox → leer código → confirmar resultado

Si el inbox tarda, el modelo puede volver a preguntar. Si el servicio responde con un error ambiguo, puede reintentar otra vez. Un caso como fake e mail com en una entrada de usuario o un dominio mal escrito como temp gamil com no debería convertir el flujo en una cadena de llamadas costosas.

Sin un límite por herramienta suelen aparecer tres síntomas:

  • la latencia total crece aunque cada llamada individual parezca razonable;
  • los reintentos ocultan un fallo de contrato y duplican efectos secundarios;
  • nadie sabe si el coste proviene del modelo, del proveedor externo o del polling.

El agente necesita un límite global, pero también límites locales. Un presupuesto de 60 segundos para toda la tarea no explica cómo repartir esos segundos entre una consulta y cinco esperas.

El presupuesto como contrato

Un contrato mínimo puede describirse así:

{
  "task_budget": {
    "deadline_ms": 60000,
    "max_tool_calls": 8,
    "max_estimated_cost": 0.04
  },
  "tools": {
    "create_test_account": {"timeout_ms": 5000, "max_attempts": 1},
    "read_inbox": {"timeout_ms": 8000, "max_attempts": 3},
    "confirm_code": {"timeout_ms": 5000, "max_attempts": 1}
  }
}
Enter fullscreen mode Exit fullscreen mode

El valor importante no es que los números sean perfectos. Es que estén declarados antes de ejecutar y que cada adaptador pueda rechazar una llamada cuando el presupuesto ya no alcanza. Un timeout local debe respetar el deadline global; de lo contrario, tres herramientas pueden consumir 60 segundos cada una en una tarea que solo tenía un minuto.

La respuesta del adaptador también debe ser explícita: ok, timeout, budget_exhausted o unknown. Esta última opción importa para una operación con efectos secundarios. Un timeout no prueba que el servidor no haya actuado.

Un modelo de datos pequeño

Para depurar el flujo guardo un recibo por intento, no una copia completa del prompt:

{
  "run_id": "agent_91a",
  "tool_call_id": "call_04",
  "tool": "read_inbox",
  "attempt": 2,
  "deadline_remaining_ms": 17300,
  "status": "timeout",
  "duration_ms": 8004,
  "input_hash": "sha256:..."
}
Enter fullscreen mode Exit fullscreen mode

Con este dato puedo responder preguntas operativas: ¿se agotó el tiempo antes de consultar?, ¿cuántos intentos usó el polling?, ¿qué herramienta consumió el presupuesto? Para detalles de integración conviene separar el recorrido del agente de los contratos de email; por ejemplo, los contratos de email para pruebas repetibles pueden ser una frontera útil para el inbox.

También mantengo los límites fuera del prompt del modelo. El modelo puede proponer “esperar un poco más”, pero el runtime debe decidir si quedan recursos. El prompt es una guía; el adaptador es la autoridad.

Cómo repartir tiempo y reintentos

Hay tres reglas que funcionan bien como punto de partida:

  1. Reservar una parte para la salida. Si todas las herramientas consumen el deadline, el agente no tendrá tiempo para explicar el resultado.
  2. No reintentar errores de validación. Un dominio inválido o un código mal formado no mejora con otro intento.
  3. Reducir el polling progresivamente. Es mejor consultar tras 1, 2 y 4 segundos que golpear el inbox cada 200 milisegundos.

Para acciones idempotentes, el reintento puede usar el mismo tool_call_id. Para acciones que crean recursos, primero hay que consultar el estado o enviar una clave de idempotencia. Si no existe ninguna de las dos opciones, devolver unknown es más honesto que afirmar que falló.

Una matriz simple ayuda a revisar la arquitectura:

Herramienta Efecto secundario Reintento Evidencia mínima
Consultar inbox No Sí, limitado mensaje o timeout
Crear cuenta Sí Solo idempotente ID externo
Confirmar código Sí Normalmente no estado final

Implementación por checkpoints

Implementaría el diseño en cuatro checkpoints:

  • Límite: rechazar llamadas cuando deadline_remaining_ms sea cero.
  • Medición: registrar inicio, fin, intento y presupuesto restante.
  • Clasificación: distinguir errores reintentables, terminales y desconocidos.
  • Prueba: simular latencia, respuesta tardía, entrada inválida y duplicación.

En cada checkpoint debe existir una señal observable. Un contador de llamadas es útil, pero no alcanza: hace falta asociarlo con run_id y con el nombre de la herramienta. Para revisar patrones y ejemplos de publicación técnica, también se puede explorar pruebas de correo en DEV.to, aunque la implementación real debe conservar sus propios recibos.

Checklist final

  • ¿Hay un deadline global y un timeout por herramienta?
  • ¿El adaptador conoce el presupuesto restante antes de ejecutar?
  • ¿Se diferencian errores de entrada, timeouts y resultados desconocidos?
  • ¿Las acciones con efectos secundarios tienen idempotencia?
  • ¿El polling tiene un máximo de intentos y un intervalo creciente?
  • ¿Cada intento deja un recibo consultable sin guardar datos sensibles?
  • ¿El agente puede explicar que el presupuesto se agotó?

Conclusión

Un agente confiable no es el que siempre insiste hasta obtener una respuesta. Es el que sabe cuánto puede gastar, qué evidencia debe dejar y cuándo detenerse. Convertir tiempo, intentos y coste en un contrato pequeño hace que las herramientas sean más previsibles; además, permite cambiar el modelo sin perder el control del sistema.

Top comments (0)