> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aihubmix.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 構造化出力 Structured Outputs

> JSON Schema によるモデル出力形式の制約（Structured Outputs）。OpenAI、Anthropic Claude、Gemini などのモデルで response_format および output_config.format をサポートし、自動デグレードとクロスプロトコル変換に対応しています。

## 機能概要

構造化出力（Structured Outputs）を使用すると、モデルの応答が定義した JSON Schema に厳密に従うようになり、正規表現や後処理なしでプログラムから直接パースできる戻り値が保証されます。

プロンプトでモデルに「JSONで返してください」と依頼する方法とは異なり、構造化出力は**制約付きデコーディング（Constrained Decoding）**に基づいています。上流プロバイダが JSON Schema を文法規則にコンパイルし、推論過程でトークンごとに生成を制約するため、モデルが Schema に違反するコンテンツを出力することは**不可能**です。

典型的なユースケース：

* 非構造化テキストからのエンティティ・フィールド抽出
* 分類 / ラベリング / 感情分析
* マルチステップ推論における中間結果の標準化された受け渡し
* Agent ツール呼び出しパラメータの厳密な型制約

## 各プロトコルのパラメータ対照表

<Note>
  3つのプロトコルでパラメータ名は異なりますが、基本的なメカニズムは同じです：モデルの出力が提供された JSON Schema に厳密に一致します。
</Note>

| プロトコル                              | パラメータ                                      | 対応モデル                                           |
| ---------------------------------- | ------------------------------------------ | ----------------------------------------------- |
| OpenAI Chat `/v1/chat/completions` | `response_format.type: "json_schema"`      | Claude 4.5+、GPT-4o / GPT-5 シリーズ、Gemini シリーズ     |
| Anthropic Messages `/v1/messages`  | `output_config.format.type: "json_schema"` | Claude 4.5+（直接接続 / Vertex）；Bedrock は 4.5～4.6 のみ |
| OpenAI Responses `/v1/responses`   | `text.format.type: "json_schema"`          | 上流モデルの対応状況に準ずる                                  |

### AWS Bedrock の制限事項

AWS Bedrock 上の Claude 4.7 以降のバージョンは Mantle 推論パスを使用しており、このパスは現在 `output_config.format` をサポートしていません。ゲートウェイはこれらのモデルに対して自動的に `format` フィールドを除去し、レスポンスヘッダーにデグレードを記録します（下記の[デグレードメカニズム](#自動デグレードメカニズム)を参照）。リクエストはこれによりエラーになることはありません。

***

## クイックスタート

### OpenAI プロトコル（推奨）

構造化出力に対応するすべてのモデルに適用でき、プロバイダ横断で共通して使用できます。

<CodeGroup>
  ```python Python theme={null}
  from openai import OpenAI

  client = OpenAI(
      api_key="<AIHUBMIX_API_KEY>",
      base_url="https://aihubmix.com/v1",
  )

  response = client.chat.completions.create(
      model="claude-sonnet-5",
      messages=[
          {"role": "user", "content": "以下の情報を抽出してください：田中太郎、28歳、東京都渋谷区"}
      ],
      response_format={
          "type": "json_schema",
          "json_schema": {
              "name": "person_info",
              "strict": True,
              "schema": {
                  "type": "object",
                  "properties": {
                      "name": {"type": "string"},
                      "age": {"type": "integer"},
                      "city": {"type": "string"}
                  },
                  "required": ["name", "age", "city"],
                  "additionalProperties": False
              }
          }
      }
  )

  import json
  data = json.loads(response.choices[0].message.content)
  print(data)
  # {"name": "田中太郎", "age": 28, "city": "東京都渋谷区"}
  ```

  ```typescript Node.js theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
    apiKey: "<AIHUBMIX_API_KEY>",
    baseURL: "https://aihubmix.com/v1",
  });

  const response = await client.chat.completions.create({
    model: "claude-sonnet-5",
    messages: [
      { role: "user", content: "以下の情報を抽出してください：田中太郎、28歳、東京都渋谷区" },
    ],
    response_format: {
      type: "json_schema",
      json_schema: {
        name: "person_info",
        strict: true,
        schema: {
          type: "object",
          properties: {
            name: { type: "string" },
            age: { type: "integer" },
            city: { type: "string" },
          },
          required: ["name", "age", "city"],
          additionalProperties: false,
        },
      },
    },
  });

  const data = JSON.parse(response.choices[0].message.content);
  console.log(data);
  ```

  ```bash cURL theme={null}
  curl https://aihubmix.com/v1/chat/completions \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer <AIHUBMIX_API_KEY>" \
    -d '{
      "model": "claude-sonnet-5",
      "messages": [
        {"role": "user", "content": "以下の情報を抽出してください：田中太郎、28歳、東京都渋谷区"}
      ],
      "response_format": {
        "type": "json_schema",
        "json_schema": {
          "name": "person_info",
          "strict": true,
          "schema": {
            "type": "object",
            "properties": {
              "name": {"type": "string"},
              "age": {"type": "integer"},
              "city": {"type": "string"}
            },
            "required": ["name", "age", "city"],
            "additionalProperties": false
          }
        }
      }
    }'
  ```
</CodeGroup>

### 他のモデルの使用（GLM-5.2 の例）

同じ OpenAI プロトコルのパラメータが構造化出力に対応するすべてのモデルに適用でき、`model` を切り替えるだけで使用できます。

```python Python theme={null}
from openai import OpenAI

client = OpenAI(
    api_key="<AIHUBMIX_API_KEY>",
    base_url="https://aihubmix.com/v1",
)

response = client.chat.completions.create(
    model="glm-5.2",
    messages=[
        {"role": "user", "content": "以下の情報を抽出してください：田中太郎、28歳、東京都渋谷区"}
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "person_info",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "age": {"type": "integer"},
                    "city": {"type": "string"}
                },
                "required": ["name", "age", "city"],
                "additionalProperties": False
            }
        }
    }
)

import json
data = json.loads(response.choices[0].message.content)
print(data)
# {"name": "田中太郎", "age": 28, "city": "東京都渋谷区"}
```

### Claude ネイティブプロトコル

Anthropic SDK を使用して直接呼び出します。パラメータは `output_config.format` です。

<CodeGroup>
  ```python Python theme={null}
  import anthropic

  client = anthropic.Anthropic(
      api_key="<AIHUBMIX_API_KEY>",
      base_url="https://aihubmix.com",
  )

  response = client.messages.create(
      model="claude-sonnet-5",
      max_tokens=1024,
      messages=[
          {"role": "user", "content": "以下の情報を抽出してください：田中太郎、28歳、東京都渋谷区"}
      ],
      output_config={
          "format": {
              "type": "json_schema",
              "schema": {
                  "type": "object",
                  "properties": {
                      "name": {"type": "string"},
                      "age": {"type": "integer"},
                      "city": {"type": "string"}
                  },
                  "required": ["name", "age", "city"],
                  "additionalProperties": False
              }
          }
      }
  )

  import json
  data = json.loads(response.content[0].text)
  print(data)
  ```

  ```bash cURL theme={null}
  curl https://aihubmix.com/v1/messages \
    -H "Content-Type: application/json" \
    -H "x-api-key: <AIHUBMIX_API_KEY>" \
    -H "anthropic-version: 2023-06-01" \
    -d '{
      "model": "claude-sonnet-5",
      "max_tokens": 1024,
      "messages": [
        {"role": "user", "content": "以下の情報を抽出してください：田中太郎、28歳、東京都渋谷区"}
      ],
      "output_config": {
        "format": {
          "type": "json_schema",
          "schema": {
            "type": "object",
            "properties": {
              "name": {"type": "string"},
              "age": {"type": "integer"},
              "city": {"type": "string"}
            },
            "required": ["name", "age", "city"],
            "additionalProperties": false
          }
        }
      }
    }'
  ```
</CodeGroup>

***

## Schema の記述ポイント

### 必須フィールド

すべての `object` 型には `additionalProperties: false` を明示的に宣言する必要があります。これがない場合、一部の上流プロバイダがリクエストを拒否します。

```json theme={null}
{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "score": { "type": "number" }
  },
  "required": ["name", "score"],
  "additionalProperties": false
}
```

### ネストされたオブジェクト

ネストされた `object` にも同様に `additionalProperties: false` が必要です：

```json theme={null}
{
  "type": "object",
  "properties": {
    "user": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "email": { "type": "string" }
      },
      "required": ["name", "email"],
      "additionalProperties": false
    }
  },
  "required": ["user"],
  "additionalProperties": false
}
```

### クロスプロトコル間の Schema 差異

| 特性                               | OpenAI プロトコル | Anthropic プロトコル                 |
| -------------------------------- | ------------ | ------------------------------- |
| `name` フィールド                     | 必須           | 非対応（ゲートウェイがクロスプロトコル呼び出し時に自動処理）  |
| `strict` フィールド                   | 任意、`true` 推奨 | 非対応                             |
| 数値制約 (`minimum`, `maximum` 等)    | 対応           | 非対応（ゲートウェイが自動クリーニング、リクエストに影響なし） |
| 文字列制約 (`minLength`, `maxLength`) | 対応           | 非対応（ゲートウェイが自動クリーニング）            |

<Tip>
  OpenAI プロトコル経由で Claude モデルを呼び出す場合、ゲートウェイが Schema フォーマットを自動変換し、互換性のないキーワードをクリーニングするため、手動での対応は不要です。
</Tip>

***

## 自動デグレードメカニズム

ゲートウェイはデフォルトですべてのリクエストに対して構造化出力の自動デグレード保護を有効にしています。モデルまたはプラットフォームがサポートしていない場合、ゲートウェイは**エラーを返さず**、自動的に Schema 制約を除去し、レスポンスヘッダーにデグレードの理由を記録します。リクエストは引き続き正常なモデル応答を受け取りますが、出力は Schema による強制制約を受けません。

これにより、クライアント側で構造化出力を統一的に有効化でき、モデルごとの互換性判断を行う必要がなくなります：

* **マルチモデル切り替えが安心**：同一のコードで Claude、GPT、Gemini、GLM 間でモデルを切り替える際、対象モデルが構造化出力をサポートしていなくてもリクエストはエラーになりません
* **フォールバックルーティングが透過的**：メインチャネルが利用不可でバックアップチャネルにフォールバックルーティングされた場合、バックアップチャネルのモデルバージョンが構造化出力をサポートしていなくても、リクエストは正常に完了します
* **クライアントロジックの簡素化**：「どのモデルが構造化出力をサポートしているか」のリストを管理する必要がなく、ゲートウェイが自動処理済み。クライアントはレスポンスヘッダーを確認して追加のパース処理が必要かどうかを判断するだけです

### レスポンスヘッダー

```
X-Structured-Output-Degraded: <reason>
```

| reason                                 | 意味                                                       |
| -------------------------------------- | -------------------------------------------------------- |
| `model_unsupported`                    | 当該モデル（または当該モデルの現在のプラットフォーム上）が構造化出力をサポートしていません            |
| `json_object_unsupported_on_anthropic` | `json_object` モードは Anthropic フォーマットに変換できません              |
| `json_schema_missing_schema`           | `json_schema` タイプが指定されましたが `schema` フィールドがありません          |
| `schema_keywords_stripped`             | Schema 内の一部の制約キーワードがクリーニングされました（例：`minimum`、`maxLength`） |

### 検出の例

```python Python theme={null}
import httpx

response = httpx.post(
    "https://aihubmix.com/v1/chat/completions",
    headers={
        "Authorization": "Bearer <AIHUBMIX_API_KEY>",
        "Content-Type": "application/json",
    },
    json={
        "model": "claude-sonnet-5",
        "messages": [{"role": "user", "content": "情報を抽出してください：田中太郎、28歳"}],
        "response_format": {
            "type": "json_schema",
            "json_schema": {
                "name": "person",
                "strict": True,
                "schema": {
                    "type": "object",
                    "properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
                    "required": ["name", "age"],
                    "additionalProperties": False,
                }
            }
        }
    }
)

# デグレードが発生したか確認（例：リクエストが非対応の Bedrock チャネルにルーティングされた場合）
degraded = response.headers.get("X-Structured-Output-Degraded")
if degraded:
    print(f"構造化出力がデグレードされました：{degraded}")
    # この場合もモデルの応答は正常ですが、出力は Schema による強制制約を受けません
else:
    import json
    data = json.loads(response.json()["choices"][0]["message"]["content"])
    print(data)  # {"name": "田中太郎", "age": 28}
```

***

## `json_object` モードとの違い

|           | `json_schema`（構造化出力）           | `json_object`      |
| --------- | ------------------------------ | ------------------ |
| 出力保証      | 指定された Schema に厳密に一致            | 有効な JSON であることのみ保証 |
| フィールド制御   | フィールド名、型、必須かどうかがすべて制約される       | 制約なし               |
| 対応プロトコル   | OpenAI / Anthropic / Responses | OpenAI 互換プロトコルのみ   |
| Claude 対応 | `output_config.format` 経由      | 非対応                |

<Warning>
  `json_object` モードは Claude ネイティブプロトコルへの変換をサポートしていません。OpenAI プロトコル経由で Claude に `response_format: {"type": "json_object"}` を送信した場合、レスポンスヘッダーに `json_object_unsupported_on_anthropic` のデグレードが記録されます。`json_schema` タイプの使用を推奨します。
</Warning>

***

## よくある質問

<AccordionGroup>
  <Accordion title="どのモデルが Structured Outputs に対応していますか？">
    **Claude シリーズ**（Anthropic API の `output_config.format` 経由）：

    * Opus / Sonnet / Haiku 4.5 以降
    * Fable / Mythos 5 以降
    * Bedrock プラットフォームは 4.5～4.6 のみ対応；Vertex AI は直接接続と同一

    **OpenAI シリーズ**（`response_format` 経由）：

    * GPT-4o 以降、GPT-5 シリーズ

    **Gemini シリーズ**（`responseSchema` 経由）：

    * Gemini 2.5 以降

    各モデルの対応機能タグは[モデル一覧ページ](https://aihubmix.com/models)でご確認いただけます。
  </Accordion>

  <Accordion title="Bedrock 上の一部の Claude モデルが構造化出力に対応していないのはなぜですか？">
    AWS Bedrock 上の Claude 4.7 以降は新しい Mantle 推論パスを使用しており、このパスは現在 `output_config.format` パラメータを受け付けません。ゲートウェイが自動的に処理します：format を除去して正常にレスポンスを返し、同時にデグレードヘッダー `X-Structured-Output-Degraded: model_unsupported` を記録します。Claude 4.5～4.6 は Bedrock 上で完全にサポートされています。
  </Accordion>

  <Accordion title="クロスプロトコル呼び出し時に JSON Schema は変更されますか？">
    はい。OpenAI プロトコル経由で Claude モデルを呼び出す場合、ゲートウェイが自動的に以下を実行します：

    1. `response_format` を `output_config.format` に変換
    2. Anthropic が非対応の Schema キーワード（`minimum`、`maxLength` 等）を除去
    3. キーワードがクリーニングされた場合、レスポンスヘッダーに `schema_keywords_stripped` を記録

    逆方向（Claude プロトコルから OpenAI モデルの呼び出し）も同様に自動変換されます。
  </Accordion>

  <Accordion title="Structured Outputs と Extended Thinking は同時に使用できますか？">
    はい。`output_config` 内の `format`（構造化出力）と `reasoning` 内の `effort`（思考強度）は独立したパラメータであり、同時に設定できます：

    ```json theme={null}
    {
      "output_config": {
        "format": {
          "type": "json_schema",
          "schema": { ... }
        }
      },
      "reasoning": {
        "effort": "high"
      }
    }
    ```
  </Accordion>

  <Accordion title="OpenRouter などの集約プラットフォームと比較して、デグレードメカニズムにはどのような違いがありますか？">
    多くの API 集約プラットフォームは、モデルが構造化出力をサポートしていない場合にエラーを直接返します。AIHubMix は**グレースフルデグレード**戦略を採用しています：互換性のないパラメータを自動的に除去し、モデルのレスポンスを正常に返した上で、`X-Structured-Output-Degraded` レスポンスヘッダーでクライアントにデグレードの理由を通知します。これにより、アプリケーションが中断されることはありません。
  </Accordion>
</AccordionGroup>
