OpenAI互換APIとJSON Schema検証を使ったn8nの人手承認ワークフロー
OpenAI互換APIで構造化データを抽出し、JSON Schemaに対して結果を検証したうえで、影響の大きいツールの実行前に人手承認を求めるn8nワークフローを構築します。
目次
抽出だけでなく、アクションを承認する
請求書、サポートチケット、フォーム、受信リクエストでは、リスクが高いのはフィールドの抽出そのものではないことがよくあります。顧客レコードの作成、ステータスの変更、外部メッセージの送信、データの削除など、その後に何が起きるかが問題になります。
そのため、堅牢なn8n設計では、次の3つのゲートを設けます。
- 抽出: OpenAI互換APIが構造化データを返す。
- 検証: n8nがデータがJSON Schemaに準拠しているかを確認する。
- 承認: 人が承認した後にのみ、n8n AI Agentが影響の大きいツールを呼び出せるようにする。
これにより、不正なデータがレビュアーに届くのを防ぎ、承認済みの実行をモデルの出力から分離できます。
OneMuxは、1つのOpenAI互換APIを通じて主要なAIモデルにアクセスできるようにします。エンドポイントと選択したモデルが、n8nの構成に必要なリクエスト形式とパラメータをサポートしていることが文書で確認できる場合、モデルへのアクセス経路として利用できます。ここでは、OneMuxとn8nの連携がテスト済みであるとは主張していません。
前提条件
必要なものは次のとおりです。
- HTTP Request、Code、および該当する場合はAI Agentノードを利用できるn8nインスタンス。
- n8nの構成でサポートされている承認チャネル。n8n Chat、Slack、Telegram、メール、その他の文書化されたチャネルなど。
- OpenAI互換APIへのアクセス。OneMuxを利用する場合は、まずOneMuxクイックスタートを参照し、OneMuxドキュメントで現在のエンドポイント、認証方式、モデル識別子、サポートされているリクエストパラメータを確認してください。
- 抽出したいオブジェクトを定義するJSON Schema。
- 人手レビューなしでは実行すべきでない宛先ツール。CRMの更新やメッセージ送信アクションなど。
すべてのOpenAI互換エンドポイントが、すべての構造化出力機能をサポートしているとは限りません。response_format、JSON Schema、ツール呼び出し、選択したモデルがサポートされていることを確認してください。OneMuxモデルディレクトリは利用可能なモデルの選択肢を確認するのに役立ちますが、それだけで特定のn8nノード構成がサポートされていることを証明するものではありません。
推奨されるn8nワークフロー
実用的なワークフローでは、次のノードを使用できます。
- Webhookまたは別のトリガーが入力テキストを受け取る。
- HTTP Requestがテキストを互換モデルのエンドポイントに送信する。
- Codeが返されたオブジェクトを解析して検証する。
- IFが無効な結果をエラーまたは手動修正の経路に振り分ける。
- AI Agentが検証済みオブジェクトを受け取り、影響の大きいツールにアクセスできるようにする。
- 人手レビューがそのツールの実行前にワークフローを一時停止する。
- 承認済みツールがレコードを書き込む、またはメッセージを送信する。
抽出リクエストでは、ワークフローに必要なフィールドだけを要求します。サポートリクエスト向けの簡潔なスキーマ例は次のようになります。
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"additionalProperties": false,
"required": ["category", "priority", "summary", "customer_email"],
"properties": {
"category": {
"type": "string",
"enum": ["billing", "technical", "account", "other"]
},
"priority": {
"type": "string",
"enum": ["low", "normal", "high", "urgent"]
},
"summary": {
"type": "string",
"minLength": 1
},
"customer_email": {
"type": "string",
"format": "email"
}
}
}
OpenAI互換リクエストを設定する
HTTP Requestノードでは、プロバイダーのドキュメントに記載されたベースURLと認証手順を使用します。アカウントと地域に対して確認していないプロバイダー固有のURLをハードコードしないでください。
以下のリクエスト形式は例示です。response_formatとそのJSON Schema構造が受け入れられるかどうかは、選択したエンドポイント、モデル、n8n構成によって異なります。
{
"model": "YOUR_DOCUMENTED_MODEL_ID",
"messages": [
{
"role": "system",
"content": "Extract the requested fields. Do not guess missing values. Return only an object matching the supplied schema."
},
{
"role": "user",
"content": "{{$json.source_text}}"
}
],
"temperature": 0,
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "support_request",
"strict": true,
"schema": {
"type": "object",
"additionalProperties": false,
"required": ["category", "priority", "summary", "customer_email"],
"properties": {
"category": {"type": "string"},
"priority": {"type": "string"},
"summary": {"type": "string"},
"customer_email": {"type": "string"}
}
}
}
}
}
この例では、意図的にプレースホルダーのモデルIDを使用しています。選択したエンドポイントとの互換性が文書化されているモデルを選択してください。厳格なJSON Schema出力が利用できない場合は、検証経路で準拠していないレスポンスを安全に拒否できるときに限り、サポートされているJSONモードを使用します。JSONモードだけではスキーマ検証と同等ではありません。
実行前にレスポンスを検証する
プロバイダーのレスポンスでは、生成されたコンテンツが異なるフィールドに格納されることがあります。パーサーを作成する前に、n8nで実際のレスポンスを1件確認してください。次のCodeノードは、モデルがmessage.contentにJSON文字列を返したことを前提としています。実際に受け取るレスポンスに合わせてパスを調整してください。
const raw = $json.choices?.[0]?.message?.content;
if (typeof raw !== 'string') {
throw new Error('Model response did not contain message.content as a string');
}
let extracted;
try {
extracted = JSON.parse(raw);
} catch (error) {
throw new Error('Model returned invalid JSON');
}
const required = ['category', 'priority', 'summary', 'customer_email'];
const missing = required.filter((key) => extracted[key] === undefined || extracted[key] === '');
const validCategory = ['billing', 'technical', 'account', 'other'].includes(extracted.category);
const validPriority = ['low', 'normal', 'high', 'urgent'].includes(extracted.priority);
const validEmail = typeof extracted.customer_email === 'string' &&
/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(extracted.customer_email);
if (missing.length || !validCategory || !validPriority || !validEmail) {
throw new Error('Extracted object failed application validation');
}
return [{ json: { extracted } }];
本番環境では、n8nのデプロイ環境で許可される場合、この簡易チェックを保守されたJSON Schemaバリデーターに置き換えてください。リクエスト内のスキーマと検証で適用するスキーマは、同じものとしてバージョン管理する必要があります。後続システムで改訂を区別する必要がある場合は、出力にスキーマバージョンを追加してください。
AI Agentツールに人手承認を追加する
検証済みオブジェクトをAI Agentのコンテキストとして使用します。広範なデータベースアクセスではなく、CreateSupportTicketのように範囲を限定したツールをAgentに与えてください。AI AgentのTools Panelで、その特定のツールに対する人手レビューを設定します。
n8nのドキュメントによると、レビューが必要なツールをAgentが実行しようとすると、ワークフローは一時停止します。レビュアーは、提案された入力でツールを実行できるよう呼び出しを承認することも、アクションをキャンセルするために拒否することもできます。n8nは、組み込みのチャットインターフェースのほか、Slack、Telegram、Discord、Teams、メール、WhatsApp、Google Chat、Outlookメールなどの連携を含む複数の承認チャネルをサポートしています。現在の設定手順とチャネルの詳細は、公式のn8n human-in-the-loopドキュメントを参照してください。
有用な承認メッセージでは、実行予定のアクションとパラメータを明示します。
The AI wants to use {{ $tool.name }} with the following parameters:
{{ JSON.stringify($tool.parameters, null, 2) }}
元のドキュメントでは、このレビューコンテキストに$tool.nameと$tool.parametersを使用しています。レビュアーが追加のコンテキストを必要とする場合に備え、メッセージを読みやすくし、元のリクエストまたはチケット参照を含めてください。
Agentのシステムプロンプトでは、レビュー時の動作も説明してください。
The CreateSupportTicket tool requires human approval. If approval is denied, do not retry automatically. Tell the user that the action was not completed and explain what information or correction is needed.
制限事項とトラブルシューティング
モデルがMarkdownや余分なテキストを返す
送信した構造化出力パラメータをエンドポイントがサポートしているか確認してください。サポートされていない場合は、未対応のパラメータを削除し、指示を明確にしたうえで、Codeノードの検証を厳格なゲートとして維持します。検証していないオブジェクトをライトツールに渡してはいけません。
n8nが想定したレスポンスフィールドを見つけられない
HTTP Requestの出力を確認し、パーサーを更新してください。OpenAI互換APIはリクエストの慣例を共有していても、レスポンスの詳細やサポートされるパラメータが異なる場合があります。
承認リクエストが曖昧すぎる
範囲を限定したツールを使用し、承認メッセージに$tool.nameと$tool.parametersを含めてください。「このリクエストを処理する」といった不透明な指示をレビュアーに承認させないでください。
拒否されたツール呼び出しがループする
Agentのシステムプロンプトに拒否時の動作を明示し、拒否によってアクション経路を終了するか、確認に振り分けるようワークフローを設定してください。n8nのドキュメントでは、承認が必要なツールと、拒否された場合にAgentがどう応答すべきかを説明することが推奨されています。
レビュアーが誤ったデータを承認する
スキーマに適合していることは、意味的な正しさを証明しません。入力の抜粋、抽出されたフィールド、実行予定のアクションを一緒に表示してください。影響の大きいワークフローでは、レビュアーに機密フィールドを個別に確認してもらう必要があります。
まとめ
構造化抽出における安全なn8nパターンは、「モデルに直接書き込ませる」ことではありません。制約されたオブジェクトに抽出し、検証したうえで、外部に影響を与えるツールの前に人手承認を配置します。OpenAI互換APIはモデルへのアクセスを簡素化でき、n8nはオーケストレーションと承認の制御を提供します。OneMuxを使用する場合は、文書化された互換エンドポイントとモデルパラメータを使い、自分の環境で構成を検証してください。サポートされていない構造化出力機能がある場合は、処理を停止するか、別途検証するレスポンス経路に切り替える理由と考えてください。
よくある質問
n8nはOneMuxをOpenAI互換APIとして利用できますか?
OneMuxのエンドポイントと選択したモデルが、n8nの構成に必要なリクエスト形式とパラメータをサポートしていれば、利用できる可能性があります。この記事では、OneMuxとn8nの連携がテスト済みであるとは主張していません。OneMuxのドキュメントで、現在のエンドポイント、認証方式、モデルID、構造化出力のサポートを確認してください。
人手承認はJSON Schema検証の前と後、どちらに行うべきですか?
通常は検証の後です。レビュアーには、形式が不正または不完全なモデル出力ではなく、構造的に有効な提案アクションを提示する必要があります。検証によって値の意味的な正しさが保証されるわけではないため、レビュアーは抽出フィールドを入力元と比較する必要があります。
JSONモードを使えば、レスポンスが必ず自分のスキーマに一致しますか?
いいえ。JSONモードは通常、JSON形式を扱うものであり、すべてのプロパティ、型、列挙値、必須フィールドの制約まで保証するものではありません。利用できる場合はサポートされたJSON Schemaレスポンス形式を使用し、影響の大きいツールを呼び出す前に、n8nで同じスキーマを独立して適用してください。
どのn8nツールに人手承認を必須にすべきですか?
外部通信の送信、レコードの変更、データの削除、購入、その他の取り消し不能または価値の大きいアクションを実行するツールを優先してください。読み取り専用ツールに同じレベルのレビューが必要かどうかは、リスクとコンプライアンス要件によって異なります。
レビュアーがn8nのツール呼び出しを拒否するとどうなりますか?
n8nのドキュメントによると、アクションはキャンセルされ、AIには拒否が通知されます。Agentのプロンプトで、自動的に再試行せず、ユーザーに伝える、代替案を提示する、または確認を求めるよう指示してください。
関連記事
Guides
人による承認とテスト検証を備えたn8nのコード変更ワークフローを構築する
リポジトリへの変更を提案し、書き込み前に担当者の承認を得て、生成されたコミットをテストで検証するn8nワークフローを設計します。
Guides
n8nで人の承認とOpenAI互換APIを使った文書Q&Aワークフローを構築する
出典の明示、必要に応じた人の承認、OneMux経由の条件付きOpenAI互換モデル接続を組み込んだ、実践的なn8n文書Q&A設計を解説します。
Guides
GPT 6.1 Terraの料金とコンテキスト:信頼性の高いJSON抽出ガイド
OneMuxを通じたJSON Schema検証付きの構造化抽出で、GPT 6.1 Terraのワークロード料金、コンテキスト、リトライ、出力トークンを見積もり、上限を設定する方法を解説します。
Guides
ツール呼び出し・人間による承認・実行制限を備えたLangGraphカスタマーサポートエージェントの構築
カスタマーサポートのトリアージに使えるLangGraphの実践パターンを紹介。問い合わせの振り分け、検索ツールの呼び出し、人による承認まで返金を保留する方法、グラフ実行を制限する方法を解説します。