Todo el mundo se obsesiona con el prompt. Perfeccionan el saludo, ajustan el tono y se preocupan por si el modelo suena lo suficientemente cálido. Eso es una distracción. Cuando un agente de IA comienza a enviar correos electrónicos reales a usuarios reales, el peligro no es que escriba "Atentamente" en lugar de "Saludos". El peligro es que no puedes saber, con certeza, qué ocurrió entre la decisión del agente y la llegada del mensaje a la bandeja de entrada. Yo miro primero el límite. Ahí es donde los sistemas de producción mueren silenciosamente.
El contrato es el punto débil
Las demos de IA son permisivas. Una conversación fluida en una ventana del navegador oculta un caos de suposiciones. En producción, la verdadera vulnerabilidad reside en el contrato entre tres elementos: la decisión del agente, la herramienta que ejecuta la acción y el paso que verifica el resultado. Si ese límite es difuso, el sistema funciona maravillosamente hasta que deja de hacerlo. Entonces falla silenciosamente, envía duplicados a todo un segmento de clientes o dispara mensajes en el momento equivocado sin un registro claro de por qué. El prompt puede leerse como poesía, pero la arquitectura subyacente aún puede estar sostenida con un hilo.
No permita que el agente escriba libremente
El error más común es darle al agente una página en blanco. Los equipos permiten que describa un correo en texto plano y luego confían en que una herramienta posterior interprete la intención a partir de la prosa. Eso es frágil. Un LLM puede sugerir una intención razonable, pero su infraestructura no necesita creatividad. Necesita un contrato. Necesita campos específicos que una máquina pueda validar sin ambigüedades.
Cuando un agente emite una solicitud de correo electrónico, la salida debe contener exactamente lo que la infraestructura requiere:
- Versión de la plantilla: Qué versión del cuerpo del correo se está utilizando, para que sepa qué vio el usuario.
- Alcance del destinatario: Quién recibe esto, definido por IDs de usuario o reglas de segmentación, no mediante lenguaje natural como "el usuario que se acaba de registrar".
- ID de seguimiento (Trace ID): Un identificador único que sigue esta solicitud desde el agente, pasando por su ejecutor, por el proveedor de correo y hasta sus registros (logs).
- Ventana de tiempo: Cuándo es válido este envío, para que decisiones obsoletas del agente no activen correos a medianoche horas después.
- Idempotencia: Una clave que evita que el mismo envío lógico se ejecute dos veces si el agente reintenta o si hay un hipo en la red.
El texto sin procesar es una API terrible. Deja lugar a la ambigüedad sobre la urgencia, la audiencia y la acción. Los campos específicos son legibles por máquinas, auditables y testeables. Convierten una instrucción vaga en un comando verificable.
Acciones, no prosa
En lugar de entregarle al agente una tarea de escritura abierta, restríngalo a un menú de acciones permitidas. Piénselo como una API interna con un enum fijo. El agente no redacta una línea de asunto ni se pregunta por los saludos. Elige una acción como send_review_request o send_retry_notice. Ese es el alcance de su libertad creativa.
Un ejecutor determinista toma entonces esa clave de acción, extrae la plantilla correcta del control de versiones, la hidrata con datos saneados, completa la lista de destinatarios desde una fuente verificada y construye el comando final. El agente decide qué debe suceder. El código aburrido y predecible decide cómo sucede.
Esta separación hace que el sistema sea fácil de probar. Puede verificar que un estado de entrada determinado activa de forma fiable send_retry_notice sin necesidad de ejecutar una inferencia de LLM. Sus pruebas unitarias se vuelven rápidas y deterministas porque comprueban la lógica de mapeo, no la temperatura del modelo. Sus pruebas de integración se centran en si el ejecutor mapea correctamente la acción al servicio de correo, no en si el modelo tuvo un buen día.
Construya en cinco capas
Un sistema sólido no surge de un único prompt. Se construye en capas, y cada capa posee una única y clara responsabilidad.
1. El backend reduce el evento a datos seguros.
Ya sea que el activador sea un webhook, un cambio en la base de datos o un trabajo programado, esta capa sanaiza las entradas, elimina campos inesperados y entrega al agente solo lo que necesita. Si el payload de un webhook contiene veinte campos pero el agente solo necesita dos, pase los dos. Ningún texto bruto del usuario debe llegar a la capa de decisión sin ser comprobado.
2. El agente elige una acción a partir del esquema fijo.
El agente observa el contexto, toma una decisión y devuelve una de las claves de acción predeterminadas junto con los metadatos requeridos. No redacta prosa. No adivina los destinatarios. Devuelve un payload estructurado que la siguiente capa puede validar contra un esquema JSON.
3. The tool validates permissions and required fields.
Does this agent context have the right to trigger send_review_request for this user? Is the recipient scope non-empty and within allowed limits? Is the idempotency key present and unique in your log? Is the trace ID well-formed? Fail here, loudly, before any email service is ever touched.
4. The email service logs the send with a trace ID.
Every message that leaves your system should carry that trace identifier through the provider's API and into your observability stack. If a user complains they received two copies, you should be able to query one ID and see exactly where the duplication originated: a retried agent call, a flaky executor, or a misbehaving callback.
5. The end-to-end test checks the actual inbox for content and effect.
Open the rendered message in a real mailbox. Is the subject line populated correctly? Does the unsubscribe link resolve? Does clicking the primary call-to-action button land on the correct page with the correct user state? A passing unit test means the code ran. Only an inbox test tells you the email actually works for a human.
Evidence Over Guessing
When a test fails in this pipeline, you need four specific pieces of evidence. Accept nothing less.
- The original decision from the agent. What action did it choose, and what was the full input context?
- The normalized command from the tool. What did the deterministic executor build after applying the template, hydration logic, and validation rules?
- The message in the isolated inbox. Not a log of what you think you sent, but the real MIME message, headers and all, captured in a dedicated test mailbox.
- The final effect after clicking the link. The resulting page state, database change, or external event that proves the email achieved its purpose.
If one piece is missing, your team will fill the gap with assumptions. They will guess. Guessing in automation is expensive. It burns hours, erodes trust, and turns every incident into a forensic mystery instead of a
