- AI 技能
- AI 插件
- 工作流自动化
- 流程编排
【免费下载链接】n8n-skills
n8n skillset for Claude Code to build flawless n8n workflows
在 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()让模型复述,否则人类审批的是模型编造的转述而非即将发出的调用。
工具名称与描述即提示词
模型每一轮都会执行这样的选择过程:
- 拿到系统提示词、对话历史、以及工具列表。
- 对每个工具,读取name + description + 参数 schema(含
$fromAI描述)。 - 挑选描述与当前任务最匹配的工具。
坏的名称和描述会造成坏的选型——通常是静默的:模型就是不调用你的工具,或者用垃圾参数去调另一个工具。没有任何报错。
命名:动词开头、具体明确
| 好 | 坏 | 为什么 |
|---|---|---|
Search customer database | query/tool1 | 通用名称什么也说明不了 |
Generate image with Veo | imageGen | 哪个生成器? |
Edit existing image | edit | 编辑什么? |
Send Slack message to channel | slack | 说出动作,而不是表面的对象名 |
Lookup user by email | getUser | 怎么查? |
描述:三部分构成
- 它做什么(一句话)。
- 何时使用它(一到两句话,包含边界 / 示例)。
- 参数说明(仅当
$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
相关推荐
快速上手Ryujinx:如何在PC上免费畅玩Switch游戏的3个技巧终极指南
快速上手Ryujinx:如何在PC上免费畅玩Switch游戏的3个技巧终极指南 想要在PC上体验Switch游戏的魅力吗?Ryujinx Switch模拟器为你
硬件仿真图形学使用 GEPA LangChainAdapter 优化 LangChain 提示词与工具 Agent 实战指南
使用 GEPA LangChainAdapter 优化 LangChain 提示词与工具 Agent 实战指南 GEPA 的 LangChainAdapter
AI Agent提示工程模型优化Docker 部署魔兽世界私服:AzerothCore WotLK 3.3.5 容器化实战
Docker 部署魔兽世界私服:AzerothCore WotLK 3.3.5 容器化实战 AzerothCore 是开源 MMO 服务器框架,跑魔兽世界 3.
游戏开发后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考