n8n-subworkflows について
n8n-subworkflowsは、再利用可能なn8nサブワークフローを設計するスキルです。エージェントが既存の実装を探し、明確な入出力契約を定め、再利用・テスト・分離のためにロジックを抽出するタイミングを判断するのに役立ちます。
主な機能
- 01構築前の検索
- 02型付き入力契約
- 03ステートレス/ステートフルのパターン
- 04検索用タグ付け
- 05抽出するタイミングの指針
活用シーン
- 01複数のn8nワークフローでのロジック再利用
- 02単独でテスト可能な処理ステップの作成
- 03データベースやAPI操作のカプセル化
- 04タグによる既存サブワークフローの検索
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ n8n-io/ skills --skill n8n-subworkflowsインストール後、Claude Code で/n8n-subworkflowsを入力して読み込まれたか確認します。
同梱ファイルreferences/NAMING_AND_DISCOVERY.mdreferences/SUBWORKFLOW_PATTERNS.md
詳細
n8n サブワークフロー
サブワークフローは再利用可能な関数です。Execute Workflow Trigger で入力パラメーターを宣言し、本文で処理を行い、最後のノードで出力を返します。呼び出し元は、ほかのノードと同じようにこれを呼び出します。
この考え方により、関数としてのメリットであるカプセル化、再利用性、テスト容易性、置き換え可能性が得られます。n8n での主要な再利用手段ですが、残念ながら十分に活用されていません。
サブワークフローがないと、同じロジックが複数のワークフローに重複して記述されます。バグ修正を複数箇所で行うことになり、どこかで修正が漏れ、「同一」のコピーに差異が生じていきます。
必須事項
- 作成する前に検索してください。 汎用的な問題に対応するロジックを記述する前に、すでにサブワークフローが存在するか確認してください。タグ(
search_workflows({ tags: ['subworkflow'] })、ドメインタグ)やキーワード(query: '<keyword>')で絞り込めます。タグは検索の仕組みです(n8n 2.27.0+)。 Execute Workflow Triggerでは、パススルーではなく、型付きフィールドを使った「Define Below」を使用してください。 エージェントツール(fromAi)や構造化された呼び出し元が値を渡せるのは、「Define Below」モードだけです。例外は2つあります。(a)サブワークフローがバイナリを受け取る必要がある場合(その場合、エージェントツールとして直接接続できません)、または(b)サブワークフローに入力が一切ない場合(「Define Below」には少なくとも1つのフィールドが必要です)。詳しくは、以下の「サブワークフローの入出力」を参照してください。
推奨される基本方針
- 再利用可能なものはすべてサブワークフローにします。 ある論理的なまとまりが別の場所でも使われそうなら、切り出してください。例外は、単純なラッパー(HTTP 呼び出し1回で、ロジックがないもの)と、現在の呼び出し元に強く結び付いたまとまりです。
- 純粋なロジックでは、ステートレスを既定にします(入力 → 出力、外部状態なし)。状態を扱うロジックには、明確な契約のもとで操作を抽象化する、意図的なステートフルサブワークフローを構築します(ORM/リポジトリパターン)。避けるべきなのは「意図しない」状態です。たとえば、気付かないうちにログテーブルへ書き込む「検証」サブワークフローです。
- 検索しやすいようにタグを付けます:各サブワークフローに
subworkflow、ドメインタグ(customer)、および/またはtoolを付けます。search_workflows({ tags })が絞り込みに使用するのはタグです。名前は簡潔で説明的なものにします(Parse RFC2822 date)。references/NAMING_AND_DISCOVERY.mdを参照してください。 - 説明文にはキーワードを含めます。 入出力の形式と代表的な用語を記載し、さまざまな検索語句で見つかるようにします。
- 入力契約が実際に異なる場合は分割します(バイナリと JSON、同期と非同期、異なる認証方式)。パススルーと内部の条件分岐を使って、異なる契約を1つのトリガーに押し込まないでください。
references/SUBWORKFLOW_PATTERNS.mdの「入力形式による分割」を参照してください。
判断フロー:これはサブワークフローにすべきか?
About to write a chunk of logic?
├── Could this plausibly be needed in another workflow?
│ ├── Yes → extract to sub-workflow
│ └── No → keep inline
│
├── Is this chunk >5 nodes and conceptually one thing?
│ └── Extract if you want testability, isolation, or reuse; if it's only for a cleaner canvas, group it inline instead (see below).
│
├── Is this chunk dealing with a generic concern (auth, retry, parsing, formatting)?
│ └── Almost certainly extract. These are the canonical reusable sub-workflows.
│
└── Is this chunk doing one HTTP call with no logic around it?
└── Don't extract. Extra workflow boundary for nothing.
唯一の目的がキャンバスをすっきりさせること(再利用、分離、テスト容易性、エージェントツールとしての利用ではない)なら、読みやすさだけを目的とした区分にはキャンバスノードグループを既定のツールとして使用します。より高速で(呼び出しごとのサブ実行が不要)、よりシンプル(入出力の契約が不要)であり、ロジックをインラインに保てます。まとまりが有効なグループを形成する場合(接続されており、入口と出口がそれぞれ1つ)は、その部分をグループ化します。そうでなければ、付箋を使用してください。再利用、分離、独立したテスト、またはエージェントツールが本当に必要な場合にのみ、サブワークフローとして切り出します。詳しくは n8n-workflow-lifecycle の「読みやすさ」を参照してください。
ステートレスとステートフルのサブワークフロー
どちらも主要な選択肢です。どちらを選ぶかは、意図とカプセル化によって決まります。
ステートレス
入力を受け取り、出力を返します。入出力以外の I/O はありません。純粋なロジックでの既定の選択肢です。
例:
Parse RFC2822 date(タグsubworkflow)。入力:日付文字列。出力:ISO 日付またはエラー。Compute MRR from subscription(タグsubworkflow)。入力:サブスクリプションオブジェクト。出力:MRR の数値。Format invoice as HTML(タグsubworkflow)。入力:請求書データ。出力:HTML 文字列。
ロジックを再び使う場合は、副作用が発生する心配なく呼び出せます。
ステートフル(意図的)
明確な入出力の契約のもとで、外部の状態を読み取る、または書き込みます。リポジトリパターンに似ています。サブワークフローが状態操作を抽象化するため、呼び出し側は実装ではなくドメインの用語で考えられます。
例:
Get customer by id(タグcustomer)。入力:ID。出力:顧客オブジェクト、または{ ok: false, error: 'not_found' }。DB を読み取ります。Write customer billing record(タグcustomer、billing)。入力:レコード。出力:{ ok: true, id }。DB に書き込みます。Append audit event(タグaudit)。入力:イベント。出力:{ ok: true, eventId }。ログストアに書き込みます。Send to on-call(タグnotification)。入力:チャンネル、メッセージ。出力:{ ok: true, messageId }。Slack/SMTP を呼び出します。
これらをサブワークフローとして構築する利点は次のとおりです。
- 呼び出し側はストレージ(
SELECT * FROM customers ...)ではなく、ドメインの用語(get customer by id)で考えられます。 - 呼び出し側に手を加えずに、その背後にあるストア/API(Postgres → Supabase、ネイティブノード → HTTP)を差し替えられます。
- 冪等性、再試行、検証をサブワークフローの責任として、1 か所に集約できます。
避けるべきなのは、意図せず発生する状態変更です。純粋な処理として名前や説明が付けられたサブワークフローが、ひそかにログテーブルへ書き込むようなケースです。安全に再試行したり組み合わせたりできると合理的に想定していた呼び出し側を、予期せず巻き込みます。副作用を契約の一部にする(名前を変え、説明し、結果を返す)か、外部に移してください。
抽出するタイミング
主な兆候は 2 つあります。
1. 概念上の一貫性
ノードのまとまりが 1 つの論理的な処理を担っている場合、再利用されていなくても、次の目的で抽出する価値があります。
- テスト容易性。 データを固定して、サブワークフロー単体で実行できます。
- 置き換えやすさ。 実装を差し替えても、呼び出し側への影響が波及しません。
読みやすさだけを理由に抽出する必要はありません。ノードグループを 1 つのラベル付きボックスにまとめれば、より手軽に 5 つのノードを 1 つにできます(サブ実行も入出力の契約もありません)。テスト容易性、置き換えやすさ、または再利用も必要な場合に抽出してください。
1.5 ファイア・アンド・フォーゲットの監査ログパターン
監査ログは、ファイア・アンド・フォーゲット型のステートフルパターンを具体的に示すために、ここで取り上げています。ユーザーから依頼されていない限り、ワークフローに監査ログを追加しないでください。 このパターン自体(サブワークフローを非同期で起動し、完了を待たないこと)は、メトリクスや通知など、あらゆる副次的な記録に応用できます。
意図的にステートフルな監査ログのサブワークフローを Execute Workflow の waitForSubWorkflow: false を指定して呼び出すと、呼び出し側は書き込みの完了を待たずに済みます。
Caller ──→ [Execute Workflow: DB audit log]
{ title: 'Email Confirmation Received',
description: <serialized data> }
waitForSubWorkflow: false
↓ (caller continues immediately)
──→ [Continue with next step]
サブワークフローはタイトルと説明を受け取り、ログテーブル(または Slack、あるいはその両方)に書き込んで終了します。呼び出し側は待ちません。監査ログは副次的な記録であり、クリティカルパスではありません。
ユーザーから依頼された場合は、意味のある状態遷移(「確認メール受信」「ユーザー確認済み」「処理開始」「適格性の判定」)のたびに起動し、ログからタイムラインを再構成できるようにします。
役立つ理由は次のとおりです。
- 追加の負担なく可観測性を得られます。 問題が起きたときに、実行ごとのタイムラインを確認できます。
- 結合がありません。 実装(DB、Slack、またはその両方)を変更しても、呼び出し側に手を加える必要がありません。
- デフォルトで非同期です。
waitForSubWorkflow: falseにより、監査ログの記録がメインワークフローを遅らせません。
監査ログのワークフローは、適切なステートフルサブワークフローの例です。副作用こそが目的です。
1.7 ミドルウェアパターン
Webhook ワークフローが API の形式に合っているなら、そのように扱います。サブワークフローをミドルウェアにします。メインハンドラーの前に実行される、小さなステートレス関数です。処理をそのまま通すか、4xx で早期終了します。
Webhook
→ [Verify JWT] # decode + validate; 401 on failure
→ [Rate limit] # check + bump counter; 429 on failure
→ IF (all middleware ok)
→ Main handler logic
→ Respond 200
→ ELSE → Respond with the 4xx the middleware returned
典型的な例は、n8n 内で独自の JWT 認証を実装することです。Verify JWT(タグ subworkflow)は、生の Authorization ヘッダーを受け取り、デコードして署名と有効期限を検証し、{ ok: true, user_id } または { ok: false, status: 401, message } を返します。呼び出し元では ok に基づいて IF で分岐し、失敗時は早期にレスポンスを返し、成功時は処理を続けます。
インラインではなくサブワークフローにする理由は、認証が必要なすべての webhook から同じものを呼び出せるためです。ライブラリの差し替え、署名キーのローテーション、リフレッシュトークンのロジックの追加を、1 か所で行えます。再利用の対象が明確で、契約はシンプルであり、すべての API エンドポイントで一貫した形式の失敗レスポンスを返せます。
4xx/5xx のレスポンス形式については n8n-error-handling と、基盤となるシークレットの取り扱いについては n8n-credentials-and-security と組み合わせてください。
2. 繰り返しのパターン
以前に作ったことのあるものを、これから作ろうとしています。いったん止めて、検索してください。
search_workflows({ query: 'date' })
search_workflows({ tags: ['customer'] })
search_workflows({ tags: ['subworkflow'] })
一致するものがあれば、それを使ってください。なければ、サブワークフローとして作り、次の検索で見つかるようにタグを付けてください。この運用を支えるのが、タグの規約(subworkflow、ドメインタグ、tool)です。
大部分の処理がサブワークフロー内にあるなら、長い直線的なワークフローでも問題ありません
ほとんどがサブワークフローの呼び出しと判断処理を直線的に組み合わせたものなら、20 個以上のノードがあるワークフローでも読みやすくできます。その構成は次のとおりです(監査ログノードは、「実際のステップ間での副次的な観察」の例として分かりやすいため示しています。監査ログをユーザーが求めた場合にのみ含めてください)。
Webhook
→ Audit log (sub-workflow)
→ Validate
→ Audit log (sub-workflow)
→ IF auth ok
→ Look up user (or sub-workflow)
→ Audit log (sub-workflow)
→ Process step 1 (sub-workflow)
→ Audit log (sub-workflow)
→ Process step 2 (sub-workflow)
→ Audit log (sub-workflow)
→ Decide eligibility (sub-workflow)
→ Audit log (sub-workflow)
→ Send notification (sub-workflow)
→ Respond
「論理ステップ」はそれぞれサブワークフローの呼び出しです。呼び出し元は長くても直線的な流れとなり、上から下へ簡単に追えます。ロジックはサブワークフロー内にあります。
これは、インライン変換が 20 個あるワークフローと同じではありません。そのようなワークフローは読みづらくなります。上記のパターンが適切なのは、次の理由によります。
- 各ノードには 1 つの目的(特定のサブワークフローの呼び出し)があります。
n8n-workflow-lifecycleの「読みやすさ」に従い、付箋とノードグループでセクションを示します。- セクションを確認するには、そのセクションから呼び出されるサブワークフローを開きます。これがカプセル化です。
- 実装を読まなくても、トップレベルのオーケストレーションロジックを確認できます。
ワークフローに 15 個以上のノードがあり、Execute Workflow の呼び出しと分岐が大部分を占めていない場合は、再利用やテストの必要性に応じて、さらに処理を切り出し、残りはインラインのまま(ノードグループで)まとめてください。
切り出さない場合
- ロジックのない HTTP 呼び出しが 1 つだけの場合。
Execute Workflow → HTTP Request → returnだけのサブワークフローは、意味もなく境界を増やします。インラインにしてください。 - 呼び出し元固有の形式に密接に結び付いている場合。 呼び出し元だけが生成する深くネストされた入力をチャンクが受け取るなら、切り出しても依存関係の場所が変わるだけです。まずデータ形式を修正してください。
- パフォーマンスが重要なホットパスの場合。 サブワークフローを呼び出すたびに、わずかですが実際にレイテンシーが増加します。高スループットのワークフローでは、境界を追加する前にプロファイリングしてください。
検索してから構築する手順
ユーザーが複数のステップを含むものや、汎用的なものに聞こえる内容を説明したときは、次の手順に従ってください。
1. search_workflows with relevant tags and/or query (e.g. `tags: ['subworkflow']`, a domain tag, the operation keyword)
2. If candidates appear, fetch get_workflow_details on the top 1-3
3. Confirm fit by reading the inputs/outputs and (briefly) the body
4. If a fit exists → use it. Tell the user "I found `<name>`. Using that."
5. If no fit exists → build new and tag it (`subworkflow`, domain, `tool`) so the next search finds it
「ユーザーに伝える」ステップは重要です。ライブラリにすでに何があるかを知ることができます。
見つかるはずのワークフローが検索結果に表示されない場合、最も一般的な原因は、ワークフローごとの MCP アクセスが有効になっていないことです。n8n-workflow-lifecycle の references/MCP_ACCESS_PER_WORKFLOW.md を参照してください。
サブワークフローの入出力
サブワークフローは Execute Workflow Trigger ノードによってトリガーされます。このトリガーで入力スキーマを定義します。呼び出し元は Execute Workflow を介してデータを渡し、サブワークフローは最後のノードの出力を返します。
常に明示的なフィールドを指定して「Define Below」を使用する
Execute Workflow Trigger には2つの入力モードがあります。デフォルトでは「Define Below」(型付きフィールド)を使用してください。 これが、エージェントツール(fromAi() 経由)や構造化された呼び出し元から値を渡せる唯一のモードです。フィールドを宣言しないと、エージェントには値を入力するためのスキーマがなく、サブワークフローを toolWorkflow として適切に接続できません。
形式:
const subTrigger = trigger({
type: 'n8n-nodes-base.executeWorkflowTrigger',
config: {
parameters: {
workflowInputs: {
values: [
{ name: 'list_of_ids', type: 'array' },
{ name: 'include_transcript', type: 'boolean' },
{ name: 'session_id', type: 'string' },
],
},
},
},
})
宣言した各入力は、呼び出し元が値を入力できる型付きパラメーターになります。ワークフロー内では、$json.list_of_ids など、または下流のどこからでも $('When Executed by Another Workflow').first().json.<field> を使ってアクセスできます。
型(string、number、boolean、array、object)は慎重に選んでください。モデルはエージェントツールのパラメーターに値を入力する際、これらを必須の型として使用し、呼び出し元を接続する人もこれらを参照します。
例外1:バイナリの受け渡しモード
サブワークフローでバイナリ(画像、ファイル、PDF)を受け取る必要がある場合、型付きフィールドはJSONのみを扱うため、「Define Below」は機能しません。受け渡しモードに切り替えてください。
const subTrigger = trigger({
type: 'n8n-nodes-base.executeWorkflowTrigger',
config: {
parameters: {
inputSource: 'passthrough',
},
},
})
受け渡しモードでは、binary スロットを含め、呼び出し元のアイテムがそのままサブワークフローに渡されます。デメリットは、型付き入力スキーマがないため、エージェントツールから fromAi() を介してパラメーターを渡せないことです。バイナリの受け渡しが必要で、エージェントではなく他のワークフローから呼び出されるサブワークフローでは、このモードを使用してください。
バイナリが必要で、かつエージェントから呼び出されるサブワークフローについては、n8n-binary-and-data の references/AGENT_TOOL_BINARY.md を参照してください(エージェントツールからバイナリを直接渡すことはできません)。
例外2:入力のないサブワークフローで受け渡しモードを使う
「Define Below」では、少なくとも1つのフィールドを宣言する必要があります。入力をまったく受け取らないサブワークフロー(「アクティブな認証情報の一覧」ツール、「現在の件数」の検索、引数を取らない処理など)には、空のスキーマを設定する場所がないため、受け渡しモードしか使えません。
入力のないケースで受け渡しモードを使用する場合:
- 本文の先頭に、フィールドを指定せず「Keep Only Set」モードにした
Set(Edit Fields)ノードを配置してください。 これにより、呼び出し元のJSONがクリアされ、下流のノードが呼び出し元から渡されたデータ構造のフィールドを誤って読み取るのを防げます。これを行わないと、本文は呼び出し元が渡したデータをそのまま暗黙に取り込みます。 - トリガーに付箋を追加し、入力が不要であることを記載してください。 後から読む人(およびこれをツールとして再接続するエージェント)が、バイナリのためではなく、スキーマが意図的に空であるために受け渡しモードを使っていることを理解できるようにします。
入力のないケースでも、エージェントツールとの接続は機能します。toolWorkflow は、入力マッピングにフィールドがないサブワークフローを受け入れます。エージェントが判断するのは、呼び出すかどうかだけです。n8n-agents の references/TOOLS.md にあるパターン(「fromAi パラメーターが0個」)がそのまま当てはまります。
その他の規約
-
ワークフローの
descriptionに入出力を記載します。 フィールド名、型、目的を記載してください。呼び出し元(人間やエージェント)が契約内容を確認する際に読むのが、この説明です。 -
一貫した形式を返します。 想定される失敗(例:解析エラー)では、例外をスローするのではなく、
{ success: false, error: '...' }を返します。呼び出し元は、エラー出力をラップせずに分岐できます。 -
呼び出し元が存在するようになったら、入力スキーマを契約として扱います。 オプションフィールドの追加は安全です。フィールドの名前変更や削除も可能ですが、慎重に行ってください。すべての呼び出し元を列挙し(サブワークフロー名で
search_workflowsを実行し、手動でも確認します)、同じ変更内で移行し、公開前にvalidate_workflowとget_workflow_detailsで検証します。n8nは認識できない入力フィールドがあってもエラーを出さないため、ここでの気づきにくい破損は検出が困難です。サブワークフローにはundefinedが渡され、呼び出し元はそのことに気づきません。 -
最後にSet / Edit Fieldsノードを使って返却値を整形します。 これは任意ですが、最後の計算ノードに不要なフィールドが含まれる場合は必要になることがあり、厳密に必須ではない場合でもサブワークフローでは適切な慣行です。返却の境界で契約を明確にできるため、読者は1つのノードを見るだけでAPIを把握できます。これは
n8n-expressionsのSetノードのアンチパターンに対する正当な例外です。サブワークフローの最後のノードを暗黙的に使用するのはすべての呼び出し元なので、Setノードを明示的なAPI境界として設ける価値があります。ノード名はReturnまたはReturn <thing>にします。 -
ストレージ上の形式ではなく、自然な形式を返します。 Data Table、S3内のファイル、その他のストレージ層を扱うサブワークフローは、その表現形式を呼び出し元に見せないようにします。基盤となるストレージでJSON文字列化されたテキストなどの内部形式が使われていても、配列は配列として、オブジェクトはオブジェクトとして、日付はISO文字列として返します。返却契約はインターフェースです。ストレージのレイアウトは実装の詳細です。
よくある間違い:サブワークフローに「新規」経路(データを生成したばかりで、自然な形式)と「キャッシュ」経路(
_object列からデータを読み込んだばかりで、まだ文字列化された状態)がある場合。誤った対応:キャッシュ経路に「合わせる」ため、新規経路のデータを文字列化する。正しい対応:キャッシュ経路のデータを解析し、どちらの経路でも自然な形式で返す。呼び出し元が、どちらの経路のデータを受け取ったかを知る必要はありません。
エージェントツールとして接続されたサブワークフローについては、n8n-agentsのreferences/SUBWORKFLOW_AS_TOOL.mdを参照してください。
サブワークフローの呼び出し:Execute Workflowのモード
呼び出し元側のExecute Workflowノードでは、入力とworkflowIdのほかに2つの設定があります。
modeのデフォルトは'all'です。 サブワークフローは、N個すべてのアイテムを入力として1回実行されます。他のワークフローと同様に、アイテムはノードをアイテムごとに通過します。mode: 'each'に設定すると、サブワークフローは1回の実行につき1アイテムで、N回個別に実行されます。サブワークフローの本体が通常どおりアイテムを処理するだけなら、この2つは同等です。サブワークフローの本体がアイテムを厳密に1つだけ受け取ることを前提としている場合(実行ごとの集約、「操作対象はこの顧客だけ」というロジック、入力ごとに1回だけ実行すべき最後の書き込みなど)は、モードによる違いが重要です。mode: 'each'はその前提に合いますが、mode: 'all'では合いません。アイテムごとの反復処理が必要な場合は、サブワークフロー内のLoop Over Itemsノードよりmode: 'each'を優先してください。waitForSubWorkflowのデフォルトはtrueです。options.waitForSubWorkflow: falseを設定すると、呼び出しを開始してすぐに次へ進み、サブワークフローはバックグラウンドで続行します。呼び出し元の後続ノードには返却データが渡されません。
mode: 'each'とwaitForSubWorkflow: falseの組み合わせは、n8nが提供する唯一の真の並列化です。N個のサブワークフロー実行が待機なしでディスパッチされ、並行して実行されます(ただし、インスタンスごとの並行処理制限と呼び出しごとのオーバーヘッドの範囲内です)。「独立したジョブをN個開始し、後でポーリング/集約する」場合に便利です。たとえば、アイテムごとに長時間実行されるジョブをディスパッチして、それぞれをData Tableで追跡し、すべての行が完了を示すかタイムアウトするまでループします。
このポーリングによるファイア・アンド・フォーゲットのパターンについては、references/SUBWORKFLOW_PATTERNS.mdの「Fire-and-forget parallelization」を参照してください。
参考ファイル
| ファイル | 読むタイミング |
|---|---|
references/SUBWORKFLOW_PATTERNS.md | mode: 'all' と 'each' のデフォルト、入力形式(バイナリ/パススルーと「Define Below」)に応じた分割、Data Table のポーリングによるファイア・アンド・フォーゲット型の並列化 |
references/NAMING_AND_DISCOVERY.md | 新しいサブワークフローの命名とタグ付け、既存のものの検索、タグの規則 |
アンチパターン
| アンチパターン | 問題点 | 対処法 |
|---|---|---|
| 3つのワークフローで同じ日付解析ノードを重複させる | バグ修正が2か所で行われ、3つ目で漏れます | Parse <format> date という単一のサブワークフローに抽出し、一度だけ作成します(タグは subworkflow) |
| 検索せずに新しいサブワークフローを作る | ライブラリに重複が増え、後で検索すると両方が見つかります | 必ず最初に search_workflows を実行します |
| 純粋な処理として名前や説明が付けられているのに、ログテーブルにひそかに書き込むサブワークフロー | 呼び出し元が再試行や冪等性を判断できず、予期しない副作用に遭遇します | 副作用を契約の一部にする(名前を変更し、説明に記載して、結果を返す)か、外に移します |
description のないサブワークフロー | 今後の検索で見つからず、何をするものか誰にも分かりません | 入力/出力の形式と目的を含む description を設定します |
Helper 3 という名前のサブワークフロー | 名前から用途が分かりません | 動詞で始まる説明的な名前(Parse RFC2822 date など)を付けます。n8n-workflow-lifecycle の NAMING_CONVENTIONS.md を参照してください |
| タグのないサブワークフロー | tags フィルターに表示されず、後で自分でも見つけられなくなります | 作成直後に update_workflow の addTags を使ってタグ(subworkflow、ドメイン、tool)を付けます |
バイナリを扱う予定も、意図的に入力をゼロにする予定もないのに、Execute Workflow Trigger を passthrough に設定する | 型付きスキーマがないため、エージェントツールは fromAi でパラメーターを設定できず、構造化された呼び出し元も値を適切に渡せません | 各フィールドの名前と型を宣言した workflowInputs.values を持つ「Define Below」を使います。例外は、バイナリを受け取るサブワークフローと、実際に入力を一切受け取らないサブワークフローです(「例外 2」を参照) |
Set によるクリアノードも説明用の付箋もない、入力ゼロのサブワークフロー向けパススルートリガー | 本体が呼び出し元から渡された無関係なフィールドをひそかに読み込み、後から読む人はパススルーがバイナリ向けだと誤解します | 本体の先頭に Set(「Keep Only Set」を有効にし、フィールドは設定しない)を追加し、トリガーに入力が不要であることを記した付箋を追加します |
| バイナリ入力を必要とするサブワークフローをエージェントツールとして呼び出す | エージェントツールはバイナリを直接渡せません | 適切なパターンについては、n8n-binary-and-data の AGENT_TOOL_BINARY.md を参照してください |
| 抽出を行わずに30ノードを含むワークフローを作る | 読みにくく、テストしにくく、置き換えにくくなります | 論理的なセクションをサブワークフローに抽出します |