Documentation Index
Fetch the complete documentation index at: https://docs.arouter.ai/llms.txt
Use this file to discover all available pages before exploring further.
構造化出力は、モデルが定義したスキーマに一致する 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"
}
]
}
完全な例
Python (OpenAI)
Node.js (OpenAI)
cURL
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)
import OpenAI from "openai";
import { zodResponseFormat } from "openai/helpers/zod";
import { z } from "zod";
const client = new OpenAI({
baseURL: "https://api.arouter.ai/v1",
apiKey: "lr_live_xxxx",
});
// Zod でスキーマを定義
const PlanetInfo = z.object({
name: z.string(),
diameter_km: z.number(),
moons: z.number().int(),
habitable: z.boolean(),
});
// Zod と parse() を使用(推奨)
const response = await 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: zodResponseFormat(PlanetInfo, "planet_info"),
});
const planet = response.choices[0].message.parsed;
console.log(planet?.name); // "Mars"
console.log(planet?.moons); // 2
console.log(planet?.diameter_km); // 6779
// または response_format を直接使用
const rawResponse = 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: {
type: "object",
properties: {
name: { type: "string" },
diameter_km: { type: "number" },
moons: { type: "integer" },
habitable: { type: "boolean" },
},
required: ["name", "diameter_km", "moons", "habitable"],
additionalProperties: false,
},
},
},
});
const data = JSON.parse(rawResponse.choices[0].message.content ?? "{}");
curl https://api.arouter.ai/v1/chat/completions \
-H "Authorization: Bearer lr_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"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": {
"type": "object",
"properties": {
"name": {"type": "string"},
"diameter_km": {"type": "number"},
"moons": {"type": "integer"},
"habitable": {"type": "boolean"}
},
"required": ["name", "diameter_km", "moons", "habitable"],
"additionalProperties": false
}
}
}
}'
モデルサポート
strict: true の json_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);
ベストプラクティス
-
strict: true を使用 — これによりスキーマ準拠が保証されます。指定しない場合、モデルはスキーマに完全に一致しない有効な JSON を返す可能性があります。
-
additionalProperties: false を設定 — 厳格モードに必須です。モデルが余分なキーを追加するのを防ぎます。
-
すべての必須フィールドを明示的にリスト化 — 厳格モードでは、
properties のすべてのフィールドを required にも含めてください。
-
システムプロンプトを含める — データ抽出や構造化出力アシスタントとしての役割をモデルに伝えることで信頼性が向上します。
エラー処理
モデルがスキーマに一致する有効な 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)