n8n 子工作流即 Agent 工具(Sub-workflow as Tool):用 `.toolWorkflow` 把整个工作流变成 AI 代理的可靠能力
n8n 子工作流即 Agent 工具Sub-workflow as Tool用.toolWorkflow把整个工作流变成 AI 代理的可靠能力【免费下载链接】n8n-mcpA MCP for Claude Desktop / Claude Code / Windsurf / Cursor to build n8n workflows for you项目地址: https://gitcode.com/GitHub_Trending/n8/n8n-mcp把整个 n8n 子工作流封装成 AI Agent 可调用的工具是 n8n 生态中超过一个节点就默认用它的标准形态。本文以本仓库 n8n-agents 技能包的权威参考文档 SUBWORKFLOW_AS_TOOL.md 为核心系统讲解 Tool Workflow 节点n8n/n8n-nodes-langchain.toolWorkflow的完整实现类型化输入的 Execute Workflow Trigger、$fromAI()与确定性预填plumbed参数的分工、Agent 视角下的工具契约、以及返回形状、错误处理、独立测试等实战纪律。读完你将掌握如何把分支、重试、错误处理、子工作流复用、原生节点与自定义逻辑全部装进一个 Agent 工具里并知道什么时候不该这样做。为什么这是 n8n 中的默认方案在原生 LangChain 里一个工具就是一个函数function而在 n8n 里一个工具可以是一整个工作流。这个差异不是炫技而是能力边界的根本不同。作为工具的子工作流可以在输入上分支IF / Switch调用多个 API 并聚合结果拥有自己的重试、降级与错误处理retryOnFail、错误输出、错误工作流再调用其他子工作流子工作流嵌套读写 Data Tables用n8n_test_workflow加固定输入pinned data独立测试在 Agent 之间、以及 Agent 与非 Agent 工作流之间复用。函数式工具想做到其中大部分能力最终也必然长成一个工作流。n8n 直接把工作流这个原语交给你这正是 TOOLS.md 中超过一个节点就用子工作流工具、拿不准就默认用它的判断依据。工具的两半结构一个子工作流工具由两个工作流组成分工明确一边负责接收参数另一边负责把参数绑定到子工作流上并暴露给 Agent。第 1 半子工作流侧 —— 带类型化输入的 Execute Workflow Trigger子工作流必须以n8n-nodes-base.executeWorkflowTrigger开头并用Define Below显式类型字段模式声明输入而不是透传passthrough模式{ parameters: { workflowInputs: { values: [ { name: imagePrompt, type: string }, { name: imageName, type: string }, { name: sessionId, type: string } ] } }, type: n8n-nodes-base.executeWorkflowTrigger, typeVersion: 1.1, name: When Executed by Another Workflow }每个声明的输入都成为调用方可填的参数。触发器必须处于Define Below模式带类型的字段而非透传——透传没有 schemaAgent 就没有任何字段可以通过$fromAI去填充。唯一的两个例外子工作流需要接收二进制数据图片/PDF 等二进制不能直接作为 Agent 工具参数传递详见 n8n-binary-and-data/SKILL.md 的二进制边界说明正确做法是预置到存储把存储键作为类型化字符串字段传入工具完全没有输入透传是唯一选择此时工具的唯一决策就是是否调用。类型强制发生在Agent 侧的$fromAI的type参数上而不是触发器处。允许的类型为string、number、boolean、json两侧必须匹配。第 2 半Tool Workflow 侧 —— 指向子工作流并绑定参数在 Agent 所在的工作流中用n8n/n8n-nodes-langchain.toolWorkflow节点UI 中称 Call n8n Workflow Tool指向该子工作流并完成参数绑定{ parameters: { description: Use to create a new image from a prompt OR edit an existing image. Pass imageName as the storage key (e.g. \abc123.png\) to edit; leave empty to generate from scratch. Returns { imageUrl, imageKey }., workflowId: { __rl: true, value: sub-workflow-id, mode: list }, 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 }} }, schema: [ { id: imagePrompt, displayName: imagePrompt, type: string, display: true }, { id: imageName, displayName: imageName, type: string, display: true }, { id: sessionId, displayName: sessionId, type: string, display: true } ] } }, type: n8n/n8n-nodes-langchain.toolWorkflow, typeVersion: 2.2, name: Generate or edit image }然后通过ai_tool连接类型把它接入 AgentGenerate or edit image: { ai_tool: [[{ node: AI Agent, type: ai_tool, index: 0 }]] }接线提示AI 子节点的连接定义在子节点自身上、以ai_*类型为键ai_languageModel、ai_memory、ai_tool、ai_outputParser多个工具都接入同一个ai_tool的 index 0 即可堆叠。完整的 Agent 节点对象示例见 EXAMPLES.mdstateless agent core、Slack router shell、domain sub-agent 三个片段。每个输入各司其职$fromAI与确定性预填Tool Workflow 的参数映射是按输入逐一进行的只有两种填法Agent 决定{{ $fromAI(paramName, description, string) }}—— 由模型根据描述自主生成值工作流预填plumbed{{ $(SourceNode).first().json.field }}—— 由你的工作流从上游节点确定性取值Agent 看不到、也改不了。其中sessionId这一行是关键中的关键它不是Agent 的决策项必须从触发器预填让记忆与会话键控的工作保持一致。永远不要把sessionId放进$fromAI—— 模型会现场编造一个 UUID导致跨会话串线这正是 SKILL.md 反模式清单里交叉会话问题的根源。$fromAI的完整形态是$fromAI(paramName, description, type?, defaultValue?)其中 description 是提示词的一部分要写得像 JSDoc 一样具体格式、范围、示例详见 TOOLS.md 的 $fromAI() 一节。同一份文档也给出了给 Agent 一个按钮而不是方向盘Give the agent a button, not a steering wheel的强版本对退款这类敏感工具让orderId、amount、actor全部预填Agent 只剩是否触发这一个决策。Agent 能看到什么以及看不到什么Agent 只能看到工具的name即 Tool Workflow 节点的名称和description节点上的一个参数——两者都遵循 TOOLS.md 的规则动词开头、具体、API 文档风格、被当作提示词处理。它看不到子工作流内部实现、子工作流自身的名称、以及sessionId这类被预填的值。工具 schema 中只出现$fromAI参数。这意味着你可以对子工作流做重度重构而不改变 Agent 看到的任何东西——封装边界就是信息边界。实战示例一个工具两种模式目标让 Agent 既能生成图片也能编辑图片。两者共享大部分逻辑只差是否先下载已有图片一步因此合并成一个工具而不是做两个近乎相同的工具模型在近似工具之间的选择是不稳定的这正是 TOOLS.md 粒度一节反对的反模式。[Execute Workflow Trigger: { imagePrompt, imageName, sessionId }] ↓ [Crypto: hash for new filename] ↓ [IF: imageName empty?] ├── empty (generate) → [Gemini: generate] ──┐ └── not empty (edit): │ [S3: Download by imageName] │ ↓ │ [Gemini: edit with downloaded binary] ───────┤ ↓ [S3: Upload result] ↓ [Set: { imageUrl, imageKey }]Agent 通过往imageName里填什么来选择模式空 生成有值 编辑。这个用分支参数区分模式的思路在 AGENT_TOOL_BINARY.md 中还有更细的讨论如果模型在该判别条件上反复出错退路是保留同一个子工作流挂两个 Tool Workflow 前端门一个把imageName硬编码为空、一个交给模型填配上截然不同的 description。子工作流内部的设计纪律返回稳定形状这是契约调用方拿到的是最后一个节点的输出。选定一个形状并在所有模式下保持一致{ imageUrl: https://..., imageKey: abc123.png }不要有时返回{ url, key }、有时返回{ result: { url, key } }。输出形状是每个调用方依赖的契约——Agent 把返回内容当作提示词的一部分来读确定性调用方则把下游节点接到具体路径上契约漂移会静默破坏所有调用方。对于预期内失败如搜索无结果返回一个可分支的形状{ ok: false, error: no_results, message: No matches found for query }该抛出时就抛出Stop and Error 节点对于意外但已处理的错误认证失败、上游宕机、不可恢复的输入使用Stop and Error节点并附上详细消息。它会作为抛出的错误传播Agent 看到工具错误后可以重试/换工具/上报确定性调用方则通过onError: continueErrorOutput捕获。当结果真是错误、而不是一个正常分支时选它而不是{ ok: false }。完整的错误故事4xx/5xx 映射、重试、错误工作流见 n8n-error-handling/SKILL.md。给易失败节点接上onError: continueErrorOutput子工作流内部的易失败节点HTTP、S3、数据库应设置onError: continueErrorOutput并路由到干净的错误响应这样无论 Agent 还是确定性调用方收到的都是结构化错误而不是一次静默中断。注意 n8n-error-handling/SKILL.md 强调的两步陷阱只设onError不接线、或只接线不设onError都会让错误被静默吞掉。把输入契约当 API 写进 descriptionExecute Workflow Trigger 声明的输入就是这个工具的 API必须在子工作流的description中写清楚Generates or edits an image. Inputs: imagePrompt (string, required): detailed image description. imageName (string, optional): storage key of existing image to edit. Empty new generation. sessionId (string, required): chat session ID, used for storage keying. Returns: { imageUrl, imageKey }让工具子工作流可被发现用统一前缀命名Subworkflow:或领域前缀。Tool Workflow 节点按 ID 引用它稳定但人在 UI 里是按名称浏览的——名称是社区 MCP 场景下n8n_list_workflows/n8n_get_workflow唯一的发现面详见 n8n-subworkflows/SKILL.md 的先搜索再构建原则。脱离 Agent 独立测试子工作流工具子工作流可以完全不经过 Agent 单独测试在 Execute Workflow Trigger 上固定pin代表性输入运行n8n_test_workflow用它固定的数据执行子工作流核对输出形状是否与 Agent 将收到的完全一致。这与 n8n-subworkflows/SKILL.md 的可测试性论点一脉相承把逻辑抽成子工作流后你可以在不跑整条 Agent 链路的情况下验证它。最终使用validate_workflow校验再用n8n_get_workflow拉回 JSON 确认ai_tool接线无误。什么时候不要用子工作流作为工具单节点包装——调用这个端点然后返回直接用 HTTP Request Tool.toolHttpRequest更短只属于当前 Agent 的一次性纯代码逻辑——几行别处不存在的 JS/Python用 Custom Code Tool.toolCode即可决策规则是可复用的业务逻辑 → 子工作流一次性、Agent 专属的变换 → Code Tool。注意 Code Tool 的运行时契约是字符串进、字符串出、无$fromAI、无$helpers详见 n8n-code-tool/SKILL.md已有原生工具节点覆盖的能力——不要把slackTool再包一层子工作流。除此之外子工作流作为工具就是默认答案。这也是 TOOLS.md 四类工具决策树原生工具节点 / 子工作流工具 / HTTP Request Tool / MCP Client Tool另加 Custom Code Tool的核心分界。相关参考四类工具总览与$fromAI()详解 → TOOLS.md子工作流原语无状态设计、命名、I/O 契约、mode与waitForSubWorkflow→ n8n-subworkflows/SKILL.md 与 SUBWORKFLOW_PATTERNS.md二进制传入工具的正确姿势存储键替代字节→ n8n-binary-and-data/SKILL.md、AGENT_TOOL_BINARY.mdCustom Code Tool 例外场景 → n8n-code-tool/SKILL.md工具子工作流与 Agent 核心调用的错误输出 → n8n-error-handling/SKILL.md完整可适配的节点对象示例 → EXAMPLES.md一句话总结子工作流工具的 API 就是触发器的类型化输入加上末节点的输出形状把sessionId等关键值预填、把返回形状当作冻结的契约、把预期失败做成可分支的{ ok: false }而把真正的错误交给 Stop and Error——这套纪律让工具既对 Agent 友好也能被确定性调用方稳定消费。【免费下载链接】n8n-mcpA MCP for Claude Desktop / Claude Code / Windsurf / Cursor to build n8n workflows for you项目地址: https://gitcode.com/GitHub_Trending/n8/n8n-mcp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考