ChatGPTに「JSON形式で返して」と頼んでも、前置きが付く、Markdownのコードフェンスで囲まれる、キー名や型が変わる、といったズレは起こり得ます。手作業で使うならプロンプトを具体化することで安定させやすくなりますが、プログラムで確実に処理したい場合は、プロンプトだけに頼らずAPIのStructured Outputsでスキーマを固定するのが基本です。この記事では、JSON出力の崩れ方を切り分けて、用途ごとの対策を整理します。
まず結論:JSON出力は「構文・スキーマ・値」の3段階で考える
「JSONが返ってきた」だけでは、後続処理で安全に使えるとは限りません。実務では、JSONとして解析できるか、必要なキーや型がそろっているか、値そのものが妥当かを分けて確認すると原因を切り分けやすくなります。
| 確認する段階 | 見るポイント | 主な対策 |
|---|---|---|
| 構文 | JSON.parse()などで解析できるか | プロンプトを具体化する。APIではJSON modeまたはStructured Outputsを使う |
| スキーマ | 必須キー・型・enum・追加キーが想定どおりか | JSON Schemaを定義し、対応するAPIではStructured Outputsを使う |
| 値 | 日付・ID・金額・分類結果などが業務ルール上正しいか | アプリ側のバリデーションや元データとの照合を行う |
OpenAIの公式情報でも、従来のJSON modeは有効なJSONを生成しやすくする一方、特定のスキーマへの一致までは保証しません。スキーマ準拠が必要なAPI連携では、対応モデルでStructured Outputsを使う方が目的に合います。
用語解説:JSON Schema
JSONデータに必要なキー、型、必須項目、許容値などを定義する仕組みです。実務では「JSONとして読める」だけでなく「期待する形か」を機械的に確認するために使います。
ChatGPTのJSON出力が崩れる主な原因
- 「JSONで返して」だけで、ルートをオブジェクトにするか配列にするか指定していない
- 使用するキー名、型、必須項目、nullの扱いを決めていない
- 前置き・補足説明・Markdownのコードフェンスを禁止していない
- 出力例とルールの内容が食い違っている
- 不要なキーを追加してよいかどうかが曖昧になっている
- 出力が長すぎる、または処理が中断され、JSONが途中で終わる
特に多いのは、「JSONという形式」と「欲しいデータ構造」を同じものとして扱ってしまうケースです。JSONとして正しくても、`priority`が数値になったり、必須の`due`が消えたりすれば、アプリ側では別のエラーになります。
ChatGPT画面でJSON形式を安定させるプロンプト
チャット上で一度きりの変換や手作業を行うなら、出力形式を曖昧にしないことが第一歩です。キー、型、欠損時の扱い、禁止事項、出力例をひとまとまりで伝えます。
次の入力を、以下のルールに従ってJSONだけで返してください。
【出力ルール】
- Markdownのコードフェンスは付けない
- 前置き・説明・注釈を付けない
- ルートは1つのJSONオブジェクト
- 使用できるキーは title, priority, due のみ
- priority は "low" | "medium" | "high" のいずれか
- due が不明なら null
- キーを省略しない
- 未定義のキーを追加しない
【出力例】
{"title":"資料作成","priority":"high","due":null}
【入力】
ここに変換したい文章を入れる
この形なら、単に「JSONで」と依頼するより、モデルが満たすべき条件が明確になります。ただし、チャット上の自由文プロンプトはアプリ側の型システムではありません。重要な自動処理に使う場合は、出力後の検証まで前提にしてください。
(JSON以外も含めたChatGPTへの指示精度を上げたい場合については『GPT指示精度を上げる方法|ChatGPTで使える指示テンプレ7選』をご参照ください)
「JSONだけ」と指定しても完全な保証にならない理由
通常のチャットでは、モデルは自然言語の指示を解釈してテキストを生成します。そのため、プロンプトを厳密にしても、形式を機械的に拘束する仕組みとは別物です。前置きやコードフェンスを禁止する指示は有効ですが、「毎回まったく同じ構造になる」という契約として扱うのは避けた方が安全です。
後続処理で使うなら、まずJSONとして解析できるかを確認し、その後に必須キーと型を検証します。文字列から波括弧の範囲だけを切り出すような補正だけで済ませると、構文は直ってもキーずれや値の誤りを見逃すことがあります。
API連携ならStructured OutputsでJSON Schemaを固定する
システムからOpenAI APIを呼び出し、出力をそのままプログラムへ渡す場合は、対応モデルでStructured Outputsを使う方法があります。JSON Schemaと`strict`なスキーマ準拠を組み合わせることで、キー名や型を含む出力構造を固定できます。
import os
from typing import Literal
from pydantic import BaseModel
from openai import OpenAI
class Task(BaseModel):
title: str
priority: Literal["low", "medium", "high"]
due: str | None
client = OpenAI()
model_name = os.environ["OPENAI_MODEL"] # Structured Outputs対応モデルを設定
response = client.responses.parse(
model=model_name,
input="明日の夕方までに資料を仕上げる。優先度は高。",
text_format=Task,
)
task = response.output_parsed
print(task)
SDKや対応モデルは更新されるため、実装時はOpenAIの最新ドキュメントでStructured Outputsへの対応状況を確認してください。重要なのは、プロンプト本文だけで形をお願いするのではなく、アプリ側からスキーマを契約として渡すことです。
用語解説:Structured Outputs
OpenAI APIで、指定したJSON Schemaなどの構造に沿うよう出力を制約する機能です。JSON modeよりも「必要なキーと型を固定したい」用途に向いています。
JSON modeとStructured Outputsは何が違う?
| 方法 | 有効なJSON | 特定スキーマへの準拠 | 向いている用途 |
|---|---|---|---|
| プロンプトだけ | 保証ではない | 保証ではない | チャットでの一時利用、手作業 |
| JSON mode | ○ | × | JSONとして解析できることを優先する既存実装 |
| Structured Outputs | ○ | ○(対応するJSON Schemaの範囲) | キー・型まで固定したAPI連携 |
OpenAIの現行SDK資料でも、`json_object`は従来のJSON mode、`json_schema`はStructured Outputsとして区別され、対応モデルでは`json_schema`が推奨されています。既存システムでJSON modeを使っている場合も、スキーマ不一致のリトライが多いなら移行を検討する価値があります。
Structured Outputsでも値の正しさは別に検証する
スキーマに一致することと、内容が正しいことは別です。たとえば`due`が文字列として返ることを保証できても、その日付が元の文章と一致しているかまではJSON Schemaだけでは判断できません。
- 日付・金額・IDなどは業務ルールに沿って再検証する
- 外部データから抽出した値は、必要に応じて元データと照合する
- 安全上の拒否や出力中断を通常の成功レスポンスとして扱わない
- バリデーション失敗時のリトライ回数とエラー処理を決めておく
- ログへ入力本文を残す場合は、機密情報や個人情報を含めない設計にする
(JSONの構文・データ型・API連携自体を整理したい場合については『JSON完全ガイド|基礎からAPI連携・設計原則・エラー解決まで』をご参照ください)
よくある質問
ChatGPTの画面だけで、毎回まったく同じJSON Schemaを保証できますか?
プロンプトでキー・型・禁止事項を具体的にすると安定させやすくなりますが、通常のチャット上の自由文指示を機械的なスキーマ保証として扱うのは避けた方が安全です。プログラム連携で構造保証が必要なら、対応するOpenAI APIのStructured Outputsを検討してください。
JSON modeを使えばキー名や型も固定されますか?
いいえ。OpenAIの公式説明では、JSON modeは有効なJSONの生成を支援しますが、特定のスキーマへの一致は保証しません。キー名や型まで固定したい場合はStructured Outputsが目的に合います。
Structured Outputsなら返ってくる値も必ず正しいですか?
いいえ。構造がスキーマに一致しても、抽出・分類・推論した値そのものが正しいとは限りません。日付やID、業務上重要な値は別途バリデーションしてください。
まとめ:手作業はプロンプト、システム連携はスキーマで考える
- ChatGPT上で使うなら、キー・型・null・追加キー・前置き禁止まで具体的に指定する
- JSONとして読めることと、期待するスキーマに一致することを分けて考える
- API連携で構造を固定したいなら、対応モデルでStructured Outputsを使う
- スキーマ準拠後も、重要な値の正しさはアプリ側で検証する
まずは「JSONが崩れた」の中身を、構文・スキーマ・値のどこで失敗しているかに分解してください。原因が分かれば、プロンプトを直すべきか、API側で構造を固定すべきか、後段のバリデーションを追加すべきかを判断しやすくなります。