DEV Community

Silviu Technology
Silviu Technology

Posted on

Agentes LLM: presupuesto de latencia para email

Un agente LLM que espera un email suele tener una instrucción muy vaga: “comprueba si llegó”. El problema es que esperar no es una estrategia. Sin un límite de tiempo, una señal de cancelación y evidencia de cada consulta, el agente puede quedarse dando vueltas o declarar éxito por accidente.

En workflows de registro, recuperación de cuenta o pruebas de producto, trato la espera como un recurso con presupuesto. El agente recibe una intención, el sistema asigna un tiempo máximo y cada observación deja una pequeña prueba. Es un diseño sencillo, pero cambia bastante el diagnóstico cuando el proveedor llega tarde.

El problema: esperar no es una estrategia

Un flujo típico tiene esta forma:

crear identidad -> solicitar email -> esperar -> leer código -> continuar
Enter fullscreen mode Exit fullscreen mode

Cada flecha puede tener una latencia distinta. La API puede responder en milisegundos, mientras que la entrega del mensaje tarda varios segundos. Si el modelo sólo ve “mensaje encontrado” o “timeout”, pierde las diferencias entre una cuenta equivocada, un email atrasado y un buzón que nunca recibió nada.

También hay un riesgo de contexto: un agente puede leer un mensaje antiguo y creer que pertenece a la ejecución actual. Esto ocurre mas de lo que parece cuando se reutilizan buzones de prueba. Para reducirlo, la ejecución debe tener un identificador y el mensaje debe poder relacionarse con él, aunque sea mediante asunto, destinatario o una marca de tiempo.

Un presupuesto de latencia para el workflow

Un presupuesto útil no es una cifra mágica. Es una división explícita del tiempo total. Por ejemplo:

presupuesto_total = 30 s
  solicitud de envío = 5 s
  propagación esperada = 15 s
  lectura y validación = 5 s
  margen operativo = 5 s
Enter fullscreen mode Exit fullscreen mode

El agente no necesita decidir todos esos números. El orquestador puede entregarle un deadline y el tiempo restante. Así, una herramienta de lectura no inicia una espera de diez segundos cuando sólo quedan tres.

Hay que distinguir entre deadline y poll_interval. El primero limita la vida completa del paso; el segundo controla la frecuencia de consulta. Un intervalo corto da feedback rapido, pero genera más llamadas y puede presionar al servicio. Un intervalo creciente suele ser mejor:

intervalos: 1 s, 2 s, 4 s, 8 s, 8 s...
Enter fullscreen mode Exit fullscreen mode

El límite debe ser duro. Cuando se alcanza, el resultado es expired, no failed por defecto. Esa diferencia ayuda a saber si falló la aplicación o si simplemente no hubo evidencia a tiempo.

Diseño del contrato de observación

El agente debería recibir una respuesta estructurada y corta, no una copia completa del inbox. Un contrato mínimo puede verse así:

{
  "run_id": "signup-8f21",
  "state": "observed",
  "message_id": "m-204",
  "age_seconds": 3,
  "matched_rule": "subject:verify",
  "remaining_seconds": 12
}
Enter fullscreen mode Exit fullscreen mode

Los estados principales pueden ser pending, observed, expired, cancelled y ambiguous. Ambiguous es importante: si hay dos mensajes que cumplen la regla, continuar automáticamente es mas peligroso que pedir una decisión.

Para equipos que trabajan en CI, conviene definir contratos para correos temporales en CI antes de conectar el modelo. Para una experiencia de usuario real, también importa mantener estable la interfaz durante la espera del email; el backend y la pantalla deben contar la misma historia.

Polling, reintentos y cancelación

El polling debe ser consciente del estado. Si la solicitud de envío ya fue rechazada, seguir consultando no la hará válida. Si el mensaje fue observado pero el código no coincide, conviene clasificar el motivo y no repetir el mismo paso sin cambiar la hipótesis.

Un patrón práctico es asociar cada consulta a un attempt y registrar sólo metadatos seguros:

while clock.now() < deadline:
    result = inbox.find(run_id=run_id, rule="subject:verify")
    record(attempt=attempt, state=result.state, age=result.age_seconds)
    if result.state in {"observed", "ambiguous"}:
        return result
    sleep(next_interval(attempt))
    attempt += 1
return Expired(run_id=run_id)
Enter fullscreen mode Exit fullscreen mode

El run_id debe viajar por el sistema, pero no hace falta guardar el cuerpo entero del email en cada log. Una huella del mensaje, el asunto normalizado y la hora de recepción suelen ser suficiente para investigar. Si aparece un caso raro, se puede recuperar la evidencia con permisos más estrictos.

Una frase como “el tamp mail com no responde” puede aparecer en una nota humana durante una prueba, pero no debería convertirse en una palabra clave de control ni en una decisión del agente. Los términos imperfectos entran en comentarios; el contrato usa estados exactos.

Checkpoints de implementación

Yo validaría el diseño en este orden:

  1. Contrato: definir estados, run_id, deadline y qué significa una coincidencia.
  2. Adaptador: ocultar las diferencias entre proveedor, inbox temporal y entorno local.
  3. Reloj: inyectar un reloj controlable para probar expiraciones sin esperar de verdad.
  4. Evidencia: guardar intentos, latencia y resultado sin exponer cuerpos innecesarios.
  5. Herramienta LLM: describir entradas y salidas con ejemplos de expired y ambiguous.
  6. Pruebas: simular entrega rápida, entrega tardía, mensaje duplicado y mensaje viejo.

El punto de control más valioso es el cuarto. Sin evidencia, el agente puede parecer inteligente mientras el equipo sigue sin saber qué ocurrió.

Tradeoffs que conviene aceptar

Un presupuesto corto reduce coste y evita workflows colgados, pero puede marcar como expirado un proveedor lento. Un presupuesto largo mejora la tasa de éxito aparente, aunque empeora la experiencia y consume recursos. No existe un valor correcto para todos los productos.

Tampoco conviene usar un buzón temporal como identidad de negocio. Es útil para aislamiento, pruebas y escenarios desechables; no reemplaza la verificación de una dirección que el usuario controla. La arquitectura debe hacer visible esa frontera.

Preguntas frecuentes

¿El LLM debe elegir el intervalo de polling?

Normalmente no. El sistema puede ofrecer una política segura y permitir que el modelo solicite una espera dentro del presupuesto. Así se limita el coste y se mantiene el comportamiento repetible.

¿Qué hago si llegan dos emails válidos?

Devuelve ambiguous, conserva los identificadores y deja que una regla determinista seleccione por run_id, timestamp o versión. No pidas al modelo que adivine basándose sólo en el texto.

¿Hace falta guardar el cuerpo del mensaje?

No siempre. Para la mayoría de diagnósticos bastan metadatos, una huella y una política de acceso temporal al contenido. Es menos exposición y el log queda más manejable.

Checklist final

  • [ ] Cada workflow tiene un run_id único.
  • [ ] El paso de email recibe un deadline duro.
  • [ ] expired no se confunde con un error de aplicación.
  • [ ] Los reintentos tienen intervalo y límite explícitos.
  • [ ] Los mensajes viejos y duplicados se clasifican.
  • [ ] El agente recibe evidencia estructurada, no un inbox completo.
  • [ ] Los logs evitan datos personales innecesarios.

La idea central es pequeña: un agente no necesita esperar con más paciencia, necesita esperar con un contrato. Cuando la latencia, la cancelación y la evidencia son parte del diseño, el workflow se vuelve más fácil de probar y mucho menos misterioso.

Top comments (0)