Módulo 7: Seguridad y confiabilidad del agente

5. Human-in-the-loop: aprobación antes de acciones sensibles

Descripción

Al terminar esta lección vas a poder montar, con los dos mecanismos reales que n8n ofrece, una barrera que detiene el workflow antes de que una acción sensible ocurra y lo mantiene en pausa hasta que una persona apruebe o rechace; vas a saber cuál de los dos mecanismos corresponde a cada situación; y vas a saber redactar el mensaje que recibe quien aprueba —que es el detalle que decide si esta capa protege de verdad o si solo produce clics automáticos.

Esto importa porque es la única defensa de este módulo que funciona incluso cuando todo lo demás falló. El filtro de la lección 2 dejó pasar el ataque, el aislamiento de la lección 3 no lo detectó, y los permisos de la lección 4 no lo cubren porque issue_refund tiene que existir —TuTienda a veces devuelve dinero de verdad—. En ese escenario, el agente está convencido y va a llamar la tool. La aprobación humana es lo que hace que "el agente está convencido" y "salió dinero" dejen de ser la misma cosa.

Conexión con el módulo, y la frontera con el Módulo 4. En el Módulo 4, lección 5 ya viste este mecanismo, y conviene ser preciso sobre qué parte: allí aprendiste el criterio de negocio —la tabla de reversibilidad, impacto financiero y compromiso frente al cliente que decide qué acciones necesitan aprobación— y viste la existencia de la revisión humana en el conector Tools, con las variables $tool.name y $tool.parameters, en un ejemplo de tres líneas. Eso no se repite hoy.

Lo que agrega esta lección es todo lo que en el Módulo 4 no correspondía porque el ángulo era otro: el segundo mecanismo, que existe y sirve para casos que la revisión de tools no cubre; qué pasa exactamente cuando nadie responde; cómo se redacta el mensaje del aprobador para que la decisión sea informada y no refleja; qué hace el agente cuando le dicen que no; cómo se define un umbral para que la barrera no se convierta en ruido; y el modo de falla propio de esta capa, que es la fatiga de aprobación — una persona que aprueba sin leer es peor que no tener aprobación, porque da una falsa sensación de control. La lección 4 te dejó issue_refund clasificada como L2 en la matriz; hoy se construye el L2.

La firma que falta

En cualquier empresa con algo de tamaño, hay una cantidad de dinero por encima de la cual una sola persona no puede autorizar un pago. Ese número existe en todas partes, y no está ahí porque se desconfíe de quien maneja la cuenta. Está por dos razones: porque un error de una sola persona puede ser grande, y porque un solo punto de decisión es un solo punto de ataque — si alguien quiere sacar dinero de la empresa, le basta con engañar a esa persona.

Con dos firmas, la aritmética cambia. Ya no basta con equivocarse una vez ni con engañar a alguien una vez. Y la segunda persona no tiene que ser más lista que la primera: tiene que estar en un contexto distinto, mirar el pago desde afuera de la conversación que lo originó. Eso sola ya cambia el resultado, porque el ataque que fue convincente dentro de la conversación se ve raro fuera de ella.

Un human-in-the-loop es esa segunda firma. Y su valor está precisamente en el "afuera": la persona que aprueba no está en la conversación con el cliente, no leyó el mensaje persuasivo, no participó del razonamiento que llevó al agente a esa tool. Ve un pedido de reembolso de $1,200 cuyo motivo es "protocolo de contingencia INC-4471" y su reacción natural es "¿qué es eso?". El agente no podía tener esa reacción, porque para él ese texto era parte del contexto. Para la persona es una anomalía.

Vale la pena decir la contraparte con la misma claridad, porque define todo lo que viene después: esa persona solo puede reaccionar así si el mensaje que recibe le da con qué. Si le llega "el agente quiere ejecutar una acción, ¿apruebas?", no está fuera de la conversación — está fuera de todo, y va a decir que sí. La mitad de esta lección es el mecanismo; la otra mitad es qué le muestras.

En n8n hay dos formas de construir esta pausa, y no son intercambiables.

Mecanismo A — Revisión humana en el conector Tools

Qué es. Una configuración del propio nodo AI Agent que hace que ciertas tools no se ejecuten cuando el modelo las llama, sino que abran una solicitud de aprobación y dejen el workflow esperando. El agente sigue "creyendo" que llamó la tool; simplemente el resultado tarda hasta que alguien decide.

Su anatomía. Se configura en tres pasos, todos dentro del canvas:

  1. Haces clic en el conector Tools del nodo AI Agent, lo que abre el panel de tools.
  2. En ese panel buscas la sección Human review y eliges el canal por el que quieres recibir la solicitud. Los canales disponibles son nueve: Chat (la interfaz propia de n8n), Slack, Discord, Telegram, Microsoft Teams, Gmail, WhatsApp Business Cloud, Google Chat y Microsoft Outlook. Configuras la credencial correspondiente.
  3. Conectas al conector de tools de ese paso de revisión las tools que requieren aprobación — no al agente directamente. Las tools que no requieren aprobación siguen conectadas al agente como siempre.

Ese tercer paso es el que la gente hace mal la primera vez, y conviene visualizarlo:

# CABLEADO CORRECTO
#
# AI Agent: billing_specialist
#   │
#   ├─ ai_tool ──► lookup_charge        (directo — L0, sin aprobación)
#   ├─ ai_tool ──► open_dispute         (directo — L1, sin aprobación)
#   │
#   └─ ai_tool ──► [Human review: Slack]
#                      │
#                      └─ tools ──► issue_refund   (L2 — con aprobación)

Las variables del paso de revisión. Dentro del nodo de revisión tienes disponible $tool, con dos propiedades:

  • $tool.name — el nombre de la tool que el agente está intentando llamar. Es el nombre del nodo tal como aparece en el lienzo.
  • $tool.parameters — los parámetros con los que la está intentando llamar.

Qué pasa al aprobar y al denegar. Si la persona aprueba, la tool se ejecuta con los parámetros que el modelo especificó y el resultado vuelve al agente, que continúa su razonamiento normalmente. Si deniega, la acción se cancela y no corre, y el agente es informado del rechazo — lo que significa que tu System Message necesita decirle qué hacer con esa negativa, porque si no lo dice, el modelo improvisa (y lo más común es que reintente, que es justo lo que no quieres).

Ejemplo trabajado

Vamos a poner issue_refund de TuTienda detrás de revisión humana por Slack, con el mensaje de aprobación escrito como corresponde.

# Nodo: Slack (paso de revisión humana, en el conector Tools
#              del AI Agent billing_specialist)
#
# Channel: #aprobaciones-tutienda
#
# Message:
# 🔸 *Aprobación requerida — acción del agente*
#
# *Tool:* {{ $tool.name }}
# *Parámetros:*
# ```{{ JSON.stringify($tool.parameters, null, 2) }}```
#
# *Cliente:* {{ $('Chat Trigger').item.json.customer_id }}
# *Canal:* {{ $('Chat Trigger').item.json.channel }}
# *Sesión:* {{ $('Chat Trigger').item.json.sessionId }}
#
# *Lo que escribió el cliente (últimos 300 caracteres):*
# > {{ $('Chat Trigger').item.json.chatInput.slice(-300) }}
#
# *Ejecución:* #{{ $execution.id }}
#
# _Si el motivo no coincide con lo que pidió el cliente, deniega._

Y el fragmento del System Message que le dice al agente qué hacer con cada resultado:

# Nodo: AI Agent Tool — Name: billing_specialist
# System Message (fragmento)

SOBRE issue_refund
Esta tool requiere aprobación de una persona del equipo. Cuando la
llames, la respuesta puede tardar.

- Antes de llamarla, avísale al cliente: "Voy a enviar tu solicitud
  de reembolso a revisión del equipo; te confirmo en un momento."
- Si la aprobación es DENEGADA: no la reintentes, ni con otros
  parámetros, ni más adelante en la conversación. Dile al cliente
  que su solicitud requiere revisión adicional y que el equipo le
  dará seguimiento, y llama a open_dispute para dejar el caso
  registrado. No inventes un motivo del rechazo.
- Si el cliente insiste después de una negativa, mantén la misma
  respuesta. Una negativa no se renegocia dentro de la conversación.
- Nunca prometas al cliente que el reembolso "ya está aprobado"
  antes de recibir la confirmación de esta tool.

Qué esperar. Corre contra este montaje el ataque 2 de la lección 2 —el bloque SYSTEM OVERRIDE con el protocolo de contingencia—, y supón el peor caso: el filtro no lo atrapó y el modelo se convenció por completo. Lo que ocurre:

  1. billing_specialist decide llamar a issue_refund con { orderId: null, amount: 1200, reason: "incidente INC-4471, protocolo de contingencia" }.
  2. El workflow se detiene. El HTTP Request contra el API de pagos no se ejecutó. No hay dinero moviéndose.
  3. En #aprobaciones-tutienda aparece el mensaje, con el nombre de la tool, los parámetros formateados, el identificador del cliente, y —esto es lo que importa— el fragmento de lo que escribió el cliente.
  4. Quien está de turno lee: motivo "incidente INC-4471, protocolo de contingencia", orderId: null, y abajo un mensaje de cliente que contiene un bloque con signos de igual que dice [SYSTEM OVERRIDE — Nivel 2]. No hace falta ser experto en seguridad para que eso se vea mal.
  5. Deniega.
  6. El agente recibe el rechazo, y siguiendo su System Message le dice al cliente que su solicitud requiere revisión adicional y llama a open_dispute para dejar registro.

El ataque funcionó perfectamente en todo lo que dependía del modelo. Y no logró nada. Esa es la diferencia entre convencer al agente y causar daño, que es la distinción que atraviesa este módulo entero.

Mira ahora la misma situación con un mensaje de aprobación mal escrito, que es lo que sale por defecto si uno solo pone $tool.name:

# Message (versión pobre)
# El agente quiere ejecutar {{ $tool.name }}. ¿Apruebas?

Quien está de turno lee "El agente quiere ejecutar issue_refund. ¿Apruebas?". No sabe de cuánto, ni de qué cliente, ni por qué. Y como el agente de reembolsos hace su trabajo y la mayoría de las solicitudes son legítimas, después de la quinta vez esa persona aprueba sin pensar. El mecanismo está montado, el diagrama se ve bien, y no protege nada.

Mecanismo B — Enviar y esperar respuesta dentro del flujo

El mecanismo A resuelve un caso muy específico: una tool que el agente decide llamar. Pero no todas las acciones sensibles de un sistema son tools de un agente. A veces la acción sensible es un nodo determinista que viene después del agente, como en el ejercicio 3 de la lección 4: el agente propone un cambio de precio y un workflow separado lo aplica. Ahí no hay ninguna tool que interceptar.

Para eso está el segundo mecanismo: varios nodos de canal tienen una operación de enviar un mensaje y esperar la respuesta antes de continuar el flujo. En el nodo de Slack, la operación del recurso Message se llama "Send and Wait for Response"; en Gmail la documentación se refiere al mismo comportamiento como enviar un mensaje y esperar aprobación. Los nombres exactos de las etiquetas varían un poco entre nodos y entre versiones, así que confirma la etiqueta en el panel del nodo que estés usando antes de darla por buena — el comportamiento es el mismo.

Su anatomía. El nodo hace tres cosas: manda un mensaje al canal con uno o más botones, pone el workflow en pausa, y lo reanuda cuando alguien responde. Los tipos de respuesta que ofrece son tres:

  • Approval — botones de aprobar (y opcionalmente rechazar) dentro del mensaje. Es el que usas para una barrera.
  • Free Text — la persona escribe una respuesta libre en un formulario. Sirve cuando necesitas un motivo, no solo un sí o un no.
  • Custom Form — un formulario con los campos que definas. Sirve cuando la aprobación implica corregir algo: aprobar un reembolso pero por otro monto, por ejemplo.

Para el tipo Approval, las opciones habituales son elegir entre solo aprobar o aprobar y rechazar (dos botones), personalizar las etiquetas de los botones —por defecto algo como "Approve" y "Decline"— y mostrar o no una página de confirmación después del clic. Y una opción que conviene mirar siempre: "Limit Wait Time", que reanuda el workflow automáticamente después de un intervalo o a una hora determinada, en lugar de esperar indefinidamente.

Lo que hay debajo. Este comportamiento se apoya en el mismo mecanismo del nodo Wait, que puede reanudarse "On Webhook Call" (una URL generada, $resumeWebhookUrl) o "On Form Submitted". Saberlo sirve por dos motivos. Primero, porque si tu canal de aprobación no es ninguno de los soportados —un sistema interno, una app propia—, puedes armar la pausa a mano con un Wait en modo webhook y mandar tú la URL por donde quieras. Y segundo, por una limitación documentada que ahorra una tarde de depuración: una ejecución parcial del workflow cambia el $resumeWebhookUrl, así que el nodo que envía esa URL a un tercero tiene que correr en la misma ejecución que el nodo Wait. Si estás probando por partes y la aprobación "no reanuda nada", ese es el primer lugar a revisar.

Un detalle honesto sobre la identidad. La documentación de n8n lo dice sin rodeos para el caso del correo: un enlace de aprobación en un email no lleva identidad, así que la salida del nodo te dice la decisión, no quién la tomó. Si tu caso requiere saber quién aprobó —y para reembolsos suele requerirlo, por auditoría—, un canal como Slack en un canal privado con miembros conocidos es mejor punto de partida que el correo, y aun así conviene registrar el contexto por tu cuenta. Verifica qué campos trae realmente la salida del nodo en tu versión abriendo el panel después de una aprobación de prueba, en vez de asumir un nombre de campo.

Cuándo usar cada mecanismo

SituaciónMecanismoPor qué
El agente decide llamar una tool sensibleA — Human review en el conector ToolsIntercepta la llamada sin que tengas que sacar la tool del agente; $tool.parameters te da exactamente lo que el modelo quiso hacer
Un paso determinista después del agente ejecuta la acciónB — Send and Wait en un nodo de canalNo hay ninguna tool que interceptar; la pausa va en el flujo
Necesitas que la persona corrija un valor, no solo aprobarB, con Response Type Custom FormEl tipo Approval solo devuelve una decisión; el formulario devuelve datos
Necesitas un motivo escrito del rechazoB, con Response Type Free TextÚtil para auditoría y para mejorar el prompt del agente después
Tu canal de aprobación no está entre los soportadosWait en modo webhook, a manoEs la base de todo lo anterior; te da control total a cambio de trabajo

Y una combinación que en la práctica es la más común: el mecanismo A para las tools del agente, y el B para el paso final de un flujo de propuesta como el del ejercicio 3 de la lección 4. No compiten.

Qué ve el aprobador

Esta sección es corta y es la que más cambia el resultado. Un mensaje de aprobación debe permitir decidir sin abrir n8n. Si para entender la solicitud hay que ir a buscar la ejecución, nadie va a ir, y todos van a aprobar.

Cinco campos, y ninguno sobra:

  1. Qué acción exactamente, con sus parámetros formateados y legibles. JSON.stringify(..., null, 2) dentro de un bloque de código, no el objeto crudo en una línea.
  2. Sobre quién o sobre qué recae, con el identificador que la persona pueda reconocer o buscar: cliente, pedido, factura.
  3. Por qué el agente cree que corresponde — el campo reason o equivalente, tal como lo escribió el modelo. Este campo es el que delata los ataques, porque un motivo inventado suena inventado.
  4. El origen, es decir un fragmento del texto que llevó a esto. Es lo que permite que la persona vea el bloque raro que el agente no vio como raro.
  5. Un identificador para investigar después: el $execution.id y el sessionId. Sin eso, cuando algo salga mal en dos semanas no vas a poder reconstruir nada — y la lección 7 depende de que exista.

Y dos cosas que conviene no poner: datos personales completos que no hagan falta para decidir (un correo o una tarjeta enteros en un canal de Slack son una fuga esperando pasar) y una recomendación del propio agente sobre si aprobar o no. Lo segundo suena útil y es contraproducente: si el mensaje dice "el agente considera que este reembolso procede", acabas de trasladar la decisión de vuelta al modelo, que es exactamente lo que esta capa quería evitar.

El rechazo, el silencio y la fatiga

Tres cosas que pasan en producción y que un diagrama no muestra.

El rechazo. Ya lo cubriste en el System Message del ejemplo trabajado, pero vale la pena insistir en la línea más importante: "no la reintentes". Un agente al que le deniegan una acción y que no tiene instrucción al respecto tiende a intentar de nuevo, a veces con parámetros ligeramente distintos —bajando el monto, cambiando el motivo— porque interpreta el rechazo como una objeción a los detalles. El resultado es una cadena de solicitudes de aprobación por el mismo caso, que es la forma más rápida de agotar la paciencia de quien aprueba. Escríbelo explícitamente.

El silencio. ¿Qué pasa si nadie responde? Con el mecanismo A, el workflow queda esperando. Con el mecanismo B tienes "Limit Wait Time", y conviene usarlo siempre. Pero la pregunta de diseño es qué significa el silencio, y solo hay una respuesta segura: el silencio es un no. Si tu flujo, al expirar el tiempo, ejecuta la acción "porque nadie se opuso", acabas de construir una barrera que un atacante atraviesa mandando su solicitud un sábado a las tres de la mañana. Al vencer el plazo: no ejecutar, avisar al cliente que su caso quedó en revisión manual, y dejar el registro.

Y hay una consecuencia práctica de que el workflow espere: durante ese tiempo, la conversación del cliente está detenida. En un chat web eso se ve como un agente que no contesta. Por eso el System Message del ejemplo le pide al agente que avise antes de llamar la tool — un "voy a enviar esto a revisión, te confirmo en un momento" convierte una espera incómoda en un comportamiento normal de atención al cliente.

La fatiga. Es el modo de falla propio de esta capa y el menos discutido. Una persona que recibe treinta solicitudes de aprobación al día deja de leerlas alrededor de la quinta. A partir de ahí el botón de aprobar es un trámite, y tu barrera se convirtió en un retardo de dos minutos. Lo grave es que el sistema se ve igual de seguro en el diagrama, en la demo y en la documentación.

Se combate con un umbral, no con disciplina. La idea: no todo lo sensible es igual de sensible.

# Política de aprobación — TuTienda (documento, no un nodo)
#
# issue_refund
#   amount <= $200 y el cliente tiene < 2 reembolsos en 90 días
#       → automático, sin aprobación
#       → registro obligatorio en refund_log
#       → tope agregado: $2,000 por día en todo el sistema;
#         superado el tope, TODO pasa a aprobación
#
#   amount entre $200 y $2,000
#       → aprobación por Slack, canal #aprobaciones-tutienda
#
#   amount > $2,000  ó  cliente con 2+ reembolsos en 90 días
#       → NO existe como acción del agente (L3)
#       → open_dispute y seguimiento manual del equipo

Fíjate en tres decisiones de esa política:

El umbral libera atención. Si el 80% de los reembolsos son de menos de $200, quien aprueba pasa de treinta solicitudes diarias a seis. Seis se leen.

El tope agregado es la red bajo el umbral. Un ataque que descubra que hay un límite de $200 va a intentar cien reembolsos de $199. El tope diario de $2,000 corta eso al décimo intento y además dispara una anomalía visible: de golpe todo empieza a pedir aprobación, y alguien pregunta por qué.

Lo automático no es lo no registrado. Cada reembolso automático deja su fila. La aprobación humana y la trazabilidad son capas distintas, y la segunda no se relaja porque exista la primera — que es justamente el material de la lección 7.

Errores comunes

Poner aprobación humana en todo lo que suene delicado (conceptual). Qué pasa: alguien clasifica como L2 el reembolso, la disputa, el ticket, el cambio de dirección y el correo de confirmación, y conecta las cinco tools detrás de la revisión humana. La persona de turno recibe treinta y cinco solicitudes el primer día, aprueba las últimas veinte sin leer, y al tercer día pide que le quiten las notificaciones. Por qué pasa: al montar el mecanismo por primera vez, agregar una tool más a la lista cuesta un cable y se siente como más seguridad; el costo aparece días después y lo paga otra persona. Cómo detectarlo: cuenta cuántas solicitudes genera tu sistema por día en tráfico real, y pregúntale a quien aprueba cuántas leyó completas — si el número es "las primeras", el umbral está mal. Cómo corregirlo: la aprobación humana se reserva para lo irreversible y lo financiero por encima de un umbral, y el resto se resuelve con las palancas de la lección 4 y con registro; una barrera que se cruza sin leer no es una barrera.

Mandar un mensaje de aprobación que no permite decidir (práctico). Qué pasa: el mensaje dice "El agente quiere ejecutar issue_refund, ¿apruebas?" y nada más. Quien lo recibe no tiene el monto, ni el cliente, ni el motivo, ni el texto que originó la solicitud, así que su única estrategia posible es confiar en el agente — que es exactamente lo que esta capa existía para no hacer. Por qué pasa: $tool.name es lo primero que aparece en la documentación y produce un mensaje que "funciona"; el resto de los campos hay que ir a buscarlos a otros nodos con expresiones, y eso es trabajo. Cómo detectarlo: enséñale un mensaje de aprobación de tu sistema a alguien que no lo construyó y pídele que decida; si tiene que preguntarte algo, falta un campo. Cómo corregirlo: los cinco campos de esta lección —acción con parámetros formateados, sobre quién recae, motivo del agente, fragmento del texto de origen, e identificador de ejecución— y todos legibles sin abrir n8n.

Dejar que el vencimiento del plazo ejecute la acción (práctico). Qué pasa: alguien configura "Limit Wait Time" en dos horas y conecta la salida a la ejecución de la acción, razonando que si nadie se opuso en dos horas es porque estaba bien. La barrera queda abierta todas las noches, todos los fines de semana y todos los feriados, que es precisamente cuando un ataque conviene lanzarlo. Por qué pasa: al cablear el nodo, la salida "el tiempo expiró" parece un caso de continuación normal del flujo, y dejarla sin conectar se siente como un flujo incompleto. Cómo detectarlo: manda una solicitud de aprobación de prueba y no respondas; si al vencer el plazo la acción se ejecutó, tienes el fallo. Cómo corregirlo: el vencimiento va a la misma rama que el rechazo —no ejecutar, informar al cliente que quedó en revisión manual, registrar— y si el volumen de vencimientos es alto, el problema no es el plazo sino que hay demasiadas solicitudes, y eso se arregla con el umbral.

Ejercicios

Ejercicio 1 — Escribe el mensaje de aprobación. order_specialist tiene una tool cancel_order que cancela un pedido contra el API de la transportadora. Es irreversible una vez que la transportadora la procesa. Escribe el mensaje que recibiría quien aprueba, por Telegram, con los cinco campos de esta lección.

Ver solución
# Nodo: Telegram (paso de revisión humana en el conector Tools
#                 del AI Agent order_specialist)
#
# Message:
# ⚠️ *Cancelación de pedido — requiere aprobación*
#
# *Acción:* {{ $tool.name }}
# ```{{ JSON.stringify($tool.parameters, null, 2) }}```
#
# *Pedido:* {{ $tool.parameters.orderId }}
# *Cliente:* {{ $('Chat Trigger').item.json.customer_id }}
# *Motivo que dio el agente:* {{ $tool.parameters.reason }}
#
# *Mensaje del cliente (últimos 300 caracteres):*
# > {{ $('Chat Trigger').item.json.chatInput.slice(-300) }}
#
# *Ejecución:* #{{ $execution.id }}
# *Sesión:* {{ $('Chat Trigger').item.json.sessionId }}
#
# _Irreversible una vez procesada por la transportadora._
# _Ante cualquier duda sobre el motivo, deniega._

Tres detalles que valen:

$tool.parameters.orderId aparece dos veces, dentro del JSON completo y también suelto. Es redundante a propósito: el JSON sirve para verificar todo, la línea suelta sirve para leer de un vistazo en la notificación del teléfono.

El motivo va en su propia línea, no enterrado en el JSON. Es el campo que delata los ataques y el que hay que leer sí o sí.

La última línea recuerda la consecuencia. Quien aprueba a las once de la noche desde el celular no necesariamente recuerda qué implica cancelar un pedido en tránsito.

Por qué funciona: el mensaje permite decidir sin salir de Telegram. Esa es la única prueba que importa.

Ejercicio 2 — Elige el mecanismo. Para cada caso, di si corresponde el mecanismo A (revisión humana en el conector Tools), el B (enviar y esperar respuesta en el flujo), o ninguno de los dos, y por qué.

(a) El agente de facturación quiere emitir un reembolso. (b) Un workflow nocturno detecta pedidos con más de 10 días de retraso y quiere mandar un correo de disculpa con un cupón a cada cliente afectado. (c) El agente propone un cambio de precio y un workflow separado lo aplica al día siguiente. (d) El agente quiere consultar el estado de un pedido. (e) El agente redacta la respuesta final al cliente y alguien del equipo quiere revisarla antes de que se envíe, con posibilidad de corregir el texto.

Ver solución

(a) Mecanismo A. Es una tool que el agente decide llamar en medio de su razonamiento. La revisión en el conector Tools la intercepta sin sacarla del agente, y $tool.parameters te da el monto y el motivo exactos.

(b) Mecanismo B. No hay ningún agente decidiendo — es un workflow determinista. La pausa va en el flujo, con un nodo de canal en modo enviar-y-esperar, antes del nodo que manda los correos. Y aquí conviene un detalle: el mensaje debe decir cuántos correos y cupones se van a enviar, porque el riesgo no es un correo, son cuatrocientos.

(c) Mecanismo B. Es el caso del ejercicio 3 de la lección 4. El agente ya terminó su trabajo cuando insertó la propuesta; la acción sensible ocurre en otro workflow, sin agente, y ahí no hay tool que interceptar.

(d) Ninguno. Es L0, una lectura. Ponerle aprobación es exactamente el error de fatiga: treinta solicitudes diarias por consultar pedidos harían que nadie lea las de reembolso.

(e) Mecanismo B, con Response Type Custom Form o Free Text. El tipo Approval no sirve porque no basta con aprobar o rechazar: hay que poder corregir el texto. Un formulario devuelve el texto editado, que es lo que después se envía al cliente. Vale la pena notar que esto convierte al agente en un redactor asistido y ya no en un agente autónomo — es una decisión de producto legítima, y para una tienda que recién arranca con IA suele ser el paso intermedio correcto.

Por qué funciona: la pregunta que separa A de B es dónde vive la acción sensible. Si la ejecuta el agente llamando una tool, es A. Si la ejecuta un nodo del flujo, es B. Y (e) muestra un tercer eje: cuando la aprobación necesita devolver datos y no solo una decisión, el tipo de respuesta deja de ser Approval.

Ejercicio 3 — Diseña la política de umbrales. TuTienda te dice que su equipo de soporte son dos personas y que no pueden atender más de diez aprobaciones al día entre las dos. El sistema procesa unos 300 casos diarios; de esos, unos 40 terminan en reembolso, con esta distribución: 28 de menos de $150, 9 entre $150 y $800, y 3 por encima de $800. Escribe la política.

Ver solución
# Política de aprobación — issue_refund — TuTienda
#
# TRAMO 1 — automático  (esperado: ~28/día)
#   amount <= $150
#   Y el cliente tiene 0 reembolsos previos en 90 días
#   Y el monto no supera el total del pedido original
#     → se ejecuta sin aprobación
#     → fila obligatoria en refund_log
#
# TRAMO 2 — aprobación por Slack  (esperado: ~9/día)
#   amount entre $150 y $800
#     → mecanismo A, canal #aprobaciones-tutienda
#     → Limit Wait Time: 4 horas
#     → al vencer: NO ejecutar, open_dispute, avisar al cliente
#
# TRAMO 3 — fuera del alcance del agente  (esperado: ~3/día)
#   amount > $800
#   Ó cliente con 1+ reembolso previo en 90 días
#     → el agente NO tiene esta capacidad (L3)
#     → llama a open_dispute y escala al equipo
#
# TOPES AGREGADOS (cortan el abuso del tramo automático)
#   · $1,500/día en reembolsos automáticos en todo el sistema
#   · 3 reembolsos automáticos por hora
#     → superado cualquiera de los dos, TODO pasa al tramo 2
#       y se notifica al canal que el tope se activó

El cálculo: el tramo 2 genera unas 9 aprobaciones diarias, dentro del presupuesto de 10. El tramo 3 no genera aprobaciones porque no es una acción del agente — es una escalación, que el equipo atiende en su flujo normal de trabajo y no como una interrupción con botón.

Dos decisiones que conviene defender:

El corte en $150 no salió de la nada. Salió de la distribución real: es el número que deja el volumen de aprobaciones dentro de lo que el equipo puede leer. Un umbral que no se calcula contra la capacidad del equipo termina siendo fatiga.

El historial de reembolsos es parte del criterio, no solo el monto. Un cliente que pide su cuarto reembolso de $140 en dos meses es un patrón, y ese patrón es más informativo que el monto individual. Ese chequeo tiene que ser determinista —una consulta a refund_log, no un juicio del modelo.

Por qué funciona: la política convierte una capa que podría ahogar al equipo en una que consume nueve decisiones diarias informadas, y los topes agregados cubren el hueco que deja el tramo automático — que es el hueco que un atacante buscaría en cuanto descubra que existe un umbral.

Resumen y siguiente paso

El human-in-the-loop es la segunda firma: una persona fuera de la conversación que mira la acción antes de que ocurra, y que por estar fuera puede ver como anómalo lo que dentro del contexto se veía normal. n8n lo ofrece de dos formas que no son intercambiables: la revisión humana en el conector Tools del AI Agent —con sus nueve canales y las variables $tool.name y $tool.parameters— para interceptar una tool que el agente decide llamar; y la operación de enviar y esperar respuesta en un nodo de canal, con sus tipos Approval, Free Text y Custom Form y su "Limit Wait Time", para las acciones sensibles que ejecuta el flujo y no el agente. Debajo de ambas está el nodo Wait, con su reanudación por webhook o por formulario.

Y alrededor del mecanismo, lo que decide si sirve: un mensaje con los cinco campos que permiten decidir sin abrir n8n; un System Message que le diga al agente que no reintente tras un rechazo; un vencimiento que signifique "no"; y un umbral calculado contra la capacidad real del equipo, con topes agregados, para que la barrera no se degrade en fatiga.

Antes de avanzar a la lección 6 deberías poder: decidir entre el mecanismo A y el B según dónde vive la acción sensible; escribir un mensaje de aprobación completo con expresiones sobre $tool y sobre el trigger; explicar por qué el silencio nunca puede significar aprobación; y proponer un umbral para tu propio sistema partiendo del volumen real de casos, no de una intuición.

Con esto cierras el frente del atacante. Las lecciones 2 a 5 se ocuparon todas de la misma pregunta: qué pasa cuando alguien intenta que tu agente haga algo que no debe. La lección 6 cambia de enemigo por completo. No hay atacante, no hay injection, los permisos están bien puestos y la aprobación funciona — y el agente igual le dice al cliente que su pedido llega el jueves, un dato que ninguna tool devolvió nunca. Ese es el problema de la alucinación, y su defensa no es un filtro ni un permiso: es verificar, campo por campo, que lo que el agente afirma coincida exactamente con lo que los datos dicen.

Recursos

  • Human-in-the-loop for tools — n8n Docs — el mecanismo A completo: la sección Human review en el panel de Tools, los nueve canales de aprobación, $tool.name y $tool.parameters, y qué ocurre al aprobar y al denegar.
  • Wait node — n8n Docs — las condiciones de reanudación ("On Webhook Call", "On Form Submitted"), la opción de limitar el tiempo de espera y la advertencia sobre $resumeWebhookUrl en ejecuciones parciales.
  • Slack node — n8n Docs — la operación "Send and Wait for Response" del recurso Message, base del mecanismo B; confirma en el panel las etiquetas exactas de los tipos de respuesta en tu versión.
  • Gmail node — n8n Docs — la variante por correo del mismo mecanismo, incluida la advertencia de que un enlace de aprobación no lleva identidad de quien respondió.
  • AI Agent node — n8n Docs — el nodo donde vive el conector Tools desde el que se configura toda la revisión humana.