はじめに
業務自動化で生成AI(ChatGPT APIやGemini APIなど)を使う時、最も困るのが 「JSON以外の余計な挨拶」 が入ってパースエラーになることではありませんか?
Here is the JSON you requested:
{
"summary": "..."
}
このたった一行の「Here is...」があるせいで、後続の n8n ノードや Google Apps Script (GAS) の JSON.parse() がコケて、ワークフロー全体が停止してしまいます。
OpenAIの「JSON Mode」を使うのも手ですが、Gemini 1.5 Flash や Claude 3 Haiku など、安価で爆速なモデル では非対応だったり、設定が面倒だったりする場合があります。
そんな時は、プロンプトの最後に 「出力例」を一つ渡すだけ で、AIの出力を劇的に安定させられます。今回はその具体的な手法を紹介します。
失敗例:フォーマット指定だけでは不安定
よくある失敗パターンが、「言葉で禁止する」アプローチです。
# 命令
以下の文章から情報を抽出し、JSON形式で出力してください。
余計な解説は絶対に不要です。JSONのみを出力してください。
# 入力テキスト
...
「余計な解説は不要」と強く言っても、LLM(特にチャット用に調整されたモデル)は学習データの影響で「ユーザーに丁寧に説明を入れたほうが良い」というバイアスがかかっています。
その結果、親切心で「はい、解析しました。結果はこちらです:」という文言をつけてしまい、自動化フローを破壊します。
解決法:「出力例」を見せる (One-shot Prompting)
システムプロンプトやユーザープロンプトの最後に、期待するJSONの具体例(One-shot) を含めることで、AIは「この形式に厳密に従うべきだ」と認識します。
「やってはいけないこと」を教えるより、「やるべき正解」を見せる方が、LLMにとっては遥かに分かりやすいのです。
成功するプロンプト構成
# 命令
以下の文章から情報を抽出し、JSON形式で出力してください。
# 出力フォーマット例(以下の形式に厳密に従うこと)
{
"summary": "要約テキストがここに入ります",
"tags": ["tag1", "tag2", "tag3"],
"score": 85,
"isUrgent": false
}
# 入力テキスト
ここに分析対象のテキストを記載...
「余計な解説は不要」という抽象的な指示よりも、具体的な「例」を見せた方が、LLMは従順になります。
これは One-shot prompting と呼ばれるテクニックの一種で、特に構造化出力が必要な業務自動化では、最もコスパの良い安定化手法です。
n8nでの実装例
n8nの「AI Agent」ノードや「Basic LLM Chain」で使用する場合の実践的な構成です。
- System Message または User Message の末尾に上記の「出力例」を含める。
- (GPT-4など対応モデルなら)「Format JSON Output」オプションも併用するとなお良し。
- 後続に Codeノード を置き、安全にパースする。
n8n Codeノードでの「安全なパース」コード
万が一、AIが前後に文字をつけてしまった場合に備え、正規表現でJSON部分だけを抜き出すフォールバック処理を入れておくと完璧です。
// n8n Codeノード用
const aiOutput = $('AI Agent').item.json.output; // AIの出力テキストを取得
let result;
try {
// 1. まずはそのままパースを試みる
// 出力例を提示していれば、大抵はここで成功します
result = JSON.parse(aiOutput);
} catch (e) {
// 2. 失敗した場合のフォールバック
// 正規表現で最初の中括弧 { から 最後の中括弧 } までを抽出する
const match = aiOutput.match(/\{[\s\S]*\}/);
if (match) {
try {
result = JSON.parse(match[0]);
} catch (e2) {
throw new Error("JSONの抽出に失敗しました: " + aiOutput);
}
} else {
throw new Error("有効なJSONが見つかりません: " + aiOutput);
}
}
return result;
なぜ「例」が効くのか
LLMは確率的に「次の単語」を予測するマシンです。
抽象的な制約(「JSONだけ出して」)を与えられた場合、AIは「会話」の続きとして自然な言葉を選ぼうとします。
しかし、具体的なパターン(「こういうJSONを出したら正解」) が文脈(Context)の最後に提示されていると、モデルは「このパターンの続き」を生成しようとします。つまり、JSONの構文を開始する確率が極めて高くなるのです。
これは特に以下のモデルで有効です:
- Gemini 1.5 Flash: JSON Modeの設定がAPI経由だと少々手間だが、プロンプトだけで制御できれば非常に高速・安価。
- Claude 3 Haiku: 高速だが、厳密なJSON出力には明確な指示が必要。
- GPT-3.5 / 4o-mini: JSON Modeがあるが、One-shotを併用することで精度がさらに向上する。
応用:スキーマ定義の提示
より厳密に制御したい場合は、出力例に加えて「型定義(スキーマ)」も含めます。
TypeScriptのInterface定義風に書くと、LLMは理解しやすいです。
# 出力スキーマ
- summary: string (200文字以内)
- tags: string[] (最大5件)
- score: number (0-100の整数)
- isUrgent: boolean
# 出力例
{
"summary": "...",
"tags": ["example"],
"score": 80,
"isUrgent": false
}
これにより、キーのスペルミス(Score vs score)や、型の不一致("80" vs 80)も防げます。
まとめ
- 「JSONで返して」だけでは、LLMは親切心で余計な説明を入れがち。
- 「出力例」をプロンプトに含めることで、意図した形式に安定化させる。
- 正規表現による抽出ロジック(Codeノード)を挟めば、エラー率はほぼゼロに。
- JSON Mode非対応の安価なモデル(Gemini Flash等)でも実用レベルになる。
業務でAIを使うなら「出力例(One-shot)」は必須のテクニックです。
たった数行の追加で、エラーハンドリングやリトライのコストを大幅に削減できます。ぜひ試してみてください。
この記事を書いた人✏️@YushiYamamoto
株式会社プロドウガ CEO / AIアーキテクト
Next.js / TypeScript / n8nを活用した自律型アーキテクチャ設計を専門としています。
日々の自動化の検証結果や、ビジネス側の視点(ROI等)に関するより深い考察は、以下の公式サイトおよびnoteで発信しています。
