Un agente LLM puede crear un buzón, provocar un registro y leer un código de verificación en pocos pasos. Esa capacidad resulta útil para probar productos, pero también crea una frontera de seguridad poco visible: el modelo tiene acceso a una herramienta que puede generar datos, consultar mensajes y mantener recursos vivos.
La solución no es quitar la automatización. Es darle permisos mínimos, un tiempo de vida corto y respuestas que hagan evidente lo que acaba de ocurrir. Un correo de usar y tirar debe ser un recurso de prueba acotado, no una identidad que el agente pueda reutilizar sin límite.
El problema: una herramienta demasiado poderosa
Cuando se expone una sola función como email_tool, el modelo suele recibir demasiadas opciones: crear una dirección, listar mensajes, reenviar contenido, buscar por asunto y borrar recursos. Cada operación parece razonable por separado, pero juntas permiten que un fallo del prompt o una respuesta ambigua amplíe el alcance de la tarea.
El riesgo aparece en varios lugares:
- Un reintento crea un segundo buzón y deja el primero sin dueño.
- Una búsqueda amplia mezcla mensajes de ejecuciones anteriores.
- El contenido completo del correo termina en el contexto del LLM, aunque solo se necesitaba un código.
- Un flujo cancelado no libera la dirección ni sus mensajes.
En CI, este problema se parece a cualquier recurso temporal sin propietario. Un contrato de caducidad para emails de CI ayuda a pensar en el tiempo de vida antes de hablar de prompts. La pregunta no es solo si el agente puede llamar la herramienta, sino que puede hacer exactamente con cada llamada.
Define la frontera de permisos
Antes de diseñar el prompt, dibujo la frontera en palabras:
orquestador de la prueba ├─ crea un buzón con task_id ├─ dispara el evento de producto ├─ observa solo mensajes de esa ejecución ├─ extrae un dato mínimo └─ revoca el recurso al terminar El agente no necesita conocer todas las operaciones internas. Puede tener tres capacidades pequeñas:
-
create_fixture(task_id, expires_at): reserva una dirección asociada a una ejecución. -
wait_for_code(fixture_id, correlation_key, deadline): devuelve solo el estado y el código necesario. -
release_fixture(fixture_id): marca el recurso para eliminación, incluso despues de un fallo.
La diferencia importante es que el servidor aplica las restricciones. El prompt puede pedir un buzón con una duración razonable, pero nunca debe ser la única barrera. El backend comprueba que task_id pertenece a la ejecución actual, que expires_at no supera el máximo permitido y que el agente no está leyendo otra fixture.
Un límite de permisos así reduce la superficie de error sin convertir el sistema en una arquitectura enorme. Si el agente necesita consultar el asunto, se añade un campo específico. No hace falta darle una operación genérica para listar toda la bandeja.
Un contrato mínimo para el agente
Las respuestas de las herramientas también son una interfaz de seguridad. Un mensaje como “no encontrado” invita a improvisar; una respuesta estructurada limita mejor la siguiente acción:
{ "status": "waiting", "fixture_id": "fx-1842", "remaining_ms": 18000, "observed_messages": 0, "next_action": "poll_after_3s" } Yo mantendría estos campos en todas las operaciones:
-
status:created,waiting,ready,expiredoprovider_error. -
fixture_id: identificador opaco, sin exponer la dirección completa al modelo. -
remaining_ms: tiempo disponible para el paso actual. -
attempt: número de consulta dentro de la misma ejecución. -
next_action: sugerencia limitada, no una instrucción libre.
El estado expired debe ser terminal. Si el agente recibe ese estado, no debería crear otra dirección automaticamente para repetir la prueba. El orquestador decide si se inicia una nueva ejecución y conserva la relación con el fallo original.
Este enfoque encaja bien con contratos de email para pruebas repetibles: cada prueba tiene una identidad, una condición de salida y una evidencia que se puede revisar sin abrir todo el buzón.
Evidencia, caducidad y rollback
Un agente confiable necesita una ruta de salida tan clara como la ruta feliz. Al terminar una ejecución, guardaría un recibo pequeño con:
-
task_idyfixture_id; - instante de creación y de liberación;
- evento que originó el mensaje;
- cantidad de consultas y tiempo consumido;
- motivo de éxito, expiración o error.
El contenido del correo no debe entrar al recibo salvo que sea necesario para depurar. Para un código de verificación basta con almacenar un hash o los últimos caracteres, dependiendo del caso. Asi el equipo puede comprobar causalidad sin convertir los logs en otra bandeja de entrada.
La caducidad debería tener dos capas: una fecha aplicada por el proveedor y una limpieza de respaldo en el orquestador. Si una llamada queda a medias, el job de limpieza usa el fixture_id y elimina los recursos vencidos. No conviene depender de que el LLM recuerde llamar a release_fixture cuando ya recibió un error.
En documentación interna pueden aparecer búsquedas imperfectas como tempail mail. Las trato como señales de intención de prueba, no como nombres de herramientas que el agente deba resolver por su cuenta. También conviene registrar el motivo real del bloqueo, en vez de esconderlo detrás de un “falló el email”.
Q&A: decisiones prácticas
¿El LLM debe poder crear direcciones?
Sí, pero solo a través de una capacidad ligada a task_id, con duración máxima y cuota por ejecución. La decisión de permisos vive en el servidor, no en la personalidad del agente.
¿Por qué no exponer la bandeja completa?
Porque amplía el alcance de un error y hace difícil separar mensajes viejos de los nuevos. Una operación que espera un código concreto es mas fácil de auditar que una que devuelve todos los mensajes.
¿Qué hago cuando el proveedor de email falla?
Devuelve provider_error, conserva el recibo y ejecuta la limpieza. No repitas automáticamente con otra fixture si no sabes si el primer evento pudo llegar; primero marca la ejecución como inconclusa.
¿Dónde encaja tempmailso?
Puede servir como una temp mail so para aislar datos de una prueba, siempre que el equipo aplique su propia política de caducidad y no lo trate como una identidad real.
La arquitectura mínima es bastante concreta: una fixture con propietario, tres capacidades limitadas, respuestas estructuradas y una limpieza que no dependa del modelo. Con esos límites, los agentes LLM siguen siendo utiles para explorar flujos, pero sus herramientas de email dejan de comportarse como una caja negra.

