メインコンテンツへスキップ
構造化出力は、モデルが定義したスキーマに一致する JSON オブジェクトを返すよう強制します。これにより、非構造化のモデル出力を解析、検証、または再試行する必要がなくなります。 ARouter は 2 つの構造化出力モードをサポートしています:
モード説明
json_object有効な JSON を保証します;スキーマは強制しません
json_schema正確なスキーマに一致する JSON を保証します

構造化出力の使用

リクエストボディに response_format を渡します:

JSON Object モード

{
  "model": "openai/gpt-5.4",
  "messages": [
    {
      "role": "user",
      "content": "Return information about the planet Mars as JSON"
    }
  ],
  "response_format": { "type": "json_object" }
}
モデルは有効な JSON を返しますが、スキーマは強制されません:
{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "{\"name\":\"Mars\",\"diameter_km\":6779,\"moons\":2,\"habitable\":false}"
      }
    }
  ]
}

JSON Schema モード

厳格なスキーマを強制するには json_schema を使用します:
{
  "model": "openai/gpt-5.4",
  "messages": [
    {
      "role": "system",
      "content": "You are a data extraction assistant."
    },
    {
      "role": "user",
      "content": "Extract the planet information: Mars is a terrestrial planet with 2 moons and a diameter of 6779 km."
    }
  ],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "planet_info",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "diameter_km": { "type": "number" },
          "moons": { "type": "integer" },
          "habitable": { "type": "boolean" }
        },
        "required": ["name", "diameter_km", "moons", "habitable"],
        "additionalProperties": false
      }
    }
  }
}
レスポンス:
{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "{\"name\":\"Mars\",\"diameter_km\":6779,\"moons\":2,\"habitable\":false}"
      },
      "finish_reason": "stop"
    }
  ]
}

完全な例

import json
from openai import OpenAI
from pydantic import BaseModel

client = OpenAI(
    base_url="https://api.arouter.ai/v1",
    api_key="lr_live_xxxx",
)

# Pydantic を使ってスキーマを定義
class PlanetInfo(BaseModel):
    name: str
    diameter_km: float
    moons: int
    habitable: bool

# OpenAI の parse() メソッドを使用(推奨)
response = client.beta.chat.completions.parse(
    model="openai/gpt-5.4",
    messages=[
        {"role": "system", "content": "You are a data extraction assistant."},
        {"role": "user", "content": "Tell me about Mars."},
    ],
    response_format=PlanetInfo,
)

planet = response.choices[0].message.parsed
print(planet.name)        # "Mars"
print(planet.moons)       # 2
print(planet.diameter_km) # 6779.0

# または response_format dict を手動で使用
response = client.chat.completions.create(
    model="openai/gpt-5.4",
    messages=[
        {"role": "user", "content": "Tell me about Mars as JSON."},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "planet_info",
            "strict": True,
            "schema": PlanetInfo.model_json_schema(),
        },
    },
)
data = json.loads(response.choices[0].message.content)
planet = PlanetInfo(**data)

モデルサポート

strict: truejson_schema モードをサポートするモデル:
  • openai/gpt-5.4, openai/gpt-5.4-pro, openai/o3, openai/o4-mini
  • anthropic/claude-sonnet-4.6, anthropic/claude-opus-4.5
  • google/gemini-2.5-flash, google/gemini-2.5-pro
json_object モード(スキーマ強制なし)はより広くサポートされています。最新の機能情報は GET /v1/models を確認してください。

構造化出力のストリーミング

構造化出力はストリーミングに対応しています。JSON コンテンツは段階的に配信され、クライアント側で組み立てます:
const stream = await client.chat.completions.create({
  model: "openai/gpt-5.4",
  messages: [{ role: "user", content: "Tell me about Mars." }],
  response_format: {
    type: "json_schema",
    json_schema: {
      name: "planet_info",
      strict: true,
      schema: { /* ... */ },
    },
  },
  stream: true,
});

let jsonBuffer = "";
for await (const chunk of stream) {
  const content = chunk.choices[0]?.delta?.content;
  if (content) jsonBuffer += content;
}

const data = JSON.parse(jsonBuffer);

ベストプラクティス

  1. strict: true を使用 — これによりスキーマ準拠が保証されます。指定しない場合、モデルはスキーマに完全に一致しない有効な JSON を返す可能性があります。
  2. additionalProperties: false を設定 — 厳格モードに必須です。モデルが余分なキーを追加するのを防ぎます。
  3. すべての必須フィールドを明示的にリスト化 — 厳格モードでは、properties のすべてのフィールドを required にも含めてください。
  4. システムプロンプトを含める — データ抽出や構造化出力アシスタントとしての役割をモデルに伝えることで信頼性が向上します。

エラー処理

モデルがスキーマに一致する有効な JSON を生成できない場合(例:プロンプトがスキーマと根本的に矛盾する場合)、レスポンスの finish_reason"length" または "content_filter" になります。コンテンツを解析する前に必ず finish_reason を確認してください。
response = client.chat.completions.create(...)

choice = response.choices[0]
if choice.finish_reason != "stop":
    raise ValueError(f"Unexpected finish reason: {choice.finish_reason}")

data = json.loads(choice.message.content)