DEV Community

Silviu Technology
Silviu Technology

Posted on

Agentes LLM: una cola de señales de email

Un agente LLM que crea una cuenta de prueba y espera un email parece sencillo. En la práctica, la espera es una frontera entre dos sistemas: el agente decide qué hacer y el proveedor de correo decide cuándo aparece una señal.

Cuando esa frontera no está diseñada, el agente suele repetir la misma consulta, gastar llamadas de herramienta y terminar con un diagnóstico poco útil: “no llegó el email”. La solución que prefiero es tratar cada mensaje esperado como una señal con contrato, caducidad y evidencia.

La idea no es construir otro framework de agentes. Es añadir una pequeña cola de señales entre el workflow y la bandeja de prueba. Esa cola hace visible el estado y limita el coste de la incertidumbre.

El problema: un agente que espera sin saber qué espera

Un flujo ingenuo se parece a esto:

crear_usuario()
repetir:
    revisar_bandeja()
    si hay_email: continuar()
Enter fullscreen mode Exit fullscreen mode

El pseudocódigo es corto, pero mezcla varias preguntas distintas:

  • ¿Qué usuario y qué mensaje estamos buscando?
  • ¿Cuánto tiempo puede esperar el agente?
  • ¿Cómo distingue un email nuevo de uno de una ejecución anterior?
  • ¿Qué hace si la bandeja responde con un error temporal?
  • ¿Qué evidencia se conserva al terminar?

Sin respuestas explícitas, cada reintento parece razonable por separado y el conjunto se vuelve caro. Tambien resulta dificil saber si falló el proveedor, el filtro de búsqueda o la propia instrucción del agente.

Diseñar la cola de señales

Una señal útil tiene un identificador y una condición de éxito concreta. Para un email de verificación, usaría un registro parecido a este:

{
  "signal_id": "sig_01J9MAIL42",
  "run_id": "run_20261020_01",
  "kind": "verification_email",
  "recipient": "test-user-42@example.invalid",
  "expected_subject": "Confirma tu cuenta",
  "status": "waiting",
  "expires_at": "2026-10-20T02:35:00Z"
}
Enter fullscreen mode Exit fullscreen mode

El agente no necesita leer toda la bandeja. Pide una operación estrecha: buscar la señal sig_01J9MAIL42, con un asunto esperado y una ventana temporal. El adaptador de correo devuelve uno de cuatro estados: waiting, found, expired o provider_error.

Esta separación es importante. waiting significa que todavía no hay evidencia; provider_error significa que la consulta no fue confiable. Si ambos se convierten en “no encontrado”, el agente aprende a insistir justo cuando debería cambiar de estrategia.

Para una prueba que usa un buzón aislado, una opción como tempmailso puede encajar como adaptador externo, siempre que el equipo revise sus condiciones, privacidad y límites antes de incluirla en un pipeline. El proveedor es reemplazable; el contrato de señales debería permanecer estable.

Implementación con estados e idempotencia

El worker que consulta el correo debe ser idempotente. Si el agente repite la llamada por un timeout, no debería crear otra señal ni consumir la primera evidencia como si fuera un mensaje distinto.

signal = queue.get(signal_id)

si signal.status en [found, expired]:
    devolver signal.status

resultado = mailbox.search(
    recipient=signal.recipient,
    subject=signal.expected_subject,
    after=signal.created_at
)

si resultado.matches:
    queue.mark_found(signal_id, resultado.message_id)
si resultado.provider_error:
    queue.record_error(signal_id, resultado.code)
si no:
    queue.record_check(signal_id)
Enter fullscreen mode Exit fullscreen mode

El campo message_id evita contar dos veces el mismo email. También guardaría la hora de cada consulta, la cantidad de coincidencias y un código de error resumido, pero no el cuerpo completo del mensaje. Esa evidencia basta para depurar sin convertir los logs en un almacén de datos personales.

En búsquedas y conversaciones técnicas aparecen variantes como tem email y temp org mail. Pueden servir para analizar consultas reales, pero no deberían entrar en nombres de estados ni en reglas de coincidencia: son señales de texto, no contratos del sistema.

Presupuesto de herramientas y reintentos

Un agente necesita un presupuesto visible. Por ejemplo, puede tener diez consultas de bandeja o dos minutos, lo que ocurra primero. Cada consulta debe indicar el motivo: primera comprobación, espera después de un webhook o recuperación de un error temporal.

No usaría intervalos fijos demasiado agresivos. Un backoff pequeño con un límite superior reduce presión sobre el proveedor. Si el flujo tiene una señal de webhook, el agente puede dormir hasta que ocurra un evento y usar la consulta solo como recuperación. En ese diseño, los contratos cortos para usar herramientas ayudan a que cada llamada tenga entradas y salidas verificables.

La cola también permite separar errores recuperables de errores finales:

  • waiting: no hay coincidencia todavía; esperar según el presupuesto.
  • provider_error: reintentar con backoff y registrar el código.
  • expired: detener el workflow y crear un diagnóstico.
  • found: pasar un identificador de evidencia al siguiente paso.

El agente no deberia inventar que el mensaje llegó solo porque una llamada anterior creó al usuario. Creación de cuenta y llegada del email son eventos distintos.

Cómo evaluar el workflow

Probaría el diseño con una tabla de escenarios, no solo con el caso feliz. Cada fila debe indicar el estado esperado, el número máximo de llamadas y la evidencia que queda:

Escenario Resultado esperado Evidencia
Email llega en la primera consulta found message_id
Email llega después de dos esperas found historial de checks
No llega antes del límite expired expires_at y última consulta
Proveedor responde 503 provider_error código y reintentos
Email de otra ejecución waiting filtro por run_id

La evaluación debe comprobar también que el agente explica el siguiente paso. Un resultado expired debería producir una recomendación accionable, no otro “revisa la bandeja”. Para escenarios Kubernetes, conviene combinar esta matriz con pruebas sintéticas sin ruido en las alertas, de modo que una demora externa no se convierta automáticamente en una alerta operativa.

Checklist de implementación

Antes de conectar el adaptador de correo, revisaría estos puntos:

  • Cada señal tiene signal_id, run_id, caducidad y condición de éxito.
  • La consulta es idempotente y filtra por ejecución.
  • waiting, provider_error y expired no se confunden.
  • Existe un presupuesto de tiempo y llamadas de herramienta.
  • Los logs guardan evidencia mínima, sin contenido privado innecesario.
  • El workflow puede reanudar una señal sin crear otra.
  • Los tests cubren llegada tardía, duplicados y errores del proveedor.

El valor de este diseño está en hacer pequeño el contrato, no en añadir más autonomía. Un agente que sabe qué señal espera, cuánto puede esperar y qué evidencia debe devolver es más fácil de evaluar y bastante más barato de operar. La bandeja cambia; el contrato permanece.

Top comments (0)