メインコンテンツへスキップ
モデルが構造化出力のシナリオで返す JSON は、パースできない場合があります:出力が max_tokens によって切り捨てられている、末尾カンマが付いている、内容が Markdown コードブロックに包まれている、といったケースです。アプリケーション側では通常、このためにリトライや手動修復のロジックを書く必要があります。 構造化出力修復(Structured Output Repair)は Key レベルの機能で、デフォルトでは無効です。有効にすると、構造化 JSON 出力を宣言した非ストリーミングリクエストにおいて、モデルが返した JSON にフォーマットエラーがある場合、AIHubMix ゲートウェイが返却前に自動でパース可能な正当な JSON に修復します。クライアント側のコードを変更する必要はありません。
このスイッチはデフォルトで無効です。有効化していない場合、すべての応答はそのまま返却されます。スイッチは Key ごとに個別に設定でき、有効化すると即座に反映されます。

Key 管理ページで設定する

Key を作成または編集し、「構造化出力修復」(Structured Output Repair)スイッチを有効にします。
AIHubMix の Key 編集パネルで構造化出力修復スイッチを有効にする

1. 有効になる条件

修復は以下の条件がすべて満たされたときにのみ発生します:
  1. リクエストに使用する Key で「構造化出力修復」が有効になっている。
  2. リクエストが非ストリーミングである(stream: true を設定していない)。
  3. リクエストが構造化 JSON 出力を宣言している(各プロトコルの宣言フィールドは下表を参照)。
  4. モデルが返したテキスト内容が JSON としてパースできない。
プロトコルエンドポイント構造化出力の宣言フィールド
Chat Completions/v1/chat/completionsresponse_format.typejson_object または json_schema
Responses/v1/responsestext.format.typejson_schema または json_object
Claude Messages/v1/messagesoutput_config.format.typejson_schema
Gemini/gemini/v1beta/models/{model}:generateContentgenerationConfig.responseMimeTypeapplication/json、または responseSchema が設定されている
内容そのものが正当な JSON である場合は、一切変更せずそのまま返却します。

2. 修復できるフォーマットエラー

出力の切り捨てにより括弧 / 引用符が閉じていない(例:finish_reasonlength):
修復前
{"items": [{"name": "Widget", "price": 9.99}, {"name": "Gad
修復後
{"items": [{"name": "Widget", "price": 9.99}, {"name": "Gad"}]}
Markdown コードブロックによる包囲
修復前
```json
{"status": "ok", "count": 3}
```
修復後
{"status": "ok", "count": 3}
末尾カンマ
修復前
{"a": 1, "b": 2,}
修復後
{"a": 1, "b": 2}
シングルクォート
修復前
{'name': 'Widget'}
修復後
{"name": "Widget"}
キー名が引用符で囲まれていない
修復前
{name: "Widget", price: 9.99}
修復後
{"name": "Widget", "price": 9.99}
テキストと JSON の混在(JSON の前後に説明テキストが付いている):
修復前
Here is the JSON you requested: {"name": "Widget", "price": 9.99}
修復後
{"name": "Widget", "price": 9.99}
修復は保守的な戦略を採用しています:
  • 修復は JSON の構文の補完または正規化のみを行い、数値と文字列の内容は原文のまま維持され、精度の損失や書き換えは発生しません
  • 修復結果は正当な JSON オブジェクトまたは配列でなければならず、かつ原文との差異が妥当な範囲内である必要があります。いずれかの条件が満たされない場合は修復を諦め、元の内容をそのまま返却します。

3. 応答が修復されたかどうかの判別方法

修復が発生した場合、プログラムから読み取れる / 目視で確認できる 2 つのシグナルがあります:
  1. 応答ヘッダー X-JSON-Repaired: true(修復が発生していない場合、この応答ヘッダーはありません)。
  2. 呼び出しログの備考呼び出し記録ページの該当リクエストの備考列に This request gateway automatically corrected the JSON format issue in the model output. が表示されます。
Token 使用量と課金はモデルの元の出力に基づいて計算され、修復によって課金結果が変わることはありません。

4. 完全な例

商品情報の生成を例に、リクエストは json_schema で構造化出力を宣言します。スイッチを有効にすると、モデルの出力に上記のフォーマットエラーがあっても、取得した content はそのままパースできます:
import json
import os
import requests

response = requests.post(
    "https://aihubmix.com/v1/chat/completions",
    headers={
        "Authorization": f"Bearer {os.environ['AIHUBMIX_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={
        "model": "gpt-5.2",
        "messages": [
            {"role": "user", "content": "Generate a product listing for a wireless keyboard."}
        ],
        "response_format": {
            "type": "json_schema",
            "json_schema": {
                "name": "product",
                "schema": {
                    "type": "object",
                    "properties": {
                        "name": {"type": "string"},
                        "price": {"type": "number"},
                        "description": {"type": "string"},
                    },
                    "required": ["name", "price"],
                    "additionalProperties": False,
                },
            },
        },
    },
)

repaired = response.headers.get("X-JSON-Repaired") == "true"
product = json.loads(response.json()["choices"][0]["message"]["content"])
print(product, "repaired:", repaired)
const response = await fetch("https://aihubmix.com/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AIHUBMIX_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "gpt-5.2",
    messages: [
      { role: "user", content: "Generate a product listing for a wireless keyboard." },
    ],
    response_format: {
      type: "json_schema",
      json_schema: {
        name: "product",
        schema: {
          type: "object",
          properties: {
            name: { type: "string" },
            price: { type: "number" },
            description: { type: "string" },
          },
          required: ["name", "price"],
          additionalProperties: false,
        },
      },
    },
  }),
});

const repaired = response.headers.get("X-JSON-Repaired") === "true";
const data = await response.json();
const product = JSON.parse(data.choices[0].message.content);
console.log(product, "repaired:", repaired);
curl -sD - https://aihubmix.com/v1/chat/completions \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.2",
    "messages": [
      {"role": "user", "content": "Generate a product listing for a wireless keyboard."}
    ],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "product",
        "schema": {
          "type": "object",
          "properties": {
            "name": {"type": "string"},
            "price": {"type": "number"},
            "description": {"type": "string"}
          },
          "required": ["name", "price"],
          "additionalProperties": false
        }
      }
    }
  }'
修復を実際に観察してみたい場合は、max_tokens を小さい値(例:80)に設定して出力を切り捨てさせます:応答の finish_reasonlength となり、content は修復後の正当な JSON になり、応答ヘッダーに X-JSON-Repaired: true が付与されます。

5. 制限事項と注意点

ストリーミングリクエスト(stream: true)は修復を行わず、そのまま転送します。修復機能が必要な場合は非ストリーミングリクエストを使用してください。
修復は内容が JSON としてパースできることを保証しますが、切り捨てによって失われたデータは復元できません。finish_reason / stop_reason も併せて確認し、出力が切り捨てられている場合は必要に応じて max_tokens を増やしてリトライすることをおすすめします。
  • 構文の修復:フィールド名やフィールドの型があなたの schema に適合しているかどうかは、依然としてアプリケーション側での検証が必要です。
  • ツール呼び出しパラメータは修復の対象外tool_calls / function_call のパラメータ JSON は修復しません。ツールパラメータは実行前に常にアプリケーション側で検証してください。
  • 複数テキストブロックの出力は修復しない:モデルの出力が複数のテキストブロックを含む場合(例:Gemini が複数の parts を返す場合)はそのまま返却します。
  • 推論内容は影響を受けないreasoning_content、Gemini の thought 部分などの推論テキストは修復に関与しません。

よくある質問 FAQ

修復によって返却内容の数値やテキストが変わりますか? いいえ。修復は JSON の構文の補完または正規化(閉じ括弧の補完、末尾カンマの除去、引用符の正規化、コードブロックマークの剥離)のみを行い、数値と文字列の内容はモデル出力の原文のまま維持されます。 スイッチを有効にすると、構造化出力を宣言していない通常のリクエストに影響しますか? いいえ。response_format などの構造化出力フィールドを宣言していないリクエスト、およびすべてのストリーミングリクエストの応答は、いずれもそのまま返却されます。 修復によって追加課金が発生したり、token 使用量が変わったりしますか? いいえ。Token 使用量と課金はモデルの元の出力に基づいて計算され、修復の過程で追加費用は発生しません。 修復後の JSON は必ず私が定義した schema に適合しますか? 修復は内容が JSON としてパースできることを保証しますが、フィールド名やフィールドの型が schema に適合しているかどうかはモデル出力自体に依存します。アプリケーション側で引き続き schema 検証を残しておくことをおすすめします。