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()
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"
}
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)
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_erroryexpiredno 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)