news 2026/10/23 9:23:11

n8n Agent 工具设计实战指南:四大工具类型、`$fromAI()` 参数注入与提示词级工具描述

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
n8n Agent 工具设计实战指南:四大工具类型、`$fromAI()` 参数注入与提示词级工具描述
  • AI 技能
  • AI 插件
  • 工作流自动化
  • 流程编排

【免费下载链接】n8n-skills

n8n skillset for Claude Code to build flawless n8n workflows

项目地址:https://gitcode.com/gh_mirrors/n8/n8n-skills
点击查看免费下载

在 n8n 中构建 AI Agent 时,工具(Tool)是模型与外部能力之间的唯一桥梁。本指南基于 n8n-skills 仓库的 n8n-agents 技能包(TOOLS.md 及其配套参考文档),系统讲解四大工具类型的选型、$fromAI()参数注入机制、plumbed 参数隐藏技巧,以及如何把工具名称与描述当作提示词工程来设计。读完你将掌握一套可复用的决策框架与书写规范,能够显著减少"Agent 不调用我的工具"、"参数传错"等常见故障。


核心原则:工具的名称与描述就是提示词

Agent 选择工具的方式只有一条:读取工具的 name 和 description,仅此而已。这两个字段都是 prompt 的一部分,与参数 schema(含$fromAI描述)一起进入模型的上下文。正如 TOOLS.md 开篇所强调的:

要把工具设计当作 API 设计来对待——它做什么、何时使用、每个参数的含义、以及它会如何失败。

SKILL.md 将这一条列为"两个不可妥协原则"之首:工具名称和描述就是提示词的一部分。一个名为tool1、描述为空的工具对模型而言是"不可见的"——模型会跳过它、误选它,或者臆造参数。而且这通常没有报错,只是表现为"Agent 就是不用我的工具"。因此,工具暴露给模型的一切文本,都必须像写 API 文档一样精确。


四大工具类型与 Custom Code Tool

n8n 的 LangChain 节点族(@n8n/n8n-nodes-langchain.*)为 Agent 提供了四种"正规军"工具形态,外加一个特例(Custom Code Tool)。选型原则是:优先选择能覆盖任务的最轻方案。

1. 原生工具节点(Native Tool Node)

预置的"工具版"常规节点:slackTool、gmailTool、googleSheetsTool、toolCalculator、notionTool、httpRequestTool等。它与普通节点行为一致,唯一区别是参数可以由 Agent 通过$fromAI()填充。

维度说明
优点配置最少、经过充分测试、原生体验
缺点一个节点只能做一个操作,多步逻辑放不进来
适用场景能力恰好映射到"一个节点 + 一个操作"

当原生节点缺少某个操作、或需要非标准的参数形态时,可以用 HTTP Request Tool 指向该服务的 API,并复用该服务的预定义凭证类型——这样既复用了已有的 OAuth / API-key 凭证,又能拿到完整的 API 能力。

2. 子工作流作为工具(@n8n/n8n-nodes-langchain.toolWorkflow)

任何工作流都可以变成一个带类型化$fromAI()输入的工具,这是"不止一个节点"场景的默认选择,也是 n8n 构建 Agent 能力的正统方式(详见 SUBWORKFLOW_AS_TOOL.md)。

维度说明
优点工具内拥有 n8n 全部能力——分支、错误处理、子-子工作流、原生节点、自定义逻辑;可跨 Agent 复用;可独立测试
缺点多一层工作流边界,略有延迟
适用场景超过一个节点;逻辑可能被复用;或希望独立可测试

原生 LangChain 中"工具是一个函数",而在 n8n 中"工具可以是一整个工作流":它可以按输入分支(IF/Switch)、调用多个 API 并聚合、自带重试与回退、调用其他子工作流、读写 Data Tables、用n8n_test_workflow与固定数据独立测试、同时被 Agent 和非 Agent 工作流复用。

接线形态(两半结构):子工作流一侧以Execute Workflow Trigger的"Define Below"(类型化字段)模式声明输入,工具侧用 Tool Workflow 节点指向子工作流并绑定参数。SUBWORKFLOW_AS_TOOL.md给出了完整 JSON 示例,其中关键映射是逐输入进行的:

"workflowInputs": { "mappingMode": "defineBelow", "value": { "imagePrompt": "={{ $fromAI('imagePrompt', 'Detailed prompt describing the desired image', 'string') }}", "imageName": "={{ $fromAI('imageName', 'Storage key of an existing image to edit, or empty for new generation', 'string') }}", "sessionId": "={{ $('Chat Trigger').first().json.sessionId }}" } }
  • Agent 填充:={{ $fromAI('paramName', 'description', 'string') }}——由 Agent 决定取值。
  • Plumbed(注入):={{ $('SourceNode').first().json.field }}——由工作流确定值。

触发器的输入模式至关重要:必须是 "Define Below"(类型化字段)而非 passthrough——passthrough 没有 schema,Agent 便没有东西可供$fromAI()填充。类型强制发生在Agent 侧(通过$fromAI的type参数),而非触发器处,允许类型为string/number/boolean/json。此外,sessionId这条映射是硬性约束:绝不能让sessionId进入$fromAI,否则模型会编造一个 UUID;必须从触发器 plumb 进来,保证记忆与按会话键控的工作保持一致。

Agent 能看到的只有:Tool Workflow 节点的名称和 description。它看不到子工作流内部结构、子工作流自己的名字,也看不到sessionId这类 plumbed 值——只有$fromAI参数会出现在工具 schema 里。这意味着你可以大改子工作流内部而不影响 Agent 所见。

工具子工作流的输出契约:调用方收到的是最后一个节点输出的内容,必须固定一种返回形状并跨模式保持一致(例如始终{ imageUrl, imageKey }),输出形状是每个调用方依赖的契约。对"预期内的失败"(如搜索无结果)返回可分支的形状{ "ok": false, "error": "no_results", "message": "..." };对"非预期但可处理的错误"(认证失败、上游宕机、不可恢复输入)则用Stop and Error节点抛出,让 Agent 看到工具错误并自行重试/换工具/上报。子工作流内可失败节点(HTTP、S3、DB)应设置onError: 'continueErrorOutput'并路由到干净的错误响应。

独立测试:先n8n_test_workflow({workflowId, method: "prepare"})确认哪些节点需要固定数据;再按节点 name 构造样本项({json: {...}});然后n8n_test_workflow({workflowId, method: "pinned", pinData})运行并等待;最后核对输出形状。注意 routed 方法需要N8N_MCP_ACCESS_TOKEN及工作流开启 "Available in MCP";默认method: "auto"无法运行无 HTTP 触发器的子工作流。

3. HTTP Request Tool(@n8n/n8n-nodes-langchain.toolHttpRequest)

HTTP Request 节点的包装器,把其参数暴露给 Agent。

维度说明
优点任意 HTTP API 用一个节点就能变成工具
缺点仅限 HTTP;认证 / 重试 / 错误处理都需要自己接线
适用场景调用单个外部 API,且希望 Agent 直接编排

一个必须知道的细节:HTTP Request 自带 HTTP 层超时(默认 5 分钟),对慢端点需要调大options.timeout。而 Agent 工具本身没有超时——Agent 会一直等到工具返回。指向例如 Notion API(复用 Notion 预定义凭证)时,Agent 可以自行组合 path、method、body,覆盖原生节点不暴露的操作。代价是 Agent 现在在"手写 API 请求",更容易出错,需要足够强的模型 + 描述里清晰的端点指引——这扩大了爆炸半径,务必让用户理解这一点。

4. MCP Client Tool(@n8n/n8n-nodes-langchain.mcpClientTool)

把 Agent 连接到任意 MCP 服务器,两种形态:

  • 外部 MCP 服务器——任意第三方或自托管 MCP(GitHub、Linear、Notion、自定义内部服务)。一个节点即可暴露该服务器提供的所有工具。
  • n8n 托管的 MCP——同一实例上的某个工作流以 MCP 访问发布后,用同一个 client 节点指向 n8n 的 MCP trigger URL。让一个工作流服务多个 Agent。
维度说明
缺点工具描述与形态来自服务器,质量参差且难以调优;认证与可达性自备
适用场景现成维护良好的 MCP 服务器已覆盖该能力;或希望一个已发布的工作流服务多个 Agent

Plus:Custom Code Tool(@n8n/n8n-nodes-langchain.toolCode)

纯内联计算(数学、解析、格式化)。其运行时契约是string in / string out、没有$fromAI、没有$helpers,由 n8n-code-tool 技能管辖——写之前必须先读 n8n-code-tool/SKILL.md。经验法则:只要你在代码里想要$fromAI(),就应该用.toolWorkflow而不是.toolCode。典型错误包括$fromAI在 Code Tool 沙箱内不可用(报"No execution data available")、返回对象而非字符串(报"The response property should be a string, but it is an object")、返回工作流式数组(报"Wrong output type returned")。


决策树:到底该用哪种工具?

TOOLS.md 给出了完整的决策树,原文照录如下:

Capability the agent needs? ├── One native node + one operation does it │ → native tool node ├── Native node missing an op / needs custom params for ONE API │ → HTTP Request Tool (with the service's predefined credential) ├── More than one node, or logic that might be reused │ → Sub-workflow as tool (.toolWorkflow) ← default when in doubt ├── Pure deterministic computation, one-off, inline │ → Custom Code Tool (.toolCode) ← see n8n-code-tool └── A maintained MCP server covers it / publish n8n logic to many agents → MCP Client Tool

补充两个反向判断(来自 SUBWORKFLOW_AS_TOOL.md 的 "When NOT to use"):

  • 简单单节点包装——"调这个端点并返回"用 HTTP Request Tool 更短。
  • 一次性、仅本 Agent 使用的纯代码逻辑——几行只存在于别处的 JS/Python 用 Custom Code Tool 即可。决策规则:可复用的业务逻辑 → 子工作流;一次性的 Agent 专用转换 → Code Tool。
  • 已有原生工具节点覆盖的能力——不要用子工作流去包slackTool。

$fromAI():Agent 如何填充工具参数

$fromAI()是 n8n真实存在的表达式辅助函数,写在工具节点的参数表达式里。Agent 应该决定的参数就用它包起来:

sendTo: ={{ $fromAI('recipient', 'Email address of the recipient', 'string') }} subject: ={{ $fromAI('subject', 'Email subject line, concise and informative', 'string') }} body: ={{ $fromAI('body', 'Email body in plain text, professional tone', 'string') }}

形态:$fromAI(paramName, description, type?, defaultValue?)

参数含义要点
paramName模型内部使用的参数名snake_case 或 camelCase,保持一致
description告诉模型要产出什么值属于 prompt 的一部分,要具体:格式、范围、示例
type'string'(默认)、'number'、'boolean'、'json'强制类型校验——类型错误会导致调用失败
defaultValue模型省略该参数时使用的值可选

它只携带 JSON——不能携带二进制(不能有 base64、不能有文件字节),即使通过非 AI 绑定也不行。对于二进制,应该传一个存储键(字符串),让工具自行重新获取(详见 AGENT_TOOL_BINARY.md)。这条二进制边界是双向的硬墙:模型可以通过视觉看到上传的图片(passthroughBinaryImages: true),但工具调用传不了文件字节;工具产出的文件也不能以字节形式回给 Agent。统一的解法都是"先落存储、跨 JSON 边界传键、另一侧再取"。

好描述与无用描述的对比(原文示例):

✅ ={{ $fromAI('imageName', 'Storage key for an existing image to edit, or empty for a new generation. Use the exact key shown in the system prompt; do not reconstruct or guess.', 'string') }} ❌ ={{ $fromAI('imageName', 'image name', 'string') }} // useless to the model

把$fromAI的描述当作JSDoc来写——模型就是靠读它来判断该传什么值的。反过来,AGENT_TOOL_BINARY.md也强调:描述是模型判断取值形状的唯一指引,要与你工作流实际使用的存储后端匹配,只说明那一种形状(不要给一长串可能方案)。


Plumbed 参数:隐藏不该由 Agent 决定的东西

并非每个参数都必须走$fromAI。任何参数都可以从工作流上下文确定性地填充,而且plumbed 值对 Agent 完全不可见——不出现在工具 schema 里,模型产生的任何内容都无法影响它:

reason: ={{ $fromAI('reason', 'Why the user is requesting a refund', 'string') }} // agent-filled customerId: ={{ $('Chat Trigger').first().json.user.id }} // hidden maxRefund: ={{ $('Get user tier').first().json.refundLimit }} // hidden idempotencyKey:={{ $('Chat Trigger').first().json.sessionId }} // hidden

应该 plumb(注入)三类东西:

  • 身份(Identity)——userId、customerId、已认证操作者、租户范围。
  • 权限边界(Authority limits)——退款上限、层级标记、允许的区域。
  • 关联 ID(Correlation IDs)——sessionId、幂等键、trace ID。

"给 Agent 一个按钮,而不是一个方向盘"是这一原则的最强形态:一个敏感工具可以拥有零个$fromAI参数——"Refund order" 工具的orderId来自触发器、amount来自取回的订单记录、actor来自会话,全部 plumbed。Agent 物理上不可能退错订单,它只能决定"是否扣动扳机"。对于既需要确定性参数、又需要人工签批的动作,配合 HUMAN_REVIEW.md 使用——审阅节点插在工具与 Agent 之间的ai_tool链路上,审批消息必须用字面量{{ $tool.parameters.<name> }}展示真实参数,绝不能用$fromAI()让模型复述,否则人类审批的是模型编造的转述而非即将发出的调用。


工具名称与描述即提示词

模型每一轮都会执行这样的选择过程:

  1. 拿到系统提示词、对话历史、以及工具列表。
  2. 对每个工具,读取name + description + 参数 schema(含$fromAI描述)。
  3. 挑选描述与当前任务最匹配的工具。

坏的名称和描述会造成坏的选型——通常是静默的:模型就是不调用你的工具,或者用垃圾参数去调另一个工具。没有任何报错。

命名:动词开头、具体明确

好坏为什么
Search customer databasequery/tool1通用名称什么也说明不了
Generate image with VeoimageGen哪个生成器?
Edit existing imageedit编辑什么?
Send Slack message to channelslack说出动作,而不是表面的对象名
Lookup user by emailgetUser怎么查?

描述:三部分构成

  1. 它做什么(一句话)。
  2. 何时使用它(一到两句话,包含边界 / 示例)。
  3. 参数说明(仅当$fromAI描述里没有覆盖时才写)。

TOOLS.md 给出的完整范例:

Edit existing image: Modifies an image the user already uploaded, based on a prompt. Use when the user uploaded an image and asks for changes (color, style, composition, content). Do NOT use for generating new images from scratch — use Generate Image for that. The imageName parameter must be the storage key of the existing image as listed in your available files; do not pass the original filename or a URL.

注意这段描述包含了正面用法、负面边界("Do NOT use…")和参数形态约束——它做的是原本会撑爆系统提示词的工作,这正是它的价值所在。

接线与验证侧的证据

EXAMPLES.md 的"无状态 Agent 核心"片段中,web 搜索工具这样定义:

{ "descriptionType": "manual", "toolDescription": "Search the web fast to fact-check a claim or find a source. Use for verifying anything from training data.", "query": "={{ $fromAI('query', 'The search query, phrased to match relevant sources', 'string') }}", "type": "@tavily/n8n-nodes-tavily.tavilyTool" }

而子 Agent 工具(Idea database manager)则把关键上下文写进描述,甚至重复 "This tool is stateless"——因为路由器无法依赖共享上下文。所有工具都通过ai_tool连接("Search the web": { "ai_tool": [[{ "node": "AI Agent", "type": "ai_tool", "index": 0 }]] })接入 Agent,多个工具共享同一个ai_toolindex 0,是堆叠而非分叉。


工具描述作为模块化提示词

任何"与如何调用这个工具"相关的具体说明,都应该放进工具描述,而不是系统提示词:

放在系统提示词里(应移出)更好的位置:工具描述
"生成图片时,优先写实摄影而非8k cinematic"Generate Image: "Default to realistic photography aesthetics…"
"如果搜索工具没有结果,要礼貌地总结"Search: "Returns up to 10 results; if empty, report 'no matches' rather than retrying broader"
"视频工具用 9:16"Generate Video: "Defaults to 9:16; passaspectRatio: '16:9'for landscape"

三个理由(TOOLS.md 与 SYSTEM_PROMPT.md 共同支撑):

  • 可复用性(Reusability)——一个描述良好的工具教会每一个新 Agent 如何使用它。
  • Token 效率(Token efficiency)——按工具分片的指引只在模型"考虑该工具"时才加载,而不是每轮都烧掉 token。
  • 可维护性(Maintainability)——只改一处工具描述,而不是改埋在 5000-token 提示词里的段落。

对应的模块化分工是:系统提示词负责人格、全局行为、格式规则、文件处理;工具描述负责"如何调用这个工具、参数含义、何时选它而非其他";$fromAI描述负责"该参数具体填什么值"。SYSTEM_PROMPT.md还提醒:当前日期永远用{{ $now }}在运行时注入,硬编码的日期立刻过期。


粒度:一个带分支的工具,而不是两个近似的工具

模型在近似的工具之间选择时会困惑。如果两个工具内部有约 80% 相同:

  • 用一个带分支参数的工具。Generate Image与Edit Image共享大部分逻辑 → 合并为一个,用imageName参数区分(空 = 生成,非空 = 编辑)。
  • 只有在确实不同、且描述能清晰区分时才拆两个。Send DM与Send Channel Message是明显不同的。

SUBWORKFLOW_AS_TOOL.md 的"一个工具、两种模式"完整示例正是这个思想的实践:子工作流内部用IF: imageName empty?分支,空走 Gemini 生成、非空先 S3 按 key 下载再编辑,最终统一输出{ imageUrl, imageKey }。Agent 通过往imageName里放什么来决定模式。如果模型在这个判别器上反复出错,替代方案是两个 Tool Workflow 节点指向同一个子工作流,用不同的参数接线(一个硬编码空 key、一个让模型填)——一个子工作流、两个描述截然不同的前门。


运维要点

maxIterations:默认值太低,必须调高

Agent 有可配置的工具调用上限(options.maxIterations),默认值很低。多工具 Agent 连续调用很容易触顶,表现为 "max iterations reached" 或空输出。务必调高并准备回退方案,不要指望优雅恢复。SKILL.md 给出的参考:专注的子 Agent 用 15,宽泛的编排者用 50–200。EXAMPLES.md 中核心 Agent 设maxIterations: 50(因为每轮要链式调用多个工具),子 Agent 只设 15。

工具调用成本

每次调用至少多一次模型往返。高频调用的工具应返回精简结果——臃肿的返回会快速烧掉输入 token。

工具失败处理

在希望 Agent 收到错误字符串而非整体中止的场景下,给工具子工作流设置onError: 'continueErrorOutput'——Agent 收到错误后可以重试、换工具或直接上报(详见 n8n-error-handling/SKILL.md)。注意continueErrorOutput是"两步"设置:既要设onError创建第二输出,也要把main[1]错误输出接向真正的处理节点,只做一半会在运行时静默吞掉错误。


关联与延伸阅读

  • 子工作流工具的完整细节(两半结构、输入契约、独立测试)→ SUBWORKFLOW_AS_TOOL.md
  • 系统提示词与工具描述的分工 → SYSTEM_PROMPT.md
  • 二进制如何跨工具边界(预存储 + 传键模式)→ AGENT_TOOL_BINARY.md
  • Custom Code Tool 的 string-in/string-out 契约与常见错误 → n8n-code-tool/SKILL.md
  • 敏感工具的人工审阅包装与$tool.parameters字面量 → HUMAN_REVIEW.md
  • 完整可参考的节点 JSON 片段(无状态核心、Slack 壳、领域子 Agent)→ EXAMPLES.md

最后回到那条贯穿始终的准则:模型看不到你的接线——它看到的只是一个系统提示词和一堆"有名有姓、有描述"的工具。像设计 API 一样设计它们,"Agent 不听话"的问题就会消失大半。

  • AI 技能
  • AI 插件
  • 工作流自动化
  • 流程编排

【免费下载链接】n8n-skills

n8n skillset for Claude Code to build flawless n8n workflows

项目地址:https://gitcode.com/gh_mirrors/n8/n8n-skills
点击查看免费下载
上一篇:Express框架终极指南:从零构建高性能Node.js Web应用的7个核心技巧
下一篇:PhpRedis版本升级终极指南:从5.x到6.x迁移的10个关键注意事项

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 8:58:59

LRE框架:重构AI智能体的时间感知与因果记忆机制

1. 这不是“给AI加个备忘录”&#xff0c;而是重构智能体的时间感知能力很多人第一次看到“AI智能体记忆管理”这个词&#xff0c;下意识会想&#xff1a;不就是让大模型多存点上下文、加个向量数据库当外挂硬盘吗&#xff1f;我试过——在某个模拟项目X里&#xff0c;给一个任…

作者头像 李华
网站建设 2026/10/21 12:41:18

PocketTerm35:口袋级Linux工作站硬件校准与实战部署指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 3:03:16

两节点Gauss-Seidel潮流计算的MATLAB实现与收敛分析

第一次接触潮流计算时&#xff0c;我对着两节点电路图犯过嘀咕&#xff1a;这不过是一个电源、一条线路、一个负荷的简单电路&#xff0c;欧姆定律加基尔霍夫电压定律分分钟就能列方程&#xff0c;为什么还要专门搞一套 Gauss-Seidel 迭代&#xff1f;直到自己动手在 MATLAB 里…

作者头像 李华
网站建设 2026/10/21 3:20:43

FPGA时钟资源实战:MMCM/PLL配置与跨时钟域避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 17:44:51

ReAct循环实战指南:让大模型先想后做,稳定完成任务

前几天一个朋友发来一屏日志&#xff0c;我扫了两眼就看见他代码注释里写着“rea”。评论区里另一个开发者也追了一句“这词儿现在都快成Agent项目的默认起点了”。确实&#xff0c;在AI Agent这个方向上&#xff0c;ReAct&#xff08;Reasoning Acting&#xff0c;推理加行动…

作者头像 李华