n8n-code-tool について
n8n LangChain の AI エージェント向け Custom Code Tool の作成ガイドです。ワークフローの Code ノードとは異なる入力、サンドボックス、戻り値の仕様を説明します。
主な機能
- 01Code Tool と Code ノードの違い
- 02構造化・非構造化入力の説明
- 03文字列の戻り値要件
- 04サンドボックスの機能と制限
- 05エラー診断と命名の指針
活用シーン
- 01エージェント向け計算・整形ツールの作成
- 02複数パラメーター用スキーマの設定
- 03呼び出しや戻り値エラーの調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ czlonkowski/ n8n-skills --skill n8n-code-toolインストール後、Claude Code で/n8n-code-toolを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
ERROR_PATTERNS.mdINPUT_SCHEMA.mdREADME.md詳細
n8n Custom Code Tool
@n8n/n8n-nodes-langchain.toolCode 内でコードを書くための専門的なガイダンスです。AI エージェントが呼び出すツールであり、通常のワークフロー 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 — LLM からの文字列またはオブジェクト |
| 戻り値 | [{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}"
重要なルール
- **文字列を返してください。**数値は自動的に変換されます。それ以外の値を返すと、
"The response property should be a string, but it is an object"がスローされます。 - 入力変数は固定されています:
query(JS)、_query(Python)。名前は変更できません。 - Code Tool のサンドボックス内で
$fromAI()を使用しないでください。"No execution data available"がスローされます。 - 戻り値に
[{json: {...}}]を使用しないでください。これは Code ノード用の形式です。"Wrong output type returned"がスローされます。 - わかりやすいツール名を付けてください(v1.1 以降、英字・数字・アンダースコアを使用)。エージェントはツール名で呼び出します。
- 説明を正確に記述してください。LLM はその説明に基づいてツールを呼び出すかどうかを判断します。
2 種類の入力モード
Code Tool には、specifyInputSchema で切り替える 2 種類の入力形式があります。
モード 1:非構造化(デフォルト、specifyInputSchema: false)
AI は単一の文字列を query として渡します。複数のフィールドが必要な場合、AI はそれらを 1 つの文字列に詰め込み、コード側で解析する必要があります。実際には、説明で指示すれば、LLM は問題なく 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: /* ... */ });
メリット:設定が最も簡単で、説明するフィールドも 1 つだけです。 デメリット:スキーマ検証がありません。LLM がフィールドを忘れると、実行時にツールがエラーになります。
最適な用途:手早く作るプロトタイプや、質問・URL・テキストのように自然な入力が 1 つのツール。
モード 2:構造化(specifyInputSchema: true)
ツールは LangChain の DynamicStructuredTool になります。LLM には型付きの引数スキーマが提示され、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 を自分で記述します
メリット:LLM に型ヒントが提示され、無効な呼び出しはコード実行前に拒否され、コードもすっきりします。 デメリット:設定に多少手間がかかり、スキーマに対応した n8n のバージョンが必要です。
最適な用途:複数の型付きパラメーターがある本番用ツール(計算機、API ラッパー、数値フィールドを文字列化しがちな LLM を使用するあらゆるツール)。
参照:INPUT_SCHEMA.md でスキーマの設定方法を詳しく説明しています。
戻り値の形式
**戻り値は文字列である必要があります。**LLM はこれをツールの観測結果として読み取ります。
// ✅ 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
});
LLM は JSON を確実に解析し、ユーザーへの提示に必要なフィールドを選択できます。
エラー処理:エージェントは失敗を読み取ります
エラーがワークフローを止めるだけとは限りません。エラーは LLM に返され、通常は呼び出しを修正して再試行します。これを活用しましょう。
// 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' });
いずれの場合も、エラーメッセージはLLM 向けに書いてください。何が問題だったのか、有効な呼び出しの形式はどうあるべきかを伝えます。throw new Error('invalid input') のような説明のないエラーでは、再試行を無駄にしてしまいます。役立つメッセージなら、次の呼び出しで問題を解決できることがよくあります。
ツール名と説明
これらのフィールドはドキュメントではありません。LLM が目にするツールの契約です。プロンプトエンジニアリングとして扱ってください。
名前
[A-Za-z0-9_]+に一致する必要があります(v1.1 以降)。スペース、ハイフン、絵文字は使用できません。- 動作がわかる説明的な名前を使います:
calculate_car_loan、get_weather、search_orders。 - エージェントはこの名前でツールを呼び出します。
Code Tool(デフォルト)は役に立ちません。エージェントはいつ呼び出せばよいかわからないためです。
説明
- いつ使うか、何を送るかを説明します。
- 非構造化モードの場合は、LLM が送るべき 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 内では公開されていません。AI の入力は query から直接読み取るか、構造化フィールドには specifyInputSchema を使ってください。
エラー 2: "Wrong output type returned"
原因:[{ json: { ... } }] のようなワークフロー形式の配列を返しています。これは Code ノードの契約であり、Code Toolの契約ではありません。
修正方法:文字列を返します。構造化データの場合は 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 に意味のないデータを送る
原因:説明が曖昧な非構造化ツールを使っています。LLM が形式を推測しています。
修正方法:(a) 説明に具体的な JSON の例を含めるか、(b) specifyInputSchema: true に切り替えて、LLM に型付きスキーマを渡します。
参照:再現例を含む一覧については、ERROR_PATTERNS.md を参照してください。
サンドボックスで利用できないもの
Code Tool のサンドボックスは Code ノードのサンドボックスよりも制限が厳しくなっています。ヘルパーがそのまま使えるとは考えないでください。
| ヘルパー | Code ノード | Code Tool |
|---|---|---|
$input.all()、$input.first()、$input.item | ✅ | ❌ |
$node["NodeName"] | ✅ | ❌ |
$json、$binary | ✅ | ❌ |
$fromAI() | ❌ | ❌(隣に AI エージェントがあっても利用できません) |
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、認証情報、その他のノードにアクセスする必要がある場合 - ✅ ロジックを複数のエージェントで再利用する場合
- ✅ JSON Schema を記述せずに、構造化された型付き入力を使いたい場合
HTTP Request Tool を使う場面:
- ✅ ツールの機能が基本的に単一の API 呼び出しである場合
- ✅ URL/クエリー/本文のパラメーターごとに
$fromAI()のバインディングを設定したい場合
経験則:$fromAI() を使いたいと思ったら、おそらく toolCode ではなく toolWorkflow が適しています。
完全な動作例
本番環境向けの計算ツール(非構造化、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 による条件付きフィールドの典型例です。スキーマ関連のプロパティを確認するには、@n8n/n8n-nodes-langchain.toolCode に対して get_node({detail: "standard"}) を使います。
n8n-workflow-patterns:Code Tool は「ツールを備えた AI Agent」パターンの中で使います。通常、エージェントには複数のツールがあり、Code Tool は「ローカル計算」の選択肢です。
n8n-validation-expert:上記の Code Tool の 3 つのエラーには、それぞれ明確な特徴があります。検証で「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、またはスキーマで検証されたオブジェクト)でテスト済みである
追加リソース
- INPUT_SCHEMA.md — 構造化入力(DynamicStructuredTool)の詳細
- ERROR_PATTERNS.md — エラーの一覧と原因、修正方法
公式情報源
- n8n Custom Code Tool docs
- ToolCode source — サンドボックスの契約
- LangChain tool docs — DynamicTool/DynamicStructuredTool
覚えておいてください:Code Tool は、Code ノードの UI を備えた LangChain ツールです。契約は 文字列を入力し、文字列を出力することです。それ以外のすべては、ここから導かれます。