mcpField
N
n8n-code-tool

n8n-code-tool

github.com/czlonkowski开发6.5k1.7k 次安装4 天前更新
代码仓库

关于 n8n-code-tool

为使用 n8n LangChain AI Agent 的开发者提供 Custom Code Tool 编写指南,说明其独立于 Code 节点的输入、运行环境和返回约定。

主要功能

  1. 01区分 Code Tool 与 Code 节点
  2. 02支持非结构化和结构化输入
  3. 03规定字符串返回格式
  4. 04说明沙箱可用能力与限制
  5. 05提供错误诊断和工具描述建议

适用场景

  1. 01为 Agent 编写计算或格式转换工具
  2. 02为多参数工具设置输入 schema
  3. 03排查工具调用或返回类型错误

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/czlonkowski/n8n-skills --skill n8n-code-tool

安装后在 Claude Code 中输入/n8n-code-tool确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

ERROR_PATTERNS.md
INPUT_SCHEMA.md
README.md

详细介绍

n8n Custom Code Tool

关于如何在 @n8n/n8n-nodes-langchain.toolCode 中编写代码的专家指南——这是 AI Agent 可以调用的工具,不是常规工作流 Code 节点。


⚠️ 这不是 Code 节点

Custom Code Tool 在编辑器中看起来像 Code 节点——使用相同的 JavaScript 编辑器,布局也类似——但它是来自另一个软件包的完全不同的节点,遵循不同的运行时契约。

Code 节点Custom Code Tool
节点类型n8n-nodes-base.code@n8n/n8n-nodes-langchain.toolCode
软件包n8n-nodes-base@n8n/n8n-nodes-langchain
调用方上一个节点(工作流流转)AI Agent(LangChain)
输入$input.all() — 条目流query — 来自大模型的字符串或对象
返回值[{json: {...}}](条目数组)字符串
$fromAI()不适用不可用(参见“错误”)
HTTP 助手this.helpers.httpRequest(认证助手不可用)工具沙盒中未提供
状态每次运行的执行数据没有 getContext,也没有 $getWorkflowStaticData

如果把它当作 Code 节点使用,就会失败。 本指南其余部分将介绍 Code Tool 的实际契约。


快速入门

最简 JavaScript Code Tool
// `query` is whatever the AI sent (a string by default)
return `You asked: ${query}`;
最简 Python Code Tool
# `_query` is whatever the AI sent (a string by default)
return f"You asked: {_query}"
基本规则
  1. 返回字符串。 数字会自动转换。其他任何类型都会抛出 "The response property should be a string, but it is an object"。
  2. 输入变量是固定的:query(JS)、_query(Python)。不能重命名。
  3. 不要在 Code Tool 沙盒中使用 $fromAI()——这会抛出 "No execution data available"。
  4. 不要使用 [{json: {...}}] 这种返回格式——它适用于 Code 节点。使用后会抛出 "Wrong output type returned"。
  5. 使用描述清晰的工具名称(字母、数字和下划线,v1.1+)。Agent 会按名称调用工具。
  6. 编写准确的描述——大模型会据此决定是否调用工具。

两种输入模式

Code Tool 有两种输入形式,由 specifyInputSchema 控制:

模式 1:非结构化(默认,specifyInputSchema: false)

AI 会将一个字符串作为 query 传入。如果需要多个字段,AI 必须将它们塞进这个字符串中,再由你解析出来。实际上,只要在描述中说明,大模型通常会直接传入 JSON 字符串。

// Parse a JSON string the AI sent
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: /* ... */ });

优点:设置最简单,只需描述一个字段。 缺点:没有架构验证——如果大模型忘记某个字段,工具就会在运行时抛出错误。

适用场景:快速原型、只有一个自然输入的工具(问题、URL 或文本内容)。

模式 2:结构化(specifyInputSchema: true)

工具会变为 LangChain DynamicStructuredTool。大模型会看到带类型的参数架构,并将经过验证的对象作为 query 传入。你可以直接访问各个字段。

// query is now an object matching your 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 });

架构可通过以下任一方式定义:

  • schemaType: "fromJson" + jsonSchemaExample(n8n v≥1.3)——粘贴一个 JSON 示例,n8n 会推断架构
  • schemaType: "manual" + inputSchema——自行编写完整的 JSON Schema

优点:大模型可获取类型提示;无效调用会在代码运行前被拒绝;代码更简洁。 缺点:需要多做一些设置;要求 n8n 版本支持架构。

适用场景:包含多个带类型参数的生产级工具(计算器、API 封装,或任何大模型容易将数值参数转成字符串的工具)。

参见:INPUT_SCHEMA.md,了解完整的架构设置方法。


返回格式

返回值必须是字符串。 大模型会将其作为工具的观察结果读取。

// ✅ String
return "42";

// ✅ Number (auto-converted to string by n8n)
return 42;

// ✅ JSON-encoded structured result (recommended for rich output)
return JSON.stringify({ result: 42, currency: "SEK" });

// ❌ Raw object → "The response property should be a string, but it is an object"
return { result: 42 };

// ❌ Workflow item format → "Wrong output type returned"
return [{ json: { result: 42 } }];

// ❌ Array → "The response property should be a string, but it is an object"
return [1, 2, 3];
最佳实践:将结构化结果序列化为 JSON 字符串

如果工具的输出不只是简单的标量值,请返回 JSON 字符串:

return JSON.stringify({
  monthly_payment_sek: 5405,
  loan_amount: 351920,
  total_cost_of_credit: 63295
});

大模型能够可靠地解析 JSON,并挑选出向用户展示所需的字段。

错误处理:Agent 会读取你的错误信息

错误不会只是让工作流停止,还会返回给大模型,而大模型通常会修正调用并重试。善用这一点:

// Option A: throw — n8n surfaces the message to the agent
if (!isFinite(price)) throw new Error('price must be a number, e.g. 439900');

// Option B: return an error string — agent reads it like any tool result
if (!isFinite(price)) return JSON.stringify({ error: 'price must be a number, e.g. 439900' });

无论哪种情况,错误信息都要写给大模型看:说明哪里出错了,以及有效的调用应该是什么样的。简单地写一句 throw new Error('invalid input') 会浪费重试机会;提供指导性信息通常能修正下一次调用。


工具名称和描述

这些字段不是文档,而是大模型看到的工具契约。请将它们视为提示词工程。

名称
  • 必须匹配 [A-Za-z0-9_]+(v1.1+)。不能包含空格、连字符或表情符号。
  • 使用动词开头且含义明确的名称:calculate_car_loan、get_weather、search_orders。
  • Agent 会通过此名称调用工具。Code Tool(默认名称)毫无用处——Agent 不知道何时该调用它。
描述
  • 说明何时使用该工具,以及要发送什么内容。
  • 如果使用非结构化模式,请包含大模型应发送的 JSON 字符串示例。
  • 如果使用结构化模式,架构本身已经说明一切,只需描述用途。

非结构化示例(JSON 字符串模式):

Deterministiskt 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).

结构化示例(由架构定义):

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.

常见错误及修复方法

错误 1:"There was an error: 'Cannot assign to read only property \"name\" of object: Error: No execution data available'"

原因:你在 Code Tool 沙箱内调用了 $fromAI()。

修复方法:$fromAI() 是供其他启用了工具的节点使用的辅助函数(HTTP Request Tool、SendGrid Tool、toolWorkflow 等),在 toolCode 中不可用。请直接从 query 读取 AI 的输入(或对结构化字段使用 specifyInputSchema)。

错误 2:"Wrong output type returned"

原因:你返回了类似 [{ json: { ... } }] 的工作流风格数组。这是 Code 节点的契约,不是 Code 工具的契约。

修复方法:返回字符串。对于结构化数据,使用 return JSON.stringify(output)。

错误 3:"The response property should be a string, but it is an object"

原因:你返回了普通对象或数组。

修复方法:对结果使用 JSON.stringify(),或将其强制转换为字符串。

错误 4:AI 从不调用工具

原因:工具名称过于笼统(Code Tool、My Tool),或描述没有清楚说明何时使用该工具。

修复方法:将名称改为以动词开头且含义明确的名称(calculate_car_loan),并重写描述,明确说明触发条件(例如:“每当用户询问月度费用时,使用此工具”)。

错误 5:AI 向 query 发送乱码

原因:非结构化工具的描述含糊不清。大模型会猜测格式。

修复方法:可以选择 (a) 在描述中加入具体的 JSON 示例,或 (b) 将 specifyInputSchema: true 打开,让大模型获得类型化架构。

参见:ERROR_PATTERNS.md,了解包含复现步骤的完整目录。


沙箱中不可用的内容

Code Tool 沙箱的功能范围比 Code 节点沙箱窄。不要假定辅助函数也能通用:

辅助函数Code 节点Code Tool
$input.all()、$input.first()、$input.item✅❌
$node["NodeName"]✅❌
$json、$binary✅❌
$fromAI()❌❌(即使它就在 AI Agent 旁边)
this.helpers.httpRequest()✅❌
DateTime(Luxon)✅✅(JS 沙箱中的标准内容)
$jmespath()✅❌
this.getContext(...)✅❌
$getWorkflowStaticData(...)✅❌

影响:Code Tool 用于纯计算。如果需要 HTTP 调用、API 查询或跨调用状态,请使用其他工具节点:

  • 用于外部 API 调用的 HTTP Request Tool
  • 用于访问完整 Code 节点沙箱并执行多步逻辑的 toolWorkflow(Call Sub-workflow Tool)
  • 用于持久化状态的 MCP / 数据库工具

何时使用 Code Tool 与其他替代方案

在以下情况下使用 Code Tool:

  • ✅ 纯确定性计算(数学运算、解析、格式化、验证)
  • ✅ LLM 不应自行处理的轻量级转换(精确数学运算、正则表达式)
  • ✅ 希望将代码内联到工作流中,而不是放在单独的子工作流里

在以下情况下使用 toolWorkflow(调用子工作流工具):

  • ✅ 需要多个参数,并通过 $fromAI() 进行清晰的类型定义
  • ✅ 需要访问 this.helpers、凭据或其他节点
  • ✅ 逻辑需要在多个 Agent 之间复用
  • ✅ 希望使用结构化的类型化输入,而无需编写 JSON Schema

在以下情况下使用 HTTP Request Tool:

  • ✅ 工具本质上只需调用单个 API
  • ✅ 希望在 URL、查询参数或请求正文中,为每个参数绑定 $fromAI()

经验法则:如果你发现自己想使用 $fromAI(),那么你可能应该改用 toolWorkflow,而不是 toolCode。


完整示例

一个可用于生产环境的计算器工具(非结构化,采用 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。


与其他技能的集成

n8n-code-javascript:Code 节点技能。大多数 JavaScript 模式(数组、map/filter、DateTime)都适用,但 I/O 契约不同。不要复制数据访问代码。

n8n-node-configuration:specifyInputSchema 是由 displayOptions 驱动的经典条件字段。使用 get_node({detail: "standard"}) 查看 @n8n/n8n-nodes-langchain.toolCode 中与架构相关的属性。

n8n-workflow-patterns:Code Tool 属于“带工具的 AI Agent”模式。Agent 通常有多个工具;Code Tool 是其中的“本地计算”选项。

n8n-validation-expert:上文列出的三种 Code Tool 错误都有明显特征——如果验证时出现“Wrong output type returned”,就知道要将输出从数组项切换为字符串。


快速参考清单

部署 Code Tool 前:

  • 节点类型为 @n8n/n8n-nodes-langchain.toolCode(而不是 nodes-base.code)
  • 工具名称具有描述性、以动词开头并采用 snake_case(例如 calculate_car_loan)
  • 描述说明何时使用该工具;如果是非结构化工具,还应提供 JSON 示例
  • 输入从 query(JS)或 _query(Python)读取
  • 代码主体中没有 $fromAI()
  • 没有 $input / $json / $helpers——这些不在沙盒中
  • 返回值为字符串(结构化输出请使用 JSON.stringify())
  • 已通过 ai_tool 连接接入 AI Agent
  • 已使用 LLM 将发送的确切类型输入进行测试(字符串中的 JSON,或经过架构验证的对象)

更多资源

官方资料

请记住:Code Tool 是套着 Code 节点界面的 LangChain 工具。契约是:输入字符串,输出字符串。其他一切都由此而来。

评论

支持 Markdown