Skip to main content
文本產生

結構化輸出

執行資訊抽取或結構化資料產生任務時,大模型可能返回多餘文本(如 ```json )導致下遊解析失敗。開啟結構化輸出可確保大模型輸出標準格式的 JSON 字串,使用 JSON Schema 模式還能精確控制輸出結構和類型,無需額外驗證或重試。

使用方式

結構化輸出支援JSON Object 與 JSON Schema兩種模式:
  • JSON Object 模式:確保輸出為標準格式的 JSON 字串,但不保證符合特定結構。使用方式:
    1. 設定response_format參數:在請求體中,將 response_format 參數設定為 {"type": "json_object"}
    2. 提示詞包含 JSON 關鍵詞:System Message 或 User Message 中需要包含 "JSON" 關鍵詞(不區分大小寫),否則會報錯:'messages' must contain the word 'json' in some form, to use 'response_format' of type 'json_object'.
  • JSON Schema 模式:確保輸出內容為指定的結構。使用方式:設定 response_format{"type": "json_schema", "json_schema": {..., "strict": true}}
    提示詞無需包含 JSON 關鍵詞。
功能對比:

特性

JSON Object 模式

JSON Schema 模式

輸出有效 JSON

嚴格遵循 Schema

支援模型

Qwen 大部分模型

僅支援部分模型

response_format 參數設定

{"type": "json_object"}

{"type": "json_schema", "json_schema": {..., "strict": true}}

提示詞要求

必須包含 "JSON"

建議明確說明

適用情境

靈活的 JSON 輸出

精確的結構驗證

支援的模型

  • JSON Object
  • JSON Schema
  • 千問
  • Kimi
  • GLM
  • DeepSeek
  • 文本產生模型
    • 千問Max:Qwen3.8-Max系列、Qwen3.7-Max系列
    • 千問Max(非思考模式):Qwen3.6-Max系列、Qwen3-Max系列、Qwen-Max系列
    • 千問Plus:Qwen3.7-Plus系列
    • 千問Plus(非思考模式):Qwen3.6-Plus系列、Qwen3.5-Plus系列、Qwen-Plus系列
    • 千問Flash:Qwen3.8-Flash系列、Qwen3.7-Flash系列
    • 千問Flash(非思考模式):Qwen3.6-Flash系列、Qwen3.5-Flash系列、Qwen-Flash系列
    • 千問Turbo(非思考模式):Qwen-Turbo系列
    • 千問Coder:Qwen3-Coder系列
    • 千問Long:Qwen-Long系列
    • Qwen3.8開源系列
    • Qwen3.6開源系列(非思考模式)
    • Qwen3.5開源系列(非思考模式)
    • Qwen3開源系列(非思考模式)
    • Qwen3-Coder開源系列
    • Qwen2.5開源系列(不含math與coder模型)
  • 多模態模型
    • 千問VL(非思考模式):Qwen3-VL-Plus系列、Qwen3-VL-Flash系列、Qwen-VL-Max系列(不包括最新版與快照版模型)、Qwen-VL-Plus系列(不包括最新版與快照版模型)
    • 千問Omni:Qwen3.5-Omni-Plus系列
    • Qwen3-VL 開源系列(非思考模式)
標註為"非思考模式"的模型,在思考模式下設定 response_format{"type": "json_object"} 不會報錯,但部分模型返回的內容可能不是嚴格的標準 JSON,如需穩定擷取標準 JSON,可參考"常見問題"中的處理方式。

快速開始

以從簡歷中抽取資訊為例,示範結構化輸出的基本用法。
JSON Object 模式不保證鍵名與欄位類型穩定,不同提示詞或不同次調用的返回結果可能存在差異。如需固定結構,請使用 JSON Schema 模式。
您需要已擷取與配置 API Key配置API Key到環境變數。如果通過OpenAI SDK或DashScope SDK進行調用,還需要安裝SDK。請將範例程式碼中的 DASHSCOPE_API_HOST 替換為擷取的 API Host。
  • OpenAI相容
  • DashScope
  • Python
  • Node.js
  • curl
from openai import OpenAI
import os

client = OpenAI(
    # 各地區的API Key不同;如果沒有配置環境變數,請用API Key將下行替換為:api_key="sk-xxx"
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 如果使用北京地區的模型,需要將base_url替換為:https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/compatible-mode/v1
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
)

completion = client.chat.completions.create(
    model="qwen3.8-max",
    messages=[
        {
            "role": "system",
            "content": [{"type": "text", "text": "請抽取使用者的姓名與年齡資訊,以JSON格式返回"}]
        },
        {
            "role": "user",
            "content": [{"type": "text", "text": "大家好,我叫劉五,今年34歲,郵箱是liuwu@example.com,平時喜歡打籃球和旅遊"}],
        },
    ],
    response_format={"type": "json_object"}
)

json_string = completion.choices[0].message.content
print(json_string)

返回結果

{
  "姓名": "劉五",
  "年齡": 34
}

圖片、視頻資料處理

多模態模型同樣支援對映像和視頻資料進行結構化輸出。通過JSON Mode,可以從視覺內容中提取結構化資料,例如票據欄位、映像中的目標位置或視頻中的事件資訊。
圖片、視頻檔案限制請參見 映像與視頻理解
  • OpenAI相容
  • DashScope
  • Python
  • Node.js
  • curl
import os
from openai import OpenAI

client = OpenAI(
    # 各地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 若使用北京地區的模型,需將base_url替換為:https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/compatible-mode/v1
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1"
)

completion = client.chat.completions.create(
    model="qwen3.8-max",
    messages=[
        {
            "role": "system",
            "content": [{"type": "text", "text": "You are a helpful assistant."}],
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "http://duguang-labelling.oss-cn-shanghai.aliyuncs.com/demo_ocr/receipt_zh_demo.jpg"
                    },
                },
                {"type": "text", "text": "提取圖中ticket(數群組類型,包括 travel_date、trains、seat_num、arrival_site、price)和 invoice 的資訊(數群組類型,包括 invoice_code 和 invoice_number ),請輸出包含 ticket 和 invoice 數組的JSON"},
            ],
        },
    ],
    response_format={"type": "json_object"}
)
json_string = completion.choices[0].message.content
print(json_string)

返回結果

{
  "ticket": [
    {
      "travel_date": "2013-06-29",
      "trains": "流水",
      "seat_num": "371",
      "arrival_site": "開發區",
      "price": "8.00"
    }
  ],
  "invoice": [
    {
      "invoice_code": "221021325353",
      "invoice_number": "10283819"
    }
  ]
}

最佳化提示詞

模糊的提示詞(如”返回使用者資訊”)會導致輸出結構不可預期。為獲得可靠的結果,建議在提示詞中明確描述預期的 Schema:指定欄位名稱、類型、是否必填、格式要求(如日期格式),並提供樣本。
  • OpenAI相容
  • DashScope
  • Python
  • Node.js
from openai import OpenAI
import os
import json
import textwrap  # 用於處理多行字串的縮排,提高代碼可讀性

# 預定義樣本響應,用於向模型展示期望的輸出格式
# 樣本1:包含所有欄位的完整響應
example1_response = json.dumps(
    {
        "info": {"name": "張三", "age": "25歲", "email": "zhangsan@example.com"},
        "hobby": ["唱歌"]
    },
    ensure_ascii=False
)
# 樣本2:包含多個hobby的響應
example2_response = json.dumps(
    {
        "info": {"name": "李四", "age": "30歲", "email": "lisi@example.com"},
        "hobby": ["跳舞", "遊泳"]
    },
    ensure_ascii=False
)
# 樣本3:不包含hobby欄位的響應(hobby非必需)
example3_response = json.dumps(
    {
        "info": {"name": "趙六", "age": "28歲", "email": "zhaoliu@example.com"}
    },
    ensure_ascii=False
)
# 樣本4:不包含hobby欄位的響應
example4_response = json.dumps(
    {
        "info": {"name": "孫七", "age": "35歲", "email": "sunqi@example.com"}
    },
    ensure_ascii=False
)

# 初始化OpenAI用戶端,配置API密鑰和基礎URL
client = OpenAI(
    # 各地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 若使用北京地區的模型,需將url替換為:https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/compatible-mode/v1
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
)

# 使用dedent去除字串縮排,使多行字串在代碼中美觀,但運行時不包含額外空格
system_prompt = textwrap.dedent(f"""\
    請從使用者輸入中提取個人資訊並按照指定的JSON Schema格式輸出:

    【輸出格式要求】
    輸出必須嚴格遵循以下JSON結構:
    {{
      "info": {{
        "name": "字串類型,必需欄位,使用者姓名",
        "age": "字串類型,必需欄位,格式為'數字+歲',例如'25歲'",
        "email": "字串類型,必需欄位,標準郵箱格式,例如'user@example.com'"
      }},
      "hobby": ["字串數群組類型,非必需欄位,包含使用者的所有愛好,如未提及則完全不輸出此欄位"]
    }}

    【欄位擷取規則】
    1. name: 從文本中識別使用者姓名,必需提取
    2. age: 識別年齡資訊,轉換為"數字+歲"格式,必需提取
    3. email: 識別郵箱地址,保持原始格式,必需提取
    4. hobby: 識別使用者愛好,以字串數組形式輸出,如未提及愛好資訊則完全省略hobby欄位

    【參考樣本】
    樣本1(包含愛好):
    Q:我叫張三,今年25歲,郵箱是zhangsan@example.com,愛好是唱歌
    A:{example1_response}

    樣本2(包含多個愛好):
    Q:我叫李四,今年30歲,郵箱是lisi@example.com,平時喜歡跳舞和遊泳
    A:{example2_response}

    樣本3(不包含愛好):
    Q:我叫趙六,今年28歲,我的郵箱是zhaoliu@example.com
    A:{example3_response}

    樣本4(不包含愛好):
    Q:我是孫七,35歲,郵箱sunqi@example.com
    A:{example4_response}

    請嚴格按照上述格式和規則提取資訊並輸出JSON。如果使用者未提及愛好,則不要在輸出中包含hobby欄位。\
""")

# 調用大模型API進行資訊提取
completion = client.chat.completions.create(
    model="qwen3.8-max",
    messages=[
        {
            "role": "system",
            "content": system_prompt  # 使用最佳化後的system prompt
        },
        {
            "role": "user",
            "content": [{"type": "text", "text": "大家好,我叫劉五,今年34歲,郵箱是liuwu@example.com,平時喜歡打籃球和旅遊"}],
        },
    ],
    response_format={"type": "json_object"},  # 指定返回JSON格式,確保輸出結構化資料
)

# 提取並列印模型產生的JSON結果
json_string = completion.choices[0].message.content
print(json_string)

返回結果

{
  "info": {
    "name": "劉五",
    "age": "34歲",
    "email": "liuwu@example.com"
  },
  "hobby": ["打籃球", "旅遊"]
}

擷取指定格式的輸出

response_formattype設為json_object,可返回標準 JSON 字串,但內容結構可能不符合預期,適用於簡單情境。對於自動化解析、API 互操作等需要嚴格類型約束的複雜情境,可將 type 設定為 json_schema,強制大模型輸出嚴格符合指定格式的內容。response_format 格式與樣本如下:
{
  "type": "json_schema",
  "json_schema": {
    "name": "schema_name",       // Schema 的名稱
    "strict": true,              // 推薦設定為 true,嚴格遵守格式
    "schema": {
      "type": "object",
      "properties": {...},       // 定義欄位結構,見右側具體樣本
      "required": [...],         // 必要欄位列表
      "additionalProperties": false  // 推薦設定為 false,只輸出定義的欄位
    }
  }
}
上述樣本會強制模型輸出包含 nameage 兩個必要欄位,以及可選的 email 欄位的 JSON 對象。

使用方法

通過 OpenAI SDK 的 parse 方法,可直接傳入 Python Pydantic 類或 Node.js Zod 對象。SDK 會自動將其轉換為 JSON Schema,無需手動編寫複雜 JSON。DashScope SDK 需參考上文格式,手動構造 JSON Schema。
  • OpenAI 相容
  • DashScope
Python
from pydantic import BaseModel, Field
from openai import OpenAI
import os

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 以下為新加坡地區的URL,調用時請將 {WorkspaceId} 替換為真實的業務空間ID,各地區的URL不同。
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1"
)

class UserInfo(BaseModel):
    name: str = Field(description="使用者的姓名")
    age: int = Field(description="使用者的年齡,單位為歲")

completion = client.chat.completions.parse(
    model="qwen3.8-max",
    messages=[
        {"role": "system", "content": "提取姓名與年齡資訊。"},
        {"role": "user", "content": "我叫劉五,今年25歲。"},
    ],
    response_format=UserInfo,
)

result = completion.choices[0].message.parsed
print(f"姓名:{result.name},年齡:{result.age}")
運行代碼可獲得以下輸出:
姓名:劉五,年齡:25

配置指南

使用 JSON Schema 時,遵循以下規範可獲得更可靠的結構化輸出:
  • 必要欄位聲明 推薦將必要欄位列在 required數組中。可選欄位可不列入,例如:
{
  "properties": {
    "name": {"type": "string"},
    "age": {"type": "integer"},
    "email": {"type": "string"}
  },
  "required": ["name", "age"]
}
若輸入未提供 email 資訊,輸出中將不包含此欄位。
  • 可選欄位的實現方式 除不列入 required 外,也可通過允許 null 類型實現:
{
  "properties": {
    "name": {"type": "string"},
    "email": {"type": ["string", "null"]}  // 可以是字串或 null
  },
  "required": ["name", "email"]  // 兩個都在 required 中
}
輸出將始終包含 email 欄位,但其值可能為 null
  • additionalProperties 配置 控制是否允許輸出未在 schema 中定義的額外欄位:
{
  "properties": {"name": {"type": "string"}},
  "required": ["name"],
  "additionalProperties": true  // 允許額外欄位
}
樣本輸入:"我叫張三,25歲";輸出:{"name": "張三", "age": 25}(包含未定義的 age 欄位)。

行為

適用情境

false

只輸出定義的欄位

需要精確控制結構

true

允許額外欄位

需要捕獲更多資訊

  • 支援的資料類型:string、number、integer、boolean、object、array、enum。

應用於生產環境

  • 有效性校正 若使用 JSON Object 模式,將輸出傳遞給下遊業務前,建議使用工具對其進行有效性校正,如 jsonschema (Python)、Ajv (JavaScript)、Everit (Java)等確保其符合指定的 JSON Schema 要求,避免因欄位缺失、類型錯誤或格式不規範導致下遊系統解析失敗、資料丟失或商務邏輯中斷。失敗時可通過重試、大模型改寫等策略進行修複。
  • 禁用 max_tokens 開啟結構化輸出時,請勿設定 max_tokens。該參數限制模型輸出的 Token 數(預設值為模型最大輸出 Token 數),設定後可能導致JSON字串在輸出過程中被截斷,產生無效 JSON,下遊解析將失敗。
  • 使用 SDK 輔助產生 Schema 推薦使用 SDK 自動產生 Schema,避免手動維護導致的錯誤,並可以自動驗證和解析。
    Python
    from pydantic import BaseModel, Field
    from typing import Optional
    from openai import OpenAI
    import os
    
    client = OpenAI(
        api_key=os.getenv("DASHSCOPE_API_KEY"),
        # 以下為新加坡地區的URL,調用時請將 {WorkspaceId} 替換為真實的業務空間ID,各地區的URL不同。
        base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1"
    )
    class UserInfo(BaseModel):
        name: str = Field(description="使用者姓名")
        age: int = Field(description="使用者年齡")
        email: Optional[str] = None  # 可選欄位
    
    completion = client.chat.completions.parse(
        model="qwen3.8-max",
        messages=[
            {"role": "system", "content": "提取姓名與年齡資訊。"},
            {"role": "user", "content": "我叫劉五,今年25歲。"},
        ],
        response_format=UserInfo  # 直接傳入 Pydantic 模型
    )
    
    result = completion.choices[0].message.parsed  # 型別安全的解析結果
    print(f"姓名:{result.name},年齡:{result.age}")
    

常見問題

Q:Qwen 的思考模式模型如何結構化輸出?

A:標註為"非思考模式"的模型,在思考模式下返回的內容可能不是嚴格的標準 JSON 字串,可採用以下兩步法進行修複:先調用思考模型擷取高品質輸出,再將格式不正確的 JSON 傳給支援 JSON Mode 的模型進行修複。
  1. 擷取思考模式下的輸出 調用思考模式模型擷取高品質輸出。輸出結果可能不是標準JSON字串。
    說明:開啟思考模式時設定 response_format 參數為 {"type": "json_object"} 不會報錯。以下為兜底樣本,僅在模型返回內容不是標準 JSON 時用於示範兩步修複法,因此步驟中未設定 response_format 參數。
completion = client.chat.completions.create(
    model="qwen3.8-max",
    messages=[
        {"role": "system", "content": system_prompt},
        {
            "role": "user",
            "content": [{"type": "text", "text": "大家好,我叫劉五,今年34歲,郵箱是liuwu@example.com,平時喜歡打籃球和旅遊"}],
        },
    ],
    # 開啟思考模式;本兜底樣本未設定response_format參數(直接設定response_format不會報錯)
    extra_body={"enable_thinking": True},
    # 思考模式下需要開啟流式輸出
    stream=True
)
# 提取並列印模型產生的JSON結果
json_string = ""
for chunk in completion:
    if not chunk.choices:
        continue
    if chunk.choices[0].delta.content is not None:
        json_string += chunk.choices[0].delta.content
  1. 校正並修複輸出 嘗試解析上一步擷取的 json_string
    • 若模型返回了有效 JSON,直接解析使用即可。
    • 若模型返回了無效 JSON,可調用支援結構化輸出的模型進行修複(建議選擇速度快、成本低的模型,如非思考模式的 qwen-flash)。
import json
from openai import OpenAI
import os

# 初始化OpenAI用戶端(如果前面的代碼塊未定義client變數,請取消下面的注釋)
# client = OpenAI(
#     api_key=os.getenv("DASHSCOPE_API_KEY"),
#     base_url="https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
# )

try:
    json_object_from_thinking_model = json.loads(json_string)
    print("產生標準格式JSON字串")
except json.JSONDecodeError:
    print("未產生標準格式JSON字串,通過支援結構化輸出的模型進行修複")
    completion = client.chat.completions.create(
        model="qwen-flash",
        # 使用非思考模式
        extra_body={"enable_thinking": False},
        messages=[
            {
                "role": "system",
                "content": "你是一個json格式修複專家,請將使用者輸入的json字串修複為標準格式",
            },
            {
                "role": "user",
                "content": json_string,
            },
        ],
        response_format={"type": "json_object"},
    )
    json_object_from_thinking_model = json.loads(completion.choices[0].message.content)

錯誤碼

如果模型調用失敗並返回報錯資訊,請參見錯誤碼進行解決。
Token Plan
模型體驗
用量統計與效能監控
資產中心
服務支援