Módulo 4: Herramientas: el agente que actúa sobre sistemas reales

3. Tools nativas de n8n: buscar, crear, enviar

Descripción

Al terminar esta lección vas a poder tomar un nodo de acción que ya conoces de construir workflows normales —el nodo de Slack, en el ejemplo de esta lección— y conectarlo directamente al agente como una herramienta propia, restringida a una sola operación (buscar, crear o enviar), con una descripción que le dice al modelo cuándo usarla y con $fromAI() rellenando solo los datos que cambian en cada ejecución.

Esto importa porque es, con diferencia, la forma más común de dar manos a un agente en producción. No necesitas escribir código ni levantar un servidor propio: casi cualquier nodo que ya usarías en un workflow normal —Slack, y en la próxima lección Gmail, Sheets, tu base de datos— puede convertirse en una tool con la misma configuración que ya sabes hacer, más tres decisiones nuevas que esta lección te enseña a tomar bien. Según la validación de mercado detrás de esta guía, los agentes que actúan sobre sistemas reales aparecen en el 57 % de las ofertas que piden estas habilidades —y ese "actuar" casi siempre empieza exactamente aquí: con un nodo nativo conectado como tool, no con una integración construida desde cero.

Conexión con el módulo: en la lección anterior viste el mecanismo de tool calling —cómo el modelo decide qué herramienta invocar, con qué datos, y qué hace con el resultado—. Esta lección no repite ese mecanismo; lo pone en práctica con el tipo de tool más simple de construir: un nodo nativo de n8n restringido a una operación. Todavía no vas a conectar sistemas de negocio completos con sus propias credenciales complejas —Gmail, Sheets, una base de datos, una API externa por HTTP—, eso es exactamente el trabajo de la próxima lección.

De nodo de workflow a herramienta del agente

Imagina que le entregas a alguien nuevo en el equipo un llavero completo con quince llaves sin etiqueta, y le dices "una de estas abre el cuarto de suministros, arréglatelas". Va a perder tiempo probando, y en el peor caso abre la puerta equivocada. Ahora imagina que en cambio le entregas una sola llave, con una etiqueta que dice exactamente "cuarto de suministros — usar solo para reponer inventario". No hay ambigüedad: sabe qué abre esa llave y cuándo usarla, y no tiene acceso a las otras catorce puertas aunque quisiera.

Conectar un nodo nativo de n8n como tool de un agente es literalmente eso: le entregas una llave a la vez, no el llavero completo. n8n lo permite con casi cualquier nodo de acción que ya conoces —la documentación de cada nodo compatible lo dice de forma explícita: "This node can be used to enhance the capabilities of an AI agent", y aclara que, usado así, "many parameters can be set automatically, or with information directed by AI"—. El mecanismo concreto: abres el conector Tools del nodo AI Agent —eso abre el Tools Panel, un buscador de nodos igual al que usas para armar cualquier workflow— y ahí eliges el nodo que quieres dar como herramienta.

La diferencia frente a usar ese mismo nodo en un workflow normal es que, cuando lo conectas como tool, tienes que tomar tres decisiones que en un workflow lineal no existen:

  1. Qué operación exacta hace esta instancia del nodo. Un tool no es "el nodo de Slack" en abstracto —es una operación fija, como Search o Send—. Si necesitas que el agente pueda buscar Y enviar, conectas dos instancias del nodo, cada una restringida a su propia operación.
  2. Qué parámetros fijas tú, y cuáles rellena el modelo. Cualquier campo puede quedar en un valor fijo —como en un workflow normal— o envuelto en $fromAI(key, description, type, defaultValue), la misma función que viste en la lección anterior, para que el modelo lo complete en tiempo de ejecución según el pedido del usuario. n8n incluso te ahorra escribir la expresión a mano: junto a cada parámetro compatible hay un pequeño ícono de estrella —actívalo y n8n escribe el $fromAI() por ti, usando el nombre del parámetro como key—. Para un prototipo rápido alcanza; para un tool que vas a dejar en producción, vale la pena escribir tú la description y el type, porque son justo la pista que el modelo usa para acertar.
  3. Qué nombre y qué descripción le das a esa herramienta. El modelo no ve el nodo por dentro —decide qué tool llamar leyendo su nombre y su descripción, exactamente como aprendiste en la lección anterior sobre cómo el modelo elige entre varias tools—. Dos tools de Slack con nombres genéricos como "Slack" y "Slack" son, para el modelo, casi indistinguibles.

Nota algo importante sobre el vocabulario del módulo: n8n también ofrece nodos construidos específicamente para ser tools y que no existen fuera de ese rol —Wikipedia, SerpAPI, Custom Code Tool, HTTP Request Tool, Call n8n Workflow Tool, entre otros—. Esos vienen después, repartidos en distintas lecciones de este módulo. Esta lección y la siguiente cubren la otra mitad del mapa: nodos de acción normales, los mismos que ya sabes configurar, conectados al agente en modo tool.

Ejemplo trabajado

El equipo de operaciones de TuTienda quiere que un agente vigile los pagos rechazados y avise por Slack sin que nadie tenga que escribir el aviso a mano. El workflow arranca con un Webhook que recibe alertas del sistema de pagos:

# Payload que llega al Webhook cuando un pago falla varias veces seguidas
{
  "orderId": "8834",
  "failedAttempts": 3,
  "reason": "tarjeta rechazada por el banco emisor"
}

Ese payload se convierte en el mensaje que recibe el agente: "El pedido #8834 tuvo 3 intentos de pago rechazados. Motivo: tarjeta rechazada por el banco emisor." El agente tiene tres tools conectadas al conector Tools, las tres sobre el nodo Slack, cada una restringida a una sola operación:

# Tool 1 — search_slack_messages
Resource     = "Message"                                                    # fijo: este tool solo busca
Operation    = "Search"                                                     # fijo: nunca envía ni borra
Channel      = "#pagos-incidentes"                                          # fijo: alcance acotado por ti
Search Query = {{ $fromAI("searchQuery", "Palabras clave del incidente, por ejemplo el número de pedido", "string") }}
Description  = "Busca si ya se habló de este pedido en el canal de incidentes de pagos antes de abrir algo nuevo."
# Tool 2 — create_slack_channel
Resource     = "Channel"                                                    # fijo
Operation    = "Create"                                                     # fijo: nunca archiva ni renombra
Channel Name = {{ $fromAI("channelName", "Nombre en minúsculas y guiones, formato incident-payments-<orderId>", "string") }}
Description  = "Crea un canal dedicado cuando un incidente de pago no tiene canal previo."
# Tool 3 — send_slack_message
Resource    = "Message"                                                     # fijo
Operation   = "Send"                                                        # fijo: nunca busca ni borra
Channel     = {{ $fromAI("channel", "Canal donde avisar, normalmente el canal de incidente recién creado", "string") }}
Text        = {{ $fromAI("messageText", "Resumen claro del incidente para el equipo", "string") }}
Description = "Envía un mensaje de aviso a un canal de Slack ya existente."

Qué esperar. El agente recibe la alerta del pedido #8834 y razona en este orden, aplicando el mismo ciclo de tool calling que viste en la lección anterior:

1. Llama a search_slack_messages con searchQuery = "8834"
   → Resultado: 0 mensajes encontrados en #pagos-incidentes.
2. Como no hay nada previo, llama a create_slack_channel
   con channelName = "incident-payments-8834"
   → Resultado: canal #incident-payments-8834 creado.
3. Llama a send_slack_message con
   channel = "#incident-payments-8834"
   messageText = "Pedido #8834: 3 intentos de pago rechazados (tarjeta rechazada por el banco emisor). Revisar con el cliente."
   → Resultado: mensaje enviado.
4. Responde al workflow: "Abrí el canal #incident-payments-8834 y avisé al equipo."

Interpretación: cada llamada usó una tool distinta porque cada una tenía una operación y una descripción sin ambigüedad —el modelo nunca tuvo que adivinar si "buscar" y "enviar" eran la misma acción con parámetros distintos, porque literalmente no lo son: son tres nodos separados—. Y ninguno de los tres pudo salirse de su carril —search_slack_messages no tiene forma de enviar nada, así esté apuntando al mismo canal— porque tú fijaste Resource y Operation, no el modelo.

Qué fijas y qué dejas en manos del modelo

La configuración de arriba esconde un patrón que vale la pena nombrar aparte, porque lo vas a repetir con cada nodo nativo que conectes como tool, en esta lección y en la próxima:

Parámetro¿Fijo o $fromAI()?Por qué
Resource y OperationFijo, siempreDeciden QUÉ puede hacer la tool. Dejarlo en manos del modelo significa que una sola tool podría terminar buscando, creando o enviando según le convenga —perdiste el control sobre la operación desde el diseño—.
Channel en search_slack_messagesFijoAcota DÓNDE busca. Sin este límite, el agente podría buscar en cualquier canal de la empresa, incluyendo uno que no le corresponde revisar.
Search Query, Channel Name, Text$fromAI()Son los DATOS que cambian en cada ejecución —el número de pedido, el motivo, el resumen—. El modelo los conoce porque vienen en el mensaje que recibió; tú no puedes fijarlos de antemano porque no sabes qué pedido va a fallar mañana.

La regla corta: todo lo que decide qué puede hacer la herramienta lo fijas tú al diseñarla; todo lo que decide con qué datos se ejecuta esa acción concreta se lo dejas al modelo. La lección 5 de este módulo va a formalizar esta misma idea con un nombre —contratos de herramientas y límites de confianza— y la va a llevar más allá de Resource/Operation. Por ahora, con esta regla alcanza para que ningún tool tuyo haga algo que no decidiste que pudiera hacer.

Errores comunes

Dejar Resource u Operation en manos de $fromAI() en vez de fijarlos (conceptual). Qué pasa: alguien envuelve Resource y Operation en $fromAI() pensando "así el agente es más flexible, puede decidir la acción completa", y termina con una sola tool de Slack que a veces busca, a veces envía y, si el prompt lo empuja lo suficiente, hasta borra un mensaje —todo desde el mismo nodo, sin que nadie lo haya autorizado explícitamente para cada caso—. Por qué pasa: es tentador tratar $fromAI() como una forma genérica de "hacer todo dinámico", pero la función está pensada para los datos de una acción, no para la acción misma. Cómo detectarlo: revisa qué campos de cada tool tienen $fromAI() —si Resource u Operation aparecen ahí en vez de un valor fijo, esa tool puede ejecutar más de lo que su nombre promete—. Cómo corregirlo: fija Resource y Operation a un valor concreto por instancia de tool; si necesitas varias acciones, agrega varias instancias, cada una con su propio nombre y descripción.

Dar nombres o descripciones genéricas a varias tools del mismo nodo (conceptual). Qué pasa: conectas search_slack_messages, create_slack_channel y send_slack_message, pero les dejas a las tres el nombre por defecto que propone n8n —algo genérico como "Slack"— o descripciones casi idénticas ("interactúa con Slack"). El agente, ante un pedido de "avisa al equipo", termina invocando la tool equivocada, o intenta usar search_slack_messages para enviar un mensaje. Por qué pasa: el modelo no lee el nodo por dentro para saber qué hace cada tool —lee exactamente el nombre y la descripción que tú escribiste, igual que aprendiste en la lección anterior sobre cómo el modelo decide qué tool invocar—. Si tres tools se ven casi iguales desde afuera, para el modelo lo son. Cómo detectarlo: revisa la traza de ejecución del agente —la misma que usaste en la lección anterior— y compara qué tool invocó contra cuál necesitabas para ese pedido; nombres o descripciones repetidas entre tools son la señal de alerta antes de que falle. Cómo corregirlo: nombra cada tool con un verbo y un objeto claro (search_slack_messages, no slack_tool_1) y escribe una descripción que diga, en una frase, cuándo usar esa tool y no otra.

Probar el nodo de forma aislada mientras tiene campos con $fromAI() (práctico). Qué pasa: quieres probar rápido que la configuración de create_slack_channel funciona, le das clic a "Test step" directamente sobre el nodo Slack, fuera del flujo del agente, y la ejecución falla o el campo Channel Name queda vacío. Por qué pasa: $fromAI() solo tiene sentido —y solo se resuelve— cuando el nodo está conectado al conector Tools de un AI Agent y es el agente el que lo invoca durante su razonamiento; la documentación de n8n lo dice sin rodeos: la función "is only available for tools connected to the AI Agent node". Probado aislado, no hay ningún agente decidiendo qué valor poner ahí. Cómo detectarlo: si un nodo con $fromAI() en sus campos falla o produce valores vacíos al probarlo suelto, revisa si lo estás disparando fuera del agente. Cómo corregirlo: para probar una tool con $fromAI(), ejecuta el AI Agent completo con un mensaje de prueba que dispare esa tool —no el nodo aislado—.

Ejercicios

Ejercicio 1 — Predecir la tool correcta. Un agente de operaciones tiene conectadas las mismas tres tools del ejemplo trabajado (search_slack_messages, create_slack_channel, send_slack_message), cada una con su descripción tal como quedaron configuradas. Llega este mensaje: "Ya existe el canal #incident-payments-8834, avisa ahí que el problema se resolvió." ¿Qué tool (o tools) debería invocar el agente, y en qué orden? Justifica usando las descripciones, no una suposición.

Ver solución

Solo send_slack_message, una vez. El mensaje ya indica que el canal existe —no hace falta buscar si hay un canal previo (search_slack_messages es para cuando no se sabe si ya se habló del incidente) ni crear uno nuevo (create_slack_channel es para cuando no hay canal previo)—. El pedido encaja exactamente con la descripción de send_slack_message: "Envía un mensaje de aviso a un canal de Slack ya existente." El agente rellenaría channel = "#incident-payments-8834" y messageText con un resumen de que el problema se resolvió.

Por qué funciona: la descripción de cada tool es lo que el modelo compara contra el pedido —cuando el mensaje ya resuelve la ambigüedad que la tool de búsqueda existe para resolver, no hay razón para invocarla.

Ejercicio 2 — Encontrar el diseño riesgoso. Revisa esta configuración de un tool de Slack conectado a un agente y explica qué está mal, usando lo que viste en "Errores comunes":

# Tool — manage_slack
Resource    = {{ $fromAI("resource", "Message o Channel según haga falta", "string") }}
Operation   = {{ $fromAI("operation", "La operación que el agente considere necesaria", "string") }}
Channel     = {{ $fromAI("channel", "Canal donde operar", "string") }}
Text        = {{ $fromAI("text", "Contenido del mensaje si aplica", "string") }}
Description = "Interactúa con Slack según lo necesite el agente."
Ver solución

Resource y Operation están envueltos en $fromAI() en vez de fijos —esta tool no está restringida a buscar, crear o enviar: puede terminar ejecutando cualquier operación disponible en el nodo de Slack, incluyendo borrar un mensaje o archivar un canal, si el modelo decide que "hace falta"—. Además, la Description es genérica ("según lo necesite el agente"), lo que no le da al modelo ningún criterio real para decidir cuándo usar esta tool frente a otras —y si hay más de una tool de Slack conectada, esta ambigüedad empeora el problema del segundo error común—.

La corrección: dividir esto en tools separadas, una por operación concreta (como en el ejemplo trabajado), con Resource y Operation fijos y una descripción específica de cuándo usar cada una.

Por qué funciona: una tool bien diseñada tiene una superficie de acción que puedes describir en una frase sin usar la palabra "según" —si necesitas esa palabra, es señal de que en realidad son varias tools disfrazadas de una.

Ejercicio 3 — Diseñar una cuarta tool. El equipo de operaciones de TuTienda quiere agregar una cuarta capacidad: que el agente pueda invitar al canal de incidente a la persona responsable de guardia de finanzas (usuario de Slack @finanzas-guardia) cada vez que crea un canal nuevo. Usando el resource Channel y la operación Invite que viste en esta lección, escribe la configuración completa del tool —qué campos fijas, qué campos dejas en $fromAI(), y una descripción— siguiendo el mismo patrón que las tres tools del ejemplo.

Ver solución
# Tool 4 — invite_user_to_incident_channel
Resource    = "Channel"                                                     # fijo
Operation   = "Invite"                                                      # fijo: nunca crea ni archiva
Channel     = {{ $fromAI("channel", "Canal de incidente al que invitar, normalmente el recién creado", "string") }}
User        = "@finanzas-guardia"                                           # fijo: siempre la misma persona de guardia
Description = "Invita a la persona de guardia de finanzas al canal de un incidente de pago recién creado."

Resource y Operation quedan fijos, igual que en las otras tres tools —esta herramienta solo hace una cosa—. Channel va en $fromAI() porque cambia con cada incidente. User queda fijo, no dinámico, porque el requisito específico es siempre la misma persona de guardia —no tiene sentido dejar que el modelo "adivine" a quién invitar cuando el negocio ya decidió que es siempre la misma cuenta—.

Por qué funciona: no todo lo que varía en teoría necesita $fromAI() —varía por incidente, sí, pero el valor correcto (@finanzas-guardia) es una decisión de negocio fija, no un dato que el mensaje entrante le informe al agente—.

Resumen y siguiente paso

Ya sabes conectar un nodo de acción nativo de n8n —el mismo que usarías en cualquier workflow— al conector Tools de un AI Agent, restringiéndolo a una sola operación con Resource y Operation fijos, dejando en $fromAI() solo los datos que cambian en cada ejecución, y escribiéndole un nombre y una descripción que le permiten al modelo elegir la tool correcta entre varias.

Antes de avanzar deberías poder: explicar por qué Resource y Operation casi nunca deberían ir en $fromAI(); diseñar, para un nodo nativo cualquiera, un conjunto de tools donde cada una tenga una sola operación y una descripción sin ambigüedad; y distinguir, en cualquier parámetro nuevo que veas, si te corresponde fijarlo tú o dejarlo en manos del modelo.

Lo que todavía no viste es cómo se ve esto mismo cuando el sistema al otro lado no es Slack, sino los sistemas de negocio que de verdad mueven una empresa —el correo, una hoja de cálculo compartida, tu propia base de datos, o cualquier API que no tenga un nodo dedicado en n8n—. Con el patrón de esta lección ya interiorizado, eso es exactamente lo que sigue en la próxima lección.

Recursos

  • AI Agent node — n8n Docs — referencia del nodo AI Agent, incluyendo el conector Tools que abriste en esta lección.
  • How tools work — n8n Docs — el catálogo de tool sub-nodes construidos específicamente para agentes (Wikipedia, SerpAPI, Call n8n Workflow Tool, Custom Code Tool, HTTP Request Tool) frente a los nodos de acción normales que usaste aquí.
  • Use AI for parameters — n8n Docs — la referencia completa de $fromAI(key, description, type, defaultValue) y del ícono de estrella que genera la expresión por ti.
  • Slack node — n8n Docs — la lista completa de recursos y operaciones del nodo que usaste en el ejemplo trabajado, incluyendo las que no cubriste (Get permalink, Update, entre otras).
  • Gmail node — n8n Docs — un segundo ejemplo del mismo aviso que vas a ver en cualquier nodo compatible con el modo tool ("This node can be used to enhance the capabilities of an AI agent"), como anticipo de la próxima lección.
  • Data tables — n8n Docs — almacenamiento nativo de n8n, sin credenciales externas, con operaciones de búsqueda y creación de filas —útil si quieres practicar el mismo patrón de esta lección sin depender de una cuenta de Slack—.