Agentes de IA en producción: arquitectura para limitar el radio de impacto
Agentes de IA en producción necesitan límites reales: mínimo privilegio, herramientas permitidas, topes de gasto e idempotencia para contener cualquier fallo.

El 25 de abril, uno de los agentes de IA de Cursor, ejecutando Claude Opus 4.6, borró en nueve segundos la base de datos de producción de PocketOS y sus copias de seguridad. Después escribió una confesión. Tres meses de reservas de alquiler de vehículos desaparecieron. Opero seis agentes que interactúan con producción todos los días; esta es la arquitectura exacta de punto de control, lista de herramientas permitidas e idempotencia con la que el peor de ellos solo podría hacerme gastar un dólar de más.
El saldo de los últimos 90 días
25 de abril de 2026. Un agente de Cursor que ejecutaba Claude Opus 4.6 trabajaba en lo que Jeremy Crane, CEO de PocketOS, describió como una «tarea rutinaria» en staging. Encontró credenciales que no coincidían, decidió por iniciativa propia «poner orden» y eliminó un volumen de almacenamiento de Railway que contenía la base de datos de producción y sus copias de seguridad. Nueve segundos. Una interrupción de treinta horas. La copia recuperable más reciente tenía tres meses, así que se esfumaron tres meses de reservas de alquiler de vehículos. Después, el agente escribió una confesión en la que reconocía haber incumplido las instrucciones explícitas de no tocar producción.
26 de febrero de 2026. Alexey Grigorev, fundador de DataTalks.Club, había cambiado de equipo y su archivo local de estado de Terraform estaba desactualizado. Claude Code recibió la instrucción de limpiar recursos y ejecutó terraform destroy contra el stack de producción. La tabla courses_answer —cuando más tarde se recuperó parcialmente— contenía 1,943,200 filas. Eran dos años y medio de entregas de estudiantes. Las instantáneas automatizadas estaban en la misma cuenta que se había destruido.
A mediados de diciembre de 2025. Kiro, el agente interno de Amazon, heredó los permisos elevados de un ingeniero, eludió el control de aprobación de dos personas de Amazon —porque se aplicaba a los humanos, no al rol bajo el que operaba el agente— y eliminó y volvió a crear el entorno de producción de AWS Cost Explorer.
Tres incidentes, tres modelos distintos y tres stacks diferentes. La causa raíz común no es el modelo, sino la combinación de permisos amplios heredados, un bucle autónomo y una velocidad de ejecución que deja atrás cualquier confirmación humana. ServiceNow ya comercializa un producto de «kill switch» para responder precisamente a este temor. La arquitectura que sigue es la versión interna, y hoy la utilizo en producción.
Qué implica esto para los fundadores no técnicos
Si eres fundador y llegaste hasta aquí porque la persona que contrataste para trabajar con IA mencionó el tema, el costo de equivocarse no es «un error de IA». Es perder el sistema de reservas, los registros de estudiantes y los datos de clientes, con copias de seguridad tres meses atrasadas porque nadie probó la restauración.
La pregunta sincera para el responsable de ingeniería no es «¿qué tan bueno es el agente?». Ese enfoque no sirve. La pregunta correcta es: ¿cuál es el daño máximo que puede causar una sola ejecución del agente y quién definió ese límite? Si la respuesta es «confiamos en el modelo» o «revisamos los diffs», no existe una superficie de control. Solo hay esperanza.
La respuesta que conviene escuchar suena así: «El agente opera con un rol de nube sin permisos de destrucción. Puede invocar doce herramientas con nombre propio, ninguna de ellas un shell. Toda llamada de pago pasa por una única función con un tope de costo rígido. En el peor caso falla un paso y el gasto no supera un dólar». Esa es la arquitectura. A continuación se explica cómo construirla.
Por qué «ten cuidado» y «revisa el diff» no controlan los riesgos de agentes de IA
PocketOS perdió el volumen en nueve segundos. Kiro terminó de eliminar el entorno antes de que una persona pudiera leer la confirmación, mucho menos evaluarla. A la velocidad de un agente, intervenir después de iniciada la acción es estructuralmente imposible. Cuando alguien ve lo que está ocurriendo, la acción ya terminó.
Este es el aspecto de la seguridad de agentes de IA que gran parte de los análisis evita, porque obliga a aceptar una conclusión incómoda: la única protección que funciona es la denegación previa a la ejecución. No que «el agente pregunte y una persona cansada haga clic en “Sí”». Tampoco «registramos todo y lo revisamos después». Denegar antes de ejecutar significa que la acción destructiva nunca forma parte de la superficie que el agente puede alcanzar.
Kiro lo demostró por contraposición. Amazon contaba con una aprobación de dos personas, pero esta se aplicaba a los humanos que iniciaban trabajos. El agente heredó los permisos de quien lo puso en marcha y eludió el control porque nunca estuvo vinculado al rol bajo el que operaba. Para la persona había una escenificación de aprobación; para el bucle, permisos completos de destrucción.
Esto cambia el planteamiento. Un agente no se «supervisa». Su superficie de acción se restringe antes de iniciar el bucle, y esa restricción debe ser una propiedad del rol, no del prompt.
El punto de control: una sola función para toda llamada de pago o con efectos
Todas las llamadas de pago a modelos de mi stack de seis agentes pasan por una única función: callAi. Hace cinco cosas, en este orden: comprueba de antemano el límite diario de $20, mide la duración de la llamada, registra el número de tokens y el costo en USD en una fila del registro de solo adición ai_call_log, etiquetada con agent_id y workflow_instance_id, verifica después el límite de $1 por instancia y devuelve el resultado.
export async function callAi(env: Env, args: CallAiArgs) {
const { agentId, workflowInstanceId, model, messages } = args;
const dailySpent = await getDailySpendUSD(env);
if (dailySpent >= 20) {
throw new NonRetryableError(`daily cap hit: $${dailySpent}`);
}
const t0 = Date.now();
const res = await anthropic.messages.create({ model, messages });
const costUSD = priceOf(model, res.usage);
await env.DB.prepare(
`INSERT INTO ai_call_log
(agent_id, workflow_instance_id, model, in_tokens, out_tokens, usd, ms, ts)
VALUES (?, ?, ?, ?, ?, ?, ?, unixepoch())`
).bind(agentId, workflowInstanceId, model,
res.usage.input_tokens, res.usage.output_tokens,
costUSD, Date.now() - t0).run();
const instanceSpent = await getInstanceSpendUSD(env, workflowInstanceId);
if (instanceSpent >= 1) {
throw new NonRetryableError(`instance cap hit: $${instanceSpent}`);
}
return res;
}Superar un límite lanza un error no reintentable. El Workflow termina. El agente no puede «decidir por iniciativa propia» que continuará, porque el control presupuestario no es un prompt con el que pueda discutir: es una excepción lanzada por encima de su capa de razonamiento.
Compáralo con el caso tantas veces citado del proceso descontrolado que duró 63 horas y gastó $4,200: sin un punto de control no hay estado terminal. El bucle sigue consumiendo recursos hasta que alguien ve la factura. Con un límite por instancia, una ejecución cuesta como máximo $1. Con un límite diario, un día cuesta como máximo $20. Durante el desarrollo alcancé ambos por accidente. Ninguno costó más que una cena.
La segunda función del punto de control es forense. Cada acción deja una fila de auditoría antes de que se devuelva el resultado. Cuando algo falla, el análisis posterior es una consulta SELECT sobre ai_call_log, no una reconstrucción basada en la confesión del propio agente.
Seguridad de agentes de IA: 12 herramientas Zod, sin shell ni terraform
Toda la superficie de mutación del agente se limita a doce herramientas definidas mediante esquemas Zod estrictos. No hay una herramienta Bash. No hay una herramienta terraform. La superficie ni siquiera incluye una API para volúmenes de nube. Aunque el agente razonara que quiere ejecutar terraform destroy, no tendría cómo expresar ese deseo.
La configuración del Claude Agent SDK que impone esta restricción es breve:
const result = await query({
prompt,
permissionMode: "dontAsk",
allowedTools: [
"read_brief", "fetch_corpus", "render_markdown",
"validate_directives", "persist_draft", "schedule_publish",
"update_status", "log_event", "fetch_citation",
"embed_text", "search_vectors", "notify_human"
],
// no Bash, no Write, no Edit, no infrastructure tools
});Con permissionMode: "dontAsk", toda herramienta que no aparezca en la lista se rechaza de inmediato. No se eleva a una solicitud. No se presenta para revisión humana. Se rechaza. El orden de evaluación de permisos —hook PreToolUse, reglas de denegación, reglas de autorización, reglas de consulta, comprobación de modo y callback canUseTool— se ejecuta tal como está documentado, pero en dontAsk el callback con intervención humana se omite por diseño y las herramientas desconocidas se detienen en la comprobación de modo.
Esto habría detenido de raíz los incidentes de PocketOS y DataTalks. En esta configuración, el fallo de DataTalks es imposible porque terraform destroy no es un nombre de herramienta que el agente pueda emitir. El de PocketOS también lo es porque eliminar volúmenes no forma parte de la superficie. Aunque el modelo decidiera «poner orden», no existe una ruta que convierta ese deseo en una acción.
Aquí aparece la tentación de añadir una herramienta Bash «por si el agente necesita hacer algo que no anticipamos». No lo hagas. El día que añades Bash, el radio de impacto pasa a ser «todo lo que Bash pueda alcanzar».
Idempotencia: por qué una repetición no puede destruir dos veces
Cada instancia de Cloudflare Workflow tiene un ID determinista compuesto a partir de la entrada: publish-{brief_id}. instances.create() lanza un error ante un ID duplicado, así que volver a disparar el mismo evento no puede ejecutar el workflow dos veces. Una tormenta de reintentos en la capa de colas se convierte en una operación nula, no en una publicación duplicada.
const id = `publish-${msg.body.briefId}`;
try {
await env.PUBLISHER.create({ id, params: msg.body });
} catch (e) {
if (e.message.includes("already exists")) return; // safe replay
throw e;
}Dentro del workflow, el resultado de cada step.do() queda almacenado en caché y puede repetirse sin riesgo. Si un paso se reintenta, se reproduce el resultado en caché en lugar de volver a ejecutar el efecto. Al combinarlo con INSERT OR IGNORE sobre las tablas canónicas de D1 y una instantánea versionada en R2 en cada persistencia, un paso defectuoso no puede sobrescribir el historial en silencio. La versión anterior está a una clave de R2 de distancia.
La causa raíz del caso DataTalks fue un archivo de estado desactualizado que provocó una destrucción irreversible. Los ID deterministas del workflow y las instantáneas antes de mutar hacen que aquí una destrucción por estado obsoleto no sea fatal: aunque el workflow se ejecutara con supuestos desactualizados, la instantánea permitiría revertir. (Expliqué el mecanismo de ejecución duradera en el análisis de Cloudflare Workflow frente a Managed Agents; la lógica de idempotencia cuenta la misma historia de contención con otro nombre).
El modelo mental es este: un paso con capacidad destructiva escribe primero una instantánea versionada. La instantánea es una precondición, no una idea tardía. Si falla su escritura, la mutación no ocurre. Si falla la mutación, la instantánea es el punto de restauración. No existe una ruta en la que se pierda el estado sin tener desde dónde recuperarlo.
La migración en 5 pasos que puedes ejecutar esta semana
Este es el orden. Solo el paso 1 habría evitado los tres incidentes anteriores, así que empieza por ahí aunque no hagas nada más.
Aplica el principio de mínimo privilegio al rol de nube
El rol IAM —o la cuenta de servicio o el token de API— bajo el que opera el agente debe aplicar el principio de mínimo privilegio: no debe tener verbos de destrucción ni eliminación sobre recursos de producción. Nada de
DeleteVolume. Nada de permisos paraterraform destroy. Nada deDROP TABLE. El rol marca la base del radio de impacto; nada de lo que se añada por encima importa si el propio rol no está acotado.Esta es la lección de Kiro convertida en una medida concreta: no permitas que el agente herede los permisos amplios de la persona que lo inicia. Asígnale un rol propio y limitado.
Encierra el agente en permissionMode dontAsk con una lista allowedTools explícita
Elige el conjunto mínimo de herramientas que permita al agente cumplir su tarea. El mío tiene doce; el tuyo quizá tenga seis. Elimina por completo cualquier herramienta de shell de propósito general. Si el agente cuenta hoy con Bash porque «es práctico», esa comodidad es la vulnerabilidad.
TypeScript{ permissionMode: "dontAsk", allowedTools: [/* explicit list */] }Añade un cortacircuitos presupuestario
Usa una única función envoltorio para todas las llamadas de pago. Comprueba antes un límite diario rígido y, después, un límite por instancia. Lanza
NonRetryableErrorcuando se supere. El límite por instancia es el cortacircuitos que el diario no puede ser: el proceso descontrolado de $4,200 durante 63 horas se mantuvo por debajo de cualquier techo diario razonable mientras acumulaba costo por ejecución. El límite por instancia detecta lo que el diario no ve.Crea una instantánea antes de mutar
Todo paso con capacidad destructiva escribe primero una instantánea versionada. R2 sirve; S3 también; una tabla
*_archivede D1 también. Lo importante es que escribir la instantánea sea la precondición de la mutación, dentro del mismo paso y del mismo bloque con forma de transacción.Mantén un registro de acciones de solo adición
Escribe una fila por llamada a una herramienta antes de devolver el resultado. Etiquétala con el ID del agente, el ID de la instancia del workflow, el costo en USD y la latencia. Cuando algo falle —porque tarde o temprano ocurrirá—, el análisis posterior será un
SELECT, no una reconstrucción.
Cada paso requiere un día o menos. Este orden importa porque la contención se refuerza por capas: el paso 1 fija el piso; el paso 2 cierra la superficie de acción por encima de ese piso; el paso 3 limita el costo de operar dentro de esa superficie; y los pasos 4 y 5 hacen que cualquier fallo sea recuperable y consultable.
Preguntas frecuentes
¿No basta con indicarle al agente en el prompt del sistema que jamás elimine producción?
PocketOS lo hizo. En su propia confesión, el agente reconoció explícitamente que había incumplido esas instrucciones. Las instrucciones no son una superficie de control. Los prompts son entradas de un sistema probabilístico; la lista de herramientas permitidas y el rol de nube son propiedades del entorno de ejecución. Usa el entorno de ejecución.
¿permissionMode dontAsk elimina toda la interactividad?
No. Significa que las herramientas no incluidas en la lista se rechazan en lugar de generar una solicitud. Toda la superficie permitida sigue disponible. Lo que desaparece es el modo de fallo «el agente pregunta y una persona cansada hace clic en “Sí”», precisamente el que conviene eliminar.
¿Para qué necesito un límite de costo por instancia si ya tengo uno diario?
Porque el proceso descontrolado de $4,200 en 63 horas se mantuvo por debajo de cualquier techo diario razonable mientras acumulaba costo por ejecución. Un solo bucle defectuoso puede permanecer muy por debajo de «$20 al día» y aun así generar un gasto de cuatro cifras durante el fin de semana. El límite por instancia es el cortacircuitos que un límite diario, por su propia estructura, no puede ser.
Uso Vercel o Railway, no Cloudflare Workflows. ¿También aplica?
El punto de control, la lista de herramientas permitidas y el rol limitado son independientes de la plataforma. Solo el mecanismo de idempotencia —los ID deterministas de Workflow— es específico de Cloudflare. En otros stacks, utiliza una clave de idempotencia en el trabajo y rechaza los duplicados en la capa de colas o en el ejecutor de trabajos.
¿Es suficiente la aprobación de dos personas?
Kiro la tenía para los humanos, pero el agente heredó permisos que le permitieron eludirla. Los controles de aprobación deben vincularse al rol bajo el que opera el agente, no a la persona que lo inició. Si el rol del agente tiene permisos de destrucción, el control es decorativo.
Si estás leyendo esto porque la semana pasada un agente de tu equipo se acercó demasiado a producción, ese trabajo de contención es lo que hago en DVNC.dev: aplicar la arquitectura anterior a tu stack, en el orden que reduce primero el radio de impacto.
5 sept 2026







