Un agente LLM puede redactar un plan excelente y aun así ejecutar una acción equivocada. El riesgo aparece cuando una herramienta le permite enviar un correo, crear una cuenta o repetir una operación externa sin un límite claro.
En mis flujos de automatización trato cada ejecución como si tuviera un presupuesto. El agente puede gastar cierta cantidad de lecturas, reintentos o llamadas, pero no puede gastar más solo por que el contexto parezca urgente. Esta regla convierte una conversación flexible en un sistema que se puede revisar.
La idea es especialmente útil en pruebas de email. Un mejor correo desechable no arregla un workflow sin aislamiento: si la suite comparte inboxes o acepta mensajes antiguos, el resultado puede parecer correcto y estar asociado a la ejecución equivocada.
El problema es el presupuesto, no la creatividad
Imaginemos un agente que valida un registro:
- solicita una identidad de prueba;
- completa el formulario;
- espera un email de confirmación;
- abre el enlace;
- informa si el registro terminó bien.
Cada paso necesita permisos distintos. Leer un mensaje es una observación. Elegir esperar es una decisión. Enviar un correo o modificar una cuenta es un efecto externo. Si todas las operaciones están expuestas como herramientas equivalentes, el prompt termina siendo la frontera de seguridad.
Eso es frágil por dos motivos. Primero, un modelo puede interpretar “reintenta” de manera distinta según el contexto. Segundo, un operador no puede saber si una acción fue propuesta, autorizada o ejecutada mirando solo el texto final.
El diseño que uso separa intención y ejecución. El LLM propone una acción estructurada; una capa determinista valida el presupuesto; y un adaptador limitado llama al proveedor. En el diagrama mental queda así:
Intención → política → adaptador → evidencia
Un presupuesto de acciones en cuatro capas
La primera capa normaliza la salida del agente. En vez de aceptar una instrucción libre, recibe campos como action, inboxId, purpose, correlationId y mode. Un ejemplo pequeño:
type EmailAction = {
action: "read" | "wait" | "send";
inboxId: string;
purpose: "signup-test" | "recovery-test";
correlationId: string;
mode: "dry-run" | "live";
};
La segunda capa aplica el presupuesto. Una prueba puede permitir seis lecturas, dos esperas y cero envíos en modo dry-run. En modo live, podría permitir un solo reenvío. El número no es mágico; lo importante es que exista antes de que el agente empiece a improvisar.
La tercera capa separa las herramientas. read no debería poder enviar. send debe recibir una intención ya validada y un destinatario permitido. También conviene rechazar un inboxId que no pertenece al correlationId actual. A veces una nota de depuración contiene la frase temp mailid, pero eso no debe convertirse en un destino válido.
La cuarta capa registra el consumo. Cada evento puede tener estado proposed, allowed, executed o rejected, además del saldo restante. Así un equipo puede explicar por que el agente se detuvo sin revisar toda la conversación.
Contrato mínimo para herramientas con efectos externos
Un contrato útil declara, como mínimo:
- el identificador de la ejecución y del inbox;
- el propósito permitido, por ejemplo
signup-test; - la hora desde la que un mensaje es válido;
- las acciones y cantidades disponibles;
- el modo
dry-runolive; - la retención de logs y artefactos.
La hora de inicio evita aceptar un correo viejo. El propósito evita usar una bandeja de recuperación para validar un registro. El saldo evita que un timeout se convierta en veinte llamadas. Son controles simples, pero hacen el sistema mas predecible.
Para el contexto del producto, también ayuda revisar cohortes de activación por email: una señal de activación solo es útil si sabemos qué ejecución la produjo. Y el patrón complementa estos límites seguros para el email, porque aquí el límite se expresa como saldo consumible y no solo como una regla narrativa.
Cómo probar los límites con evidencia
Empiezo con pruebas de política, sin proveedor externo. Compruebo que dry-run nunca llame al adaptador, que un inbox de otra ejecución sea rechazado y que agotar el saldo produzca el mismo error en cada corrida. Si la prueba necesita una excusa especial, el contrato aun no es suficientemente claro.
Después uso un cliente falso con cuatro respuestas: un mensaje antiguo, uno de otro correlationId, un mensaje válido y un timeout. El resultado esperado no es que el agente adivine; es que seleccione solo el mensaje que cumple el contrato y deje una evidencia de los descartes.
Por último ejecuto un caso pequeño en vivo, con un inbox aislado y un saldo bajo. Guardo la intención original, la decisión de política, la llamada al adaptador y el resultado. Tambien verifico que un fallo no devuelva saldo por accidente: si una acción fue ejecutada, debe quedar consumida aunque el proveedor responda tarde.
Q&A: decisiones frecuentes
¿El presupuesto limita demasiado a un agente?
Limita efectos, no razonamiento. El modelo todavía puede comparar hipótesis, explicar un fallo y proponer el siguiente paso. Lo que no puede hacer es convertir una propuesta en una llamada externa sin autorización.
¿Conviene aumentar el saldo cuando falla una prueba?
No automáticamente. Primero hay que distinguir un timeout del proveedor, un mensaje inválido y una política mal configurada. Aumentar el saldo sin esa clasificación vuelve el fallo mas caro y menos visible.
¿Dónde encaja una bandeja temporal?
Como un recurso aislado dentro del contrato, no como una solución de identidad. Un servicio como temp mail.so puede ser parte del entorno de pruebas, pero la trazabilidad sigue dependiendo del inboxId, el propósito y el correlationId.
Un agente confiable no es el que nunca pide reintentos. Es el que sabe cuanto puede gastar, explica por que se detiene y deja una prueba verificable de cada decisión.
Top comments (0)