n8n-mcp 实战指南:掌握 Custom Code Tool(toolCode)的 LangChain 工具契约,写出 AI Agent 真正会调用的代码
发布时间:2026/9/13 9:37:30 锦皓数字建站
的 LangChain 工具契约,写出 AI Agent 真正会调用的代码`)
n8n-mcp 实战指南掌握 Custom Code TooltoolCode的 LangChain 工具契约写出 AI 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本文是 n8n-mcp 技能包中 n8n-code-tool 技能 的深度展开聚焦n8n/n8n-nodes-langchain.toolCode——n8n AI Agent 可调用的自定义代码工具Custom Code Tool。你将理解它与普通 Code 节点的本质区别“字符串进、字符串出”的 LangChain 契约掌握非结构化query与结构化 JSON Schema 两种输入模式学会用工具名与描述做提示词工程并能够仅凭报错信息快速修复Wrong output type returned、No execution data available等高频故障。一、这是 Code Tool不是 Code 节点Custom Code Tool 在编辑器里长得和 Code 节点几乎一样——同一个 JavaScript 编辑器、类似的布局——但它来自完全不同的包遵循完全不同的运行时契约。把它当 Code 节点用必然踩坑。维度Code 节点Custom Code Tool节点类型n8n-nodes-base.coden8n/n8n-nodes-langchain.toolCode所属包n8n-nodes-basen8n/n8n-nodes-langchain调用方上一个节点工作流流程AI AgentLangChain输入$input.all()数据流query——LLM 传来的字符串或对象返回值[{json: {...}}]条目数组一个字符串$fromAI()不适用不可用会抛错HTTP 辅助this.helpers.httpRequest不暴露给工具沙箱状态每次执行的运行数据无getContext、无$getWorkflowStaticData一句话概括Code Tool 是套着 Code 节点外衣的 LangChain 工具它的契约是“字符串进、字符串出”string in, string out。本技能的全部规则都由此派生。从仓库源码看这一契约也被校验逻辑所印证在 src/services/ai-tool-validators.ts 中validateCodeTool对nodes-langchain.toolCode节点强制执行三项检查——toolDescription缺失报MISSING_TOOL_DESCRIPTIONerror 级、jsCode为空报MISSING_CODEerror 级、未配置inputSchema/specifyInputSchema则给出 warning 提示。也就是说工具描述、代码体、输入模式这三件事是本仓库校验器眼中的“硬门槛”。二、快速开始最小可用示例最小 JavaScript Code Tool// query 是 AI 传来的内容默认是字符串 return You asked: ${query};最小 Python Code Tool# _query 是 AI 传来的内容默认是字符串注意下划线前缀 return fYou asked: {_query}六条铁律必须返回字符串。数字会被自动转换其他任何类型都会抛出The response property should be a string, but it is an object。输入变量名固定JS 是queryPython 是_query不能改名。严禁在 Code Tool 沙箱中使用$fromAI()——会抛No execution data available。严禁使用[{json: {...}}]返回格式——那是 Code 节点的契约会抛Wrong output type returned。使用描述性的工具名字母/数字/下划线v1.1。Agent 通过名字调用工具。编写精确的描述——LLM 依据描述决定是否调用此工具。三、两种输入模式非结构化 vs 结构化Code Tool 的输入形态由specifyInputSchema开关控制。本仓库的 INPUT_SCHEMA.md 对此有完整讲解这里提炼核心。模式一非结构化默认specifyInputSchema: falseAI 以单个字符串作为query传入。如果你需要多个字段就得让 AI 把它们塞进一个字符串里由你在代码中解析。实践中只要描述里写清楚LLM 会很乐意传一个 JSON 字符串。// 解析 AI 传来的 JSON 字符串 let params; try { params typeof query string ? JSON.parse(query) : query; } catch (e) { throw new Error(Expected a JSON object. Parser said: e.message); } const price Number(params.price); const months Number(params.months); // ... return JSON.stringify({ monthly_payment: /* ... */ });优点搭建最简单只需描述一个字段。缺点没有 schema 校验——LLM 漏掉字段时工具只能在运行时抛错。适合快速原型以及天然只有一个输入的工具一个问题、一个 URL、一段文本。模式二结构化specifyInputSchema: true工具变成 LangChain 的DynamicStructuredTool。LLM 看到的是一个带类型的参数 schema传入的是经过校验的对象作为query你可以直接访问字段。// query 现在是匹配 schema 的对象 const price query.price; const months query.months; const residual_percent query.residual_percent; const monthly computeAnnuity(price, months, residual_percent); return JSON.stringify({ monthly_payment: monthly });Schema 有两种定义方式schemaType: fromJsonjsonSchemaExamplen8n v≥1.3粘贴一段示例 JSONn8n 自动推断 schema最省事schemaType: manualinputSchema自己手写完整 JSON Schema适合需要字段级description、enum、minimum/maximum约束或可选字段的场景。优点LLM 获得类型提示非法调用在代码运行前就被拒绝代码更干净。缺点需要额外配置且要求 n8n 版本支持 schemafromJson需 v≥1.3节点应设typeVersion: 1.3旧版本可用manual。适合生产环境的多参数工具计算器、API 封装、任何含数字字段且 LLM 容易把它们字符串化的工具。一个关键事实沙箱收到的始终是{ query }从 ToolCode 沙箱的绑定方式来看见 INPUT_SCHEMA.md 中引用的源码片段new JsTaskRunnerSandbox(workflowMode, ctx, undefined, { query })沙箱恒以{ query }作为输入区别只在于query装的是什么模式query的类型使用方式无 schemastring需要结构时JSON.parse(query)有 schemaobject已校验解构const { price, months } query;Python 同理无 schema 时_query是字符串有 schema 时是字典。模式选择决策树你的工具需要多于一个输入字段吗 ├─ 否只是一个 URL、问题、文本块 │ └─ 非结构化——跳过 schema ├─ 是且字段都是简单类型数字、布尔、枚举 │ └─ 结构化 fromJson最省事 ├─ 是且需要约束或丰富的字段描述 │ └─ 结构化 manual └─ 是且字段复杂 / 要在多个 Agent 间复用 └─ 改用 toolWorkflow子工作流工具而不是 toolCode两个 schema 陷阱schema 必须是合法的 JSON 字符串jsonSchemaExample和inputSchema是“装 JSON 的字符串”而非对象粘贴进工作流 JSON 时注意转义。节点保存失败或 LLM 看不到字段时先单独校验 JSON。schema 变更不会追溯修复旧的 Agent 运行如果 Agent 已用非结构化工具启动切到结构化后系统提示词可能仍反映旧契约。改完 schema 设置后强制重新运行或重开 Agent 节点。四、返回值格式必须是字符串返回值必须是字符串。LLM 把返回值当作工具的 observation观察结果来读取。// ✅ 字符串 return 42; // ✅ 数字n8n 自动转为字符串 return 42; // ✅ 推荐JSON 编码的结构化结果 return JSON.stringify({ result: 42, currency: SEK }); // ❌ 裸对象 → The response property should be a string, but it is an object return { result: 42 }; // ❌ 工作流条目格式 → Wrong output type returned return [{ json: { result: 42 } }]; // ❌ 数组 → The response property should be a string, but it is an object return [1, 2, 3];最佳实践结构化结果用 JSON.stringify当工具输出不止一个标量值时返回 JSON 字符串return JSON.stringify({ monthly_payment_sek: 5405, loan_amount: 351920, total_cost_of_credit: 63295 });LLM 解析 JSON 很可靠并能从中挑选需要的字段呈现给用户。错误处理Agent 会读你的失败信息错误不会只是让工作流停止——它们会回到 LLM 那里而 LLM 通常会修正调用并重试。善用这一点// 方案 Athrow——n8n 会把消息抛给 Agent if (!isFinite(price)) throw new Error(price must be a number, e.g. 439900); // 方案 B返回错误字符串——Agent 像读普通结果一样读它 if (!isFinite(price)) return JSON.stringify({ error: price must be a number, e.g. 439900 });无论哪种方式错误信息都要写给 LLM 看说明哪里错了、合法的调用长什么样。一句裸的throw new Error(invalid input)浪费了一次重试机会一条有指导性的消息通常能直接修正下一次调用。注意一个容易被忽略的细节见 ERROR_PATTERNS.md数字会被 n8n 自动转字符串但布尔值不会需要显式String(someBoolean)或JSON.stringify(someBoolean)。五、工具名与描述这是 LLM 看到的工具契约这两个字段不是文档而是LLM 眼中的工具契约请把它们当作提示词工程来对待。名称Name必须匹配[A-Za-z0-9_]v1.1。不能有空格、连字符、emoji。用动词化、描述性的名字calculate_car_loan、get_weather、search_orders。Agent 靠这个名字调用工具。默认的Code Tool毫无用处——Agent 根本不知道何时该调用它。描述Description说明何时使用、发什么内容。非结构化模式下给出 LLM 应发送的 JSON 字符串示例。结构化模式下schema 已说明一切描述只需说明用途。非结构化示例字符串内嵌 JSON 模式Determinisktiskt beräknar månadskostnad för billån. Anropa med EN JSON-sträng: {price:439900,down_payment:87980,interest_rate:6.95,months:36,residual_percent:50} Fält: price (SEK), down_payment (SEK), interest_rate (% per år), months, residual_percent (0-99).结构化示例schema 已定义字段Deterministically computes the monthly car-loan payment given price, down payment, annual interest rate, term, and residual percent. Use whenever the user asks for monthly cost, total credit cost, or loan breakdown.仓库校验器把“描述缺失”视为 error 而非 warningMISSING_TOOL_DESCRIPTION见 ai-tool-validators.ts再次印证描述不是可选项而是工具可被正确调用的前提。六、高频错误与修复按报错信息定位完整的错误目录含复现方法见 ERROR_PATTERNS.md这里列出七个最典型的失败模式。错误 1Cannot assign to read only property name of object: Error: No execution data available原因在 Code Tool 沙箱内调用了$fromAI()。该辅助函数是为其他工具类节点HTTP Request Tool、SendGrid Tool、toolWorkflow等设计的AI 提供的值通过这些节点的工作流执行数据流动而 Code Tool 沙箱没有执行数据输入直接通过query传入。辅助函数抛错后n8n 尝试给错误的name属性打标注又因错误对象被冻结而失败于是出现这条嵌套报错。修复移除$fromAI()直接从query读取或用specifyInputSchema定义结构化字段。// ❌ 错误 const price $fromAI(price, Car price in SEK, number); // ✅ 非结构化——解析 JSON 字符串 const params JSON.parse(query); const price Number(params.price); // ✅ 结构化——specifyInputSchema: true const { price } query;错误 2Wrong output type returned原因返回了工作流条目格式[{json: {...}}]。这是普通 Code节点的契约不是工具契约。修复返回字符串结构化输出用JSON.stringify()。// ❌ 错误 return [{ json: { monthly_payment: 5405 } }]; // ✅ 正确 return JSON.stringify({ monthly_payment: 5405 });错误 3The response property should be a string, but it is an type原因返回了裸对象、数组或什么都没返回。type通常是object、undefined、function等。返回的值报错内容修复{ result: 42 }...is an objectJSON.stringify({ result: 42 })[1, 2, 3]...is an objectJSON.stringify([1, 2, 3])没有return...is an undefined补上returnundefined...is an undefined返回点东西错误 4AI 从不调用工具症状Agent 只凭自身推理回答执行轨迹里没有任何工具调用。常见原因与修复名字太泛Code Tool、My Tool→ 改成动词化、领域化的 snake_casecalculate_car_loan、search_orders、lookup_customer。描述没说明触发条件“Calculates things”太含糊→ 明确列出应触发工具的用户意图“Use this whenever the user asks about monthly cost, loan breakdown, or total interest.”工具没接线节点躺在画布上但没连到 AI Agent 的ai_tool输入。检查工作流 JSON 的connections块是否有tool_name: { ai_tool: [[{ node: AI Agent, type: ai_tool, index: 0 }]] }。名字违反[A-Za-z0-9_]v1.1 上空格、连字符、emoji 会导致工具被静默跳过。错误 5LLM 向query传入垃圾内容症状JSON.parse(query)抛错或字段类型不对。原因非结构化模式 描述含糊LLM 只好自己发明格式或要求 JSON 字符串但 LLM 发来自然语言或数字字段被 LLM 序列化成了字符串。按优先级修复切到结构化模式specifyInputSchema: true并定义字段LLM 拿到类型化 scheman8n 在代码运行前完成校验。在描述中给出具体示例——LLM 善于模仿示例。防御性强制转换const params JSON.parse(query); const price Number(params.price); if (!isFinite(price)) throw new Error(price must be numeric);错误 6$helpers is not defined/$input is not defined原因假设 Code Tool 沙箱暴露了与 Code 节点相同的辅助函数。它没有。不可用的 API$input、$json、$binary、$node[OtherNode]、$helpers.httpRequest()、$jmespath()、this.getContext(...)、$getWorkflowStaticData(...)、$fromAI()。修复纯计算就留在 Code Tool 里用原生 JS需要 HTTP 就迁移到HTTP Request Tool在 URL/body 中可用$fromAI()需要其他节点数据或凭据就迁移到Call Sub-workflow TooltoolWorkflow——它的子工作流拥有完整的 Code 节点沙箱需要跨调用状态就用子工作流读写 Data Table、Redis 等。错误 7Python 专属name query is not defined原因Python 中输入变量是_query下划线前缀不是query。# ❌ 错误 result process(query) # ✅ 正确 result process(_query)调试技巧看执行视图Execution view而不只看测试输出Agent 的工具调用和原始输入/输出都在那里你能看到 LLM 实际发送的query。在工具内打日志把收到的输入回显进返回的 JSON例如return JSON.stringify({ received_query: query, result: /* ... */ });——LLM 能看到回显你也能发现畸形输入。绕过 LLM 单独测工具临时把工具节点改成带硬编码query的独立 Code 节点手动运行测完再换回来。七、沙箱里没有的东西Code Tool 沙箱比 Code 节点沙箱更窄不要假设辅助函数会延续辅助项Code 节点Code Tool$input.all()、$input.first()、$input.item✅❌$node[NodeName]✅❌$json、$binary✅❌$fromAI()❌❌哪怕它就坐在 AI Agent 旁边this.helpers.httpRequest()✅❌DateTimeLuxon✅✅JS 沙箱标准能力$jmespath()✅❌this.getContext(...)✅❌$getWorkflowStaticData(...)✅❌结论Code Tool 只适合纯计算。如果需要 HTTP 调用、API 查询或跨调用状态请换用其他工具节点。八、何时用 Code Tool何时用替代方案你的需求选它纯确定性计算数学、解析、格式化、校验Code Tool需要多参数 干净的$fromAI()类型绑定toolWorkflow子工作流工具本质就是一次 API 调用HTTP Request Tool需要访问this.helpers、凭据或其他节点toolWorkflow跨调用持久状态toolWorkflow Data Table / Redis逻辑要在多个 Agent 间复用toolWorkflow想把代码内联在工作流里不想拆子工作流Code Tool想要结构化类型输入但不想手写 JSON SchematoolWorkflow经验法则一旦你发现自己想用$fromAI()你大概率该用toolWorkflow而不是toolCode。九、完整可运行示例汽车贷款计算器一个生产级计算器工具非结构化、字符串内嵌 JSON 模式可直接作为工作流 JSON 中的节点对象{ parameters: { name: calculate_car_loan, description: Computes monthly car-loan payment using an annuity formula with residual/balloon. Call with a single JSON string. Example: {\price\:439900,\down_payment\:87980,\interest_rate\:6.95,\months\:36,\residual_percent\:50,\setup_fee\:695,\monthly_admin_fee\:59}. Required: price, down_payment, interest_rate, months, residual_percent. Optional: setup_fee, monthly_admin_fee (default 0)., language: javaScript, jsCode: let params;\ntry {\n params typeof query string ? JSON.parse(query) : query;\n} catch (e) {\n throw new Error(Invalid JSON: e.message);\n}\n\nconst price Number(params.price);\nconst down_payment Number(params.down_payment);\nconst interest_rate Number(params.interest_rate);\nconst months Number(params.months);\nconst residual_percent Number(params.residual_percent);\nconst setup_fee Number(params.setup_fee ?? 0) || 0;\nconst monthly_admin_fee Number(params.monthly_admin_fee ?? 0) || 0;\n\nif (!isFinite(price) || price 0) throw new Error(price must be 0);\nif (down_payment 0 || down_payment price) throw new Error(down_payment must be in [0, price));\n\nconst principal price - down_payment;\nconst residual price * (residual_percent / 100);\nconst r interest_rate / 100 / 12;\nconst growth Math.pow(1 r, months);\nconst base r 0\n ? (principal - residual) / months\n : (principal - residual / growth) * r / (1 - 1 / growth);\nconst monthly_payment base monthly_admin_fee;\n\nreturn JSON.stringify({\n monthly_payment_sek: Math.round(monthly_payment),\n loan_amount: Math.round(principal),\n residual_value_sek: Math.round(residual),\n total_cost_of_credit: Math.round(monthly_payment * months residual setup_fee - principal)\n}); }, type: n8n/n8n-nodes-langchain.toolCode, typeVersion: 1.3, name: calculate_car_loan }通过ai_tool连接类型把它接进 AI Agent 即可。这个示例完整演示了本指南的全部要点描述里给 JSON 示例让 LLM 知道发什么、防御性JSON.parse、逐字段Number()强转、面向 LLM 的throw错误信息、以及最终JSON.stringify返回结构化结果。十、与其他技能的关系n8n-code-javascriptCode节点技能。大多数 JS 模式数组、map/filter、DateTime可以迁移但 I/O 契约不同别复制数据访问代码。n8n-node-configurationspecifyInputSchema是典型的 displayOptions 驱动的条件字段可用get_node({detail: standard})查看toolCode的 schema 相关属性。n8n-workflow-patternsCode Tool 位于“AI Agent with tools”模式内Agent 通常挂多个工具Code Tool 是其中的“本地计算”选项。n8n-validation-expert本指南列出的三个签名错误有清晰特征——校验若报Wrong output type returned就知道该把条目数组换成字符串。仓库的 ai-tool-validators.ts 正是这类校验逻辑的实现。十一、部署前自检清单节点类型是n8n/n8n-nodes-langchain.toolCode不是nodes-base.code工具名描述性强、动词化、snake_case如calculate_car_loan描述说明何时使用该工具非结构化时给出 JSON 示例输入从queryJS或_queryPython读取代码体中没有$fromAI()没有$input/$json/$helpers——它们不在沙箱里返回的是字符串结构化输出用JSON.stringify()通过ai_tool连接接入 AI Agent用LLM 实际会发的输入类型测试过字符串内嵌 JSON或 schema 校验过的对象十二、深入阅读INPUT_SCHEMA.md——结构化输入DynamicStructuredTool完整配置fromJson与manual两种风格、版本兼容性、决策树。ERROR_PATTERNS.md——全部错误目录精确报错字符串、根因、修复与调试技巧。README.md——技能总览、激活条件与成功度量。ai-tool-validators.ts——仓库内 Code Tool 校验实现可作为自动化验证时的权威参考。最后再强调一次Code Tool 是套着 Code 节点外衣的 LangChain 工具契约是字符串进、字符串出。其余所有规则都从这一条推导而来——记住它你就不会再被那些看似神秘的报错卡住。【免费下载链接】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),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。