跳轉到主要內容

功能概述

結構化輸出(Structured Outputs)讓模型的回覆嚴格遵循你定義的 JSON Schema,確保回傳值可以直接被程式解析,無需正則或後處理。 與在 prompt 中要求模型「請回傳 JSON」不同,結構化輸出基於受約束解碼(Constrained Decoding):上游將 JSON Schema 編譯為語法規則,在推理過程中逐 token 約束生成,模型不可能產出違反 Schema 的內容。 典型場景:
  • 從非結構化文字中擷取實體和欄位
  • 分類 / 打標籤 / 情感分析
  • 多步推理中間結果的標準化傳遞
  • Agent 工具呼叫參數的強型別約束

各協議參數對照

三種協議的參數名不同,但底層機制一致:模型輸出嚴格匹配你提供的 JSON Schema。
協議參數支援模型
OpenAI Chat /v1/chat/completionsresponse_format.type: "json_schema"Claude 4.5+、GPT-4o / GPT-5 系列、Gemini 系列
Anthropic Messages /v1/messagesoutput_config.format.type: "json_schema"Claude 4.5+(直連 / Vertex);Bedrock 僅 4.5–4.6
OpenAI Responses /v1/responsestext.format.type: "json_schema"隨上游模型能力

AWS Bedrock 限制

AWS Bedrock 上 Claude 4.7 及以上版本使用 Mantle 推理路徑,該路徑目前不支援 output_config.format。閘道會自動為這些模型剝離 format 欄位並在回應標頭中標記降級(見下方降級機制),請求不會因此報錯。

快速開始

OpenAI 協議(推薦)

適用於所有支援結構化輸出的模型,跨廠商通用。
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": "台北市信義區"}

使用其他模型(GLM-5.2 示例)

同一套 OpenAI 協議參數適用於所有支援結構化輸出的模型,切換 model 即可。
Python
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
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)

Schema 編寫要點

必需欄位

所有 object 類型必須顯式宣告 additionalProperties: false,否則部分上游會拒絕請求。
{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "score": { "type": "number" }
  },
  "required": ["name", "score"],
  "additionalProperties": false
}

巢狀物件

巢狀的 object 同樣需要 additionalProperties: false
{
  "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)支援不支援(閘道自動清理)
使用 OpenAI 協議呼叫 Claude 模型時,閘道會自動轉換 Schema 格式並清理不相容的關鍵字,無需手動適配。

自動降級機制

閘道預設為所有請求開啟結構化輸出的自動降級保護。當模型或平台不支援時,閘道不會回傳錯誤,而是自動剝離 Schema 約束並在回應標頭中標記降級原因。你的請求仍然會得到正常的模型回覆,只是輸出不受 Schema 強制約束。 這意味著你可以放心地在用戶端統一啟用結構化輸出,而無需針對每個模型做相容判斷:
  • 多模型切換無憂:同一套程式碼在 Claude、GPT、Gemini、GLM 之間切換模型時,即使目標模型不支援結構化輸出,請求也不會報錯
  • Fallback 路由透明:當主渠道不可用觸發 Fallback 路由到備用渠道時,即使備用渠道的模型版本不支援結構化輸出,請求仍然正常完成
  • 用戶端邏輯簡化:不需要維護一份「哪些模型支援結構化輸出」的清單,閘道已自動處理;用戶端只需檢查回應標頭決定是否需要額外解析

回應標頭

X-Structured-Output-Degraded: <reason>
reason含義
model_unsupported該模型(或該模型在當前平台上)不支援結構化輸出
json_object_unsupported_on_anthropicjson_object 模式無法轉換為 Anthropic 格式
json_schema_missing_schema指定了 json_schema 類型但缺少 schema 欄位
schema_keywords_strippedSchema 中的部分約束關鍵字被清理(如 minimummaxLength

偵測範例

Python
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不支援
json_object 模式不支援轉換到 Claude 原生協議。如果你透過 OpenAI 協議向 Claude 傳送 response_format: {"type": "json_object"},回應標頭會標記 json_object_unsupported_on_anthropic 降級。建議直接使用 json_schema 類型。

常見問題

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 及以上
可透過模型列表頁查看各模型的能力標籤。
AWS Bedrock 上 Claude 4.7+ 使用了新的 Mantle 推理路徑,該路徑目前不接受 output_config.format 參數。閘道會自動處理:剝離 format 並正常回傳回應,同時標記降級標頭 X-Structured-Output-Degraded: model_unsupported。Claude 4.5–4.6 在 Bedrock 上完全支援。
會。當透過 OpenAI 協議呼叫 Claude 模型時,閘道自動:
  1. response_format 轉換為 output_config.format
  2. 移除 Anthropic 不支援的 Schema 關鍵字(minimummaxLength 等)
  3. 如果有關鍵字被清理,回應標頭標記 schema_keywords_stripped
反向(Claude 協議呼叫 OpenAI 模型)同樣自動轉換。
可以。output_config 中的 format(結構化輸出)和 reasoning 中的 effort(思考強度)是獨立參數,可以同時設定:
{
  "output_config": {
    "format": {
      "type": "json_schema",
      "schema": { ... }
    }
  },
  "reasoning": {
    "effort": "high"
  }
}
大多數 API 聚合平台在模型不支援結構化輸出時會直接回傳錯誤。AIHubMix 採用優雅降級策略:自動剝離不相容的參數,正常回傳模型回應,並透過 X-Structured-Output-Degraded 回應標頭告知用戶端降級原因。你的應用不會因此中斷。