AI APIをWebアプリに組み込むと、自然な文章だけでなく、アプリ側で処理できるJSONが欲しくなる場面が増えます。問い合わせをカテゴリ分類する、記事タイトル案を配列で返す、入力文から項目を抽出する、レビュー結果をスコア付きで返す、といった処理では、文章よりJSONのほうが扱いやすいからです。
ただし、AIに「JSONで返して」と書くだけでは、毎回安全にパースできるとは限りません。説明文が混ざる、キー名が変わる、配列になるはずが文字列になる、途中で出力が切れる、といった問題が起きます。
この記事では、AIにJSONを出力させる基本、プロンプト指定とJSON modeの違い、Structured Outputsとの役割分担、JavaScriptでのパースと検証、よくあるエラーを、Web開発者向けに整理します。
前提として、AIへの指示設計を整理したい場合は、プロンプトエンジニアリングとは?AIに安定した出力をさせる基本 を読むと流れをつかみやすいです。固定指示の考え方は、システムプロンプトとは?AIアプリの振る舞いを固定する設計方法 に分けています。
この記事の内容は、2026年7月9日時点のOpenAI API公式ドキュメントをもとにしています。APIの書き方、JSON mode、Structured Outputs、Function Callingの仕様は変わるため、実装前には必ず公式ドキュメントを確認してください。
結論:AIのJSON出力は小さく指定し、必ずアプリ側で検証する
AIにJSONを出力させるときの基本は、次の3つです。
- 出したいJSONの形を小さく決める
- JSONだけを返すように明示する
- 受け取ったJSONをアプリ側でパース・検証する
OpenAIのStructured Outputsドキュメントでは、JSON modeは有効なJSONを出しやすくする基本機能であり、Structured Outputsは指定したJSON Schemaへの一致まで扱う機能として説明されています。JSON modeは便利ですが、特定のスキーマに必ず一致することまでは保証しません。
つまり、AI JSON出力は次のように段階で考えます。
| 方法 | できること | 向いている場面 |
|---|---|---|
| プロンプトでJSONを指定 | 出力形式を文章で頼む | 試作、軽い下書き、手動確認前提 |
| JSON mode | 有効なJSONを出しやすくする | 簡単な構造化、パース前提の実装 |
| Structured Outputs | JSON Schemaに沿った出力を狙う | 本番の厳密なデータ構造、UI生成、DB保存 |
| Function Calling | AIにアプリ側の関数やツールを選ばせる | 外部API実行、DB検索、処理の分岐 |
この記事では、まずJSON出力の基本と最小実装を扱います。JSON Schemaで厳密に固定する方法は、後続の `structured-outputs-basics` で深掘りします。
AIにJSONを出力させる方法で作るもの
この記事では、問い合わせ文をAIに渡し、次のようなJSONを返してもらう例で考えます。
{
"category": "billing",
"priority": "high",
"summary": "請求金額が想定より高い理由の確認依頼",
"needs_human_review": true
}
このようなJSONが得られると、Webアプリ側で次のように使えます。
- カテゴリごとに担当チームへ振り分ける
- 優先度が高い問い合わせを管理画面で上に出す
- 要約を一覧画面に表示する
- 人間確認が必要なものだけ別キューへ送る
- 後から分析しやすい形でDBに保存する
自然文のままでは、アプリ側が「どこがカテゴリで、どこが要約か」を判断しにくくなります。JSONにすると、JavaScriptやPHP、Reactなどで値を取り出して扱いやすくなります。
APIレスポンスとしてJSONを扱う基本は、JavaScriptでJSONデータを取得する方法 も参考になります。Reactで取得したJSONを表示する流れは、Reactで取得したJSONデータを画面に表示する方法 ともつながります。
前提環境を確認する
この記事のコード例は、考え方を示すための最小例です。実際のSDK、モデル名、レスポンス形式は、利用しているAPIの公式ドキュメントに合わせてください。
前提は次のとおりです。
- サーバー側のJavaScriptからAI APIを呼び出す
- APIキーは環境変数などで管理する
- ユーザー入力はそのまま信用しない
- AIの出力は必ずパースと検証を行う
- 厳密なスキーマ固定はStructured Outputsへ分ける
AI APIをブラウザから直接呼ぶと、APIキー漏洩や利用量制御の問題が起きます。AI機能はサーバー側を経由するのが基本です。クライアントとサーバーの役割は、クライアントサーバーシステムとは も参考になります。
方法1:プロンプトでJSON形式を指定する
最も簡単なのは、プロンプトに「JSONだけで返してください」と書く方法です。
次の問い合わせ文を分類してください。
出力はJSONだけにしてください。説明文やMarkdownは不要です。
形式:
{
"category": "billing | login | bug | cancellation | other",
"priority": "low | medium | high",
"summary": "50文字以内の要約",
"needs_human_review": true
}
問い合わせ文:
先月より請求金額が高い理由を確認したいです。
この方法は、すぐ試せるのが利点です。プロンプトエンジニアリングの記事で扱ったように、目的、入力、制約、出力形式を整理して書くと、ある程度安定します。
ただし、プロンプト指定だけでは次のような問題が起きます。
- JSONの前後に説明文が混ざる
- ダブルクォートではなくシングルクォートになる
- キー名が `needsReview` などに変わる
- booleanのはずが `”true”` の文字列になる
- 出力が途中で切れてJSONとして壊れる
手動で見るだけなら問題にならない場合もありますが、Webアプリで `JSON.parse()` するなら、壊れる前提で設計します。
方法2:JSON modeで有効なJSONに近づける
OpenAI APIでは、JSON modeを使うことで、モデルの出力を有効なJSONにしやすくできます。Responses APIでは `text.format` に `{ “type”: “json_object” }` を指定する形が説明されています。
概念コードは次のようになります。
const response = await client.responses.create({
model: process.env.AI_MODEL,
instructions: `
問い合わせ分類AIです。
必ずJSONだけを返してください。
説明文、Markdown、コードフェンスは出力しないでください。
`,
input: `
問い合わせ文を分類してください。
返すJSON:
- category: billing, login, bug, cancellation, other のどれか
- priority: low, medium, high のどれか
- summary: 50文字以内
- needs_human_review: boolean
問い合わせ文:
${inquiryText}
`,
text: {
format: {
type: "json_object"
}
}
});
const rawText = response.output_text;
const data = JSON.parse(rawText);
OpenAIのStructured Outputsドキュメントでは、JSON modeを使う場合でも、会話内のどこかでJSONを生成するよう明示的に指示する必要があると説明されています。JSON modeの設定だけでなく、システムプロンプトや入力側でも「JSONだけ」と明示します。
また、JSON modeは有効なJSONを出しやすくしますが、特定のスキーマに必ず一致するわけではありません。スキーマ一致が必要なら、Structured Outputsを検討します。
最小コードを書く
ここでは、AIの出力を受け取り、`JSON.parse()` して、最低限の検証を行う流れを作ります。
function validateInquiryJson(value) {
const categories = ["billing", "login", "bug", "cancellation", "other"];
const priorities = ["low", "medium", "high"];
if (!value || typeof value !== "object") {
return false;
}
if (!categories.includes(value.category)) {
return false;
}
if (!priorities.includes(value.priority)) {
return false;
}
if (typeof value.summary !== "string" || value.summary.length === 0) {
return false;
}
if (typeof value.needs_human_review !== "boolean") {
return false;
}
return true;
}
async function classifyInquiry(client, inquiryText) {
const response = await client.responses.create({
model: process.env.AI_MODEL,
instructions: `
問い合わせ分類AIです。
必ずJSONだけを返してください。
説明文やMarkdownは出力しないでください。
`,
input: `
問い合わせ文を分類してください。
JSONの形式:
{
"category": "billing | login | bug | cancellation | other",
"priority": "low | medium | high",
"summary": "50文字以内の要約",
"needs_human_review": true
}
問い合わせ文:
${inquiryText}
`,
text: {
format: {
type: "json_object"
}
}
});
let data;
try {
data = JSON.parse(response.output_text);
} catch {
throw new Error("AI output is not valid JSON");
}
if (!validateInquiryJson(data)) {
throw new Error("AI output does not match expected fields");
}
return data;
}
このコードは、最小限の考え方です。本番では、入力の長さ制限、ログ、リトライ、ユーザー権限、個人情報の扱い、エラー時の表示を追加します。
処理の流れを分解する
AI JSON出力は、次の流れで考えると実装しやすくなります。
ユーザー入力
↓
入力検証
↓
プロンプトとJSON形式を指定
↓
AI APIへ送信
↓
JSON文字列を受け取る
↓
JSON.parse
↓
必須項目・型・値を検証
↓
UI表示・DB保存・人間確認へ分岐
重要なのは、AIが返したJSONをそのまま信用しないことです。
たとえば、次のような出力は、見た目は近くてもアプリ側では扱いづらくなります。
{
"category": "請求",
"priority": "高",
"summary": "",
"needs_human_review": "yes"
}
人間には意味が分かりますが、アプリ側では `category` が想定値ではなく、`priority` も英語の列挙値ではなく、`needs_human_review` もbooleanではありません。AIの出力は、必ずアプリ側の期待値へ合っているか確認します。
実務向けに拡張する
最小実装が動いたら、次のように拡張します。
| 拡張 | 目的 | 例 |
|---|---|---|
| 入力制限 | トークン増加や想定外入力を防ぐ | 問い合わせ文は5000文字まで |
| 列挙値の固定 | アプリ側の分岐を安定させる | categoryは5種類だけ |
| 型チェック | DB保存やUI表示の事故を防ぐ | boolean、number、stringを確認する |
| リトライ | 一時的な形式崩れに対応する | JSON不正なら1回だけ再生成する |
| 人間確認 | 判断が難しいものを安全に扱う | 不明カテゴリはレビューキューへ送る |
| ログ | 失敗原因を追えるようにする | モデル名、プロンプトバージョン、usageを保存する |
AI出力をそのまま画面に出すだけなら、多少の揺れは許容できる場合があります。しかし、DBに保存する、ワークフローを分岐する、外部APIを呼ぶ、ユーザーへ自動返信する場合は、検証を強める必要があります。
Structured OutputsやFunction Callingとの違い
AI JSON出力を考えるときは、Structured OutputsとFunction Callingとの違いも押さえておくと混乱しにくくなります。
| 方法 | 主な目的 | この記事での扱い |
|---|---|---|
| JSON mode | 有効なJSONとして返しやすくする | この記事の中心 |
| Structured Outputs | JSON Schemaに沿った出力を得る | 次の記事で深掘り |
| Function Calling | AIにアプリ側の関数やツールを選ばせる | 外部処理連携の記事で深掘り |
OpenAIのStructured Outputsドキュメントでは、モデルをツールや関数、データに接続する場合はFunction Calling、ユーザーへの応答を構造化したい場合はStructured Outputsを使う考え方が示されています。
また、JSON modeは有効なJSONを出す助けになりますが、スキーマ一致までは保証しません。OpenAIの最新モデル向けガイドでも、期待する出力スキーマをプロンプト内で説明しすぎるより、Structured Outputsを使う考え方が示されています。
この記事では、まずAIの出力をJSONとして受け取り、アプリ側で安全に扱う基本を押さえます。
よくあるエラーと原因
AI JSON出力では、次のようなエラーが起きやすいです。
JSON.parseでエラーになる
JSONの前後に説明文、Markdownのコードフェンス、余計なコメントが混ざっている可能性があります。プロンプトで「JSONだけ」と明示し、JSON modeを使い、パース失敗時の処理を用意します。
キー名が変わる
`needs_human_review` を期待しているのに、`needsReview` や `human_review` になることがあります。キー名を明示し、検証で弾きます。厳密に固定したい場合はStructured Outputsを検討します。
型が変わる
booleanのはずが文字列、numberのはずが説明文になることがあります。`typeof` やバリデーションライブラリで確認します。
配列とオブジェクトが入れ替わる
1件の問い合わせではオブジェクト、複数件では配列にしたい場合は、入力件数と出力形式を明確に分けます。処理側でも配列かどうかを確認します。
出力が途中で切れる
出力が長すぎる、コンテキスト上限に近い、最大出力が足りないと、JSONが途中で切れることがあります。項目数を減らし、出力を短くし、コンテキストウィンドウとトークンを確認します。
想定外のカテゴリが返る
ラベル定義が曖昧な場合に起きます。カテゴリの説明、例、迷ったときのルールを追加します。それでも本番では検証で弾きます。
セキュリティ・料金・運用の注意点
AI JSON出力は便利ですが、Webアプリに組み込むときは安全面と運用面も考えます。
- ユーザー入力をそのまま信じない
- AIが返したJSONをそのままDB更新や外部API実行に使わない
- 個人情報や機密情報を必要以上に渡さない
- パース失敗や検証失敗をログに残す
- 失敗時にユーザーへ見せるメッセージを用意する
- 長すぎる入力や出力でトークンが増えすぎないようにする
- モデル変更時にJSON出力が崩れないか再テストする
トークン量や料金は、入力プロンプト、出力JSON、例文、会話履歴で増えます。基本は AIのトークンとは? を参考にしてください。長文入力や履歴の扱いは、コンテキストウィンドウとは? で整理しています。
安全面では、システムプロンプトに「危険なことをしない」と書くだけでは不十分です。権限、検証、ログ、人間確認が必要です。基本的な注意点は、生成AIの安全な使い方 も参考になります。
次に読むべき関連記事
AIのJSON出力を理解したら、次は厳密な構造固定や外部処理連携へ進むと実装がつながります。
- プロンプトエンジニアリングとは?: JSON出力の前提になる指示設計を確認したい場合
- システムプロンプトとは?: JSON出力の固定ルールをどこに置くか確認したい場合
- JavaScriptでJSONデータを取得する方法: APIレスポンスとしてJSONを扱う基本を確認したい場合
- Reactで取得したJSONデータを画面に表示する方法: JSONをUIへ反映する基本を確認したい場合
- JavaScript Promiseの基本: 非同期でAI APIを扱う基礎を確認したい場合
- AIとは?エンジニアがWeb開発で押さえるべき基本を解説: AI API実装の全体像を確認したい場合
次に進むなら、`structured-outputs-basics` でJSON Schemaによる出力固定を扱うのが自然です。その後に、Function Callingで外部関数やAPIをAIに選ばせる流れへ進むと、AIアプリの実装範囲が広がります。
まとめ
AIにJSONを出力させると、分類、要約、抽出、スコアリング、管理画面表示、DB保存など、Webアプリで扱いやすい形にできます。
ただし、「JSONで返して」と頼むだけでは、本番で安全に使えるとは限りません。プロンプトで出力形式を明示し、JSON modeを使い、`JSON.parse()` とアプリ側のバリデーションで必須項目、型、列挙値を確認します。
JSON modeは有効なJSONを出しやすくする基本機能です。厳密なJSON Schema一致が必要な場合は、Structured Outputsを使う設計へ進みます。まずは小さなJSONから動かし、失敗例をログに残しながら、プロンプトと検証処理を育てていくのがおすすめです。