OpenAI 400エラーの解決:JSONモードでプロンプトに「json」という単語が必要な理由

beginner🧠 AI Tools2026-05-24| Python (OpenAI SDK v1.0+), Node.js, OpenAI API (モデル: gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-3.5-turbo-0125)

Error Message

openai.BadRequestError: Error code: 400 - {'error': {'message': "'messages' must contain the word 'json' in some form, to use 'response_format' of type 'json_object'.", 'type': 'invalid_request_error', 'param': 'messages', 'code': 'invalid_request_error'}}
#openai#jsonモード#python#gpt-4o#apiエラー

厄介な400エラー

response_format={"type": "json_object"}を使用してJSONモードを有効にし、クリーンで構造化されたレスポンスを期待していると、代わりにAPIから400 Bad Requestエラーが返されることがあります。これは多くの開発者を立ち止まらせる、よくあるハードルです。エラーは次のようになります:

openai.BadRequestError: Error code: 400 - {'error': {'message': "'messages' must contain the word 'json' in some form..."}}

なぜこれが起こるのか

JSONモードは、スマートな機能というよりも、厳格なガードレールのようなものだと考えてください。このモードを有効にすると、APIはモデルの出力を構文的に正しいJSONにするよう強制します。しかし、モデルは読心術師ではありません。プロンプトでカジュアルな会話を求めているのに、API設定でJSON構造を強制すると、両者が衝突してしまいます。

この衝突を防ぐため、OpenAIはシンプルなセーフティチェックを適用しています。リクエスト内の少なくとも1つのメッセージに「json」という文字列が含まれていなければなりません。これを忘れると、APIはモデルがプレーンテキストを出力しようとする可能性(JSON制約に違反する)があると判断し、トークンを消費する前にリクエスト全体を拒否します。

プロンプトの修正方法

修正は簡単です。メッセージ履歴のどこかで、JSONを使用するようにモデルに明示的に伝える必要があります。これはどこに記述しても構いませんが、システムメッセージに追加するのが、最初から正しい期待値を設定するための最も確実な方法です。

方法1:システムメッセージ(ベストプラクティス)

システム指示の中で出力形式を定義します。これにより、モデルは自分の主な目的が雑談ではなくデータ生成であることを理解します。

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "あなたはデータ抽出ボットです。常に結果をJSON形式で返してください。"},
        {"role": "user", "content": "日本で人口の多い上位3都市は何ですか?"}
    ],
    response_format={"type": "json_object"}
)

方法2:ユーザーメッセージ

システムメッセージを使用していない場合は、直接のリクエストの中で形式に言及してください。APIのチェックは大文字と小文字を区別しません。「JSON」でも「json」でも問題なく動作します。

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "user", "content": "健康的なスナックを5つリストアップしてください。形式:JSON"}
    ],
    response_format={"type": "json_object"}
)

Python実装の完全な例

プロンプトの要件を満たし、出力を安全にパースするスクリプトを以下に示します。モデルの出力が予期せず切り捨てられた場合にクラッシュを防ぐため、json.loads()の呼び出しをどのようにラップしているかに注目してください。

import json
from openai import OpenAI

client = OpenAI(api_key="your_api_key")

try:
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system", 
                "content": "ユーザーの詳細を、キーが 'name'、'age'、'city' のJSONオブジェクトとして抽出してください。"
            },
            {
                "role": "user", 
                "content": "私はサラ、シアトル出身の32歳のエンジニアです。"
            }
        ],
        response_format={"type": "json_object"}
    )

    # 文字列出力を実際の辞書に変換する
    raw_content = response.choices[0].message.content
    data = json.loads(raw_content)
    print(f"Parsed Data: {data}")

except Exception as e:
    print(f"Failed to process request: {e}")

不可欠な確認チェックリスト

本番環境に移行する前に、以下の3つのチェックで実装を確認してください:

- **HTTP 200 OK:** 400が表示される場合は、`messages`配列の中に「json」という単語が実際に含まれているか再確認してください。
- **Finish Reason:** `response.choices[0].finish_reason`を確認してください。`length`となっている場合、モデルのトークンが不足し、JSONが破損している可能性があります。理想的には`stop`であるべきです。
- **より優れた代替案:** スキーマの信頼性を100%にするには、**Structured Outputs** (`response_format: { type: "json_schema", ... }`) の使用を検討してください。この新しい機能では、プロンプトで「json」と言及する必要がなく、出力が正確なキーとデータ型に一致することを保証します。

開発のヒント

JSONを正しく扱うのは難しい場合があります。JSONモードを使用しても、制限に達すると、モデルが末尾に余計なカンマを付けたり、閉じ括弧を忘れたりすることが稀にあります。私はデバッグ中、ToolCraftのJSON Formatter & Validatorのようなツールを常に使用しています。これはネストされた構造を可視化するのに役立ち、乱雑なターミナルログでは見つけにくい構文エラーをキャッチしてくれます。

注意:JSONモードは、gpt-4ogpt-4-turbo、およびgpt-3.5-turbo-1106(またはそれ以降)で利用可能です。オリジナルのgpt-4やそれ以前のモデルで使用しようとすると、APIはパラメータを無視するか、エラーを返します。

Related Error Notes