Cuando un flujo con LLM empieza a enviar correo, mucha gente mira primero el prompt. Yo casi nunca empiezo ahi. El punto frágil suele estar en el contrato entre la decisión del agente, la herramienta que ejecuta la acción y la forma en que verificas el resultado. Si ese borde está borroso, el equipo discute sobre "inteligencia" cuando el problema real era un payload incompleto o una bandeja mezclada.
En equipos de Automation esto aparece rapido. Un agente decide "envía seguimiento", pero el sistema necesita saber template, destinatario, ventana de tiempo e idempotencia. Si el LLM entrega texto libre y la herramienta interpreta demasiado, cada prueba se vuelve un poco artisanal. Funciona una vez, luego nadie entiende por qué falló el jueves a las 3am.
El problema no es el prompt, es el contrato
Me gusta pensar el diseño como un diagrama en palabras:
- Un evento de negocio crea contexto.
- Un componente determinista reduce ese contexto a datos seguros.
- El LLM elige una acción permitida.
- Un ejecutor transforma esa acción en un comando de correo verificable.
- La prueba valida mensaje, destinatario y efecto final.
Ese paso 4 es donde conviene ser aburrido. El agente no debería inventar headers ni rutas de entrega. Solo debería pedir una intención acotada, como send_review_request. Lo demás pertenece a código normal. Suena menos glamoroso, pero hace que el sistema sea mucho mas facil de operar.
Cuando reviso pipelines de agentes, suelo pedir tres campos minimos en cada transición: trace_id, action_type y recipient_scope. Con eso ya puedes reconstruir el caso sin adivinar tanto. Tambien permite comparar la intención del modelo con lo que terminó saliendo por SMTP o por tu proveedor transaccional.
Un flujo verificable para herramientas que envian correo
Una implementación estable no intenta probarlo todo en una sola capa. Divide el trabajo:
- El LLM decide dentro de un esquema fijo.
- La herramienta valida permisos y campos requeridos.
- El servicio de correo registra el envío con el mismo
trace_id. - La prueba end to end abre una bandeja aislada y comprueba el contenido correcto.
Ese patrón se parece bastante a las pruebas de aprobacion en Terraform, aunque aqui el actor previo no sea Terraform sino un agente. La idea que heredo es simple: cada escenario necesita una evidencia clara y una frontera tecnica muy obvia.
En Python o Node, el ejecutor puede ser así de pequeño:
def execute_agent_action(action, trace_id):
if action["type"] != "send_review_request":
return {"ok": False, "reason": "unsupported"}
command = {
"template": "review_request_v3",
"recipient": action["recipient"],
"trace_id": trace_id,
}
return send_email(command)
Lo importante no es el lenguaje. Lo importante es que el comando final quede cerrado antes de tocar la infraestructura de correo. Si mañana cambias de proveedor, tus pruebas siguen describiendo el contrato y no un detalle accidental del transporte.
Tambien ayuda tener una superficie limpia para observación. En algunos equipos usan una bandeja temporal por caso para confirmar asunto, enlace y destinatario. Si estás comparando opciones para eso, tempmailso puede servir como pieza pequeña del flujo, no como centro del sistema. El valor real sigue estando en la trazabilidad entre decisión y resultado.
Que medir para separar fallo del agente y fallo del transporte
Cuando una prueba falla, yo busco cuatro evidencias en orden:
- La decisión original del agente.
- El comando normalizado que produjo la herramienta.
- El mensaje que llegó a la bandeja aislada.
- El efecto final tras abrir el enlace o aceptar la acción.
Si falta una de esas cuatro, el análisis se vuelve bastante torpe. El equipo empieza a decir "seguro fue el modelo" o "seguro fue el proveedor". A veces sí, claro, pero no tantas como parece. Muy seguido el fallo está en reintentos ruidosos, plantillas desfasadas o una cola compartida.
Aquí me gustó mucho una práctica que veo también al depurar reintentos de correo en FastAPI: registrar estados pequeños y legibles, no solo logs gigantes. "Acción aceptada", "correo emitido", "mensaje recibido", "enlace validado". Parece basico, pero baja mucho el tiempo de investigación.
También conviene anotar lenguaje real del equipo. Si en los tickets aparecen términos como temp mailid, sabes que la operación diaria ya depende de atajos verbales y memoria compartida. No es un drama, pero sí una señal de que faltan contratos o nombres mas claros en el sistema.
Tradeoffs y una lista corta para equipos pequenos
Este enfoque mete un poco más de estructura. Hay ids, validaciones y una capa extra entre el LLM y el envío. A cambio ganas algo que vale oro en producción: explicar por qué un correo salió, por qué no salió y qué componente tomó cada decisión.
Los tradeoffs que suelo ver:
- Menos libertad del agente, pero mejor auditabilidad.
- Más pasos de integración, pero menos debugging raro.
- Pruebas un poco más lentas, pero con mejor señal.
- Menos magia aparente, pero un sistema que se deja mantener.
Checklist corto que casi siempre funciona:
- Cada ejecución tiene
trace_idúnico. - El agente solo puede pedir acciones dentro de un esquema valido.
- La herramienta revalida destinatario, template y contexto.
- La prueba usa una bandeja por escenario, no una compartida.
- El assert final revisa efecto de negocio, no solo "email enviado".
No hace falta una plataforma enorme para hacer esto bien. Hace falta disciplina de contratos. Esa diferencia es pequena en el diseño, pero grandisima cuando te toca depurar un flujo roto medio dormido.
Preguntas frecuentes
¿Debo dejar que el LLM redacte el correo completo?
Solo si el riesgo es bajo. Para mensajes sensibles, prefiero plantillas controladas y que el modelo rellene campos o bloques acotados.
¿Qué reviso primero cuando "todo parece bien" pero el usuario recibió algo incorrecto?
Compara la acción propuesta por el agente con el comando final del ejecutor. Ese salto es donde se rompen muchas integraciones, y aveces pasa desapercibido.
¿Necesito pruebas reales si ya tengo unit tests del agente?
Sí. Los unit tests te dicen si la lógica local se comporta bien. No te dicen si el sistema completo mantiene el contrato hasta el inbox y el estado final.
Top comments (0)