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 大部分模型、Kimi、GLM、DeepSeek、Stepfun

仅支持部分模型

response_format 参数设置

{"type": "json_object"}

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

提示词要求

必须包含 "JSON"

建议明确说明

适用场景

灵活的 JSON 输出

精确的结构验证

支持的模型

  • JSON Object
  • JSON Schema
  • 千问
  • Kimi
  • DeepSeek
  • GLM
  • Stepfun
  • 文本生成模型
    • 千问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 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="sk-xxx"
    # 各地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 以下是北京地域base_url,如果使用新加坡地域的模型,需要将base_url替换为:https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1
    base_url="https://{WorkspaceId}.cn-beijing.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="sk-xxx",
    # 各地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 以下是北京地域base_url,如果使用新加坡地域的模型,需要将base_url替换为:https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1
    base_url="https://{WorkspaceId}.cn-beijing.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"
    }
  ]
}

思考模型的结构化输出

启用思考模型的结构化输出后,模型会先进行推理再生成 JSON,输出结果通常比非思考模型更准确。
  • OpenAI兼容
  • DashScope
  • Python
  • Node.js
  • HTTP

示例代码

from openai import OpenAI
import os

# 初始化OpenAI客户端
client = OpenAI(
    # 如果没有配置环境变量,请用阿里云百炼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",
)

messages=[
    {
        "role": "system",
        "content": [{"type": "text", "text": "请抽取用户的姓名与年龄信息,以JSON格式返回"}]
    },
    {
        "role": "user",
        "content": [{"type": "text", "text": "大家好,我叫刘五,今年34岁,邮箱是liuwu@example.com,平时喜欢打篮球和旅游"}],
    },
]

completion = client.chat.completions.create(
    model="qwen3.8-max",
    messages=messages,
    extra_body={"enable_thinking": True},
    stream=True,
    stream_options={
        "include_usage": True
    },
    response_format={"type": "json_object"}
)

reasoning_content = ""  # 完整思考过程
answer_content = ""  # 完整回复
is_answering = False  # 是否进入回复阶段
print("\n" + "=" * 20 + "思考过程" + "=" * 20 + "\n")

for chunk in completion:
    if not chunk.choices:
        print("\nUsage:")
        print(chunk.usage)
        continue

    delta = chunk.choices[0].delta

    # 只收集思考内容
    if hasattr(delta, "reasoning_content") and delta.reasoning_content is not None:
        if not is_answering:
            print(delta.reasoning_content, end="", flush=True)
        reasoning_content += delta.reasoning_content

    # 收到content,开始进行回复
    if hasattr(delta, "content") and delta.content:
        if not is_answering:
            print("\n" + "=" * 20 + "完整回复" + "=" * 20 + "\n")
            is_answering = True
        print(delta.content, end="", flush=True)
        answer_content += delta.content

返回结果

====================思考过程====================

用户要求抽取姓名与年龄信息,并以JSON格式返回。

从文本中可以看到:
- 姓名:刘五
- 年龄:34
- 邮箱:liuwu@example.com(但用户只要求姓名和年龄)
- 爱好:打篮球和旅游(但用户只要求姓名和年龄)

根据要求,只需要提取姓名和年龄信息,并以JSON格式返回。

JSON格式应该是:
{
  "姓名": "刘五",
  "年龄": 34
}

或者使用英文键名:
{
  "name": "刘五",
  "age": 34
}

考虑到用户使用的是中文提问,使用中文键名可能更合适。不过通常JSON键名使用英文也是常见做法。这里我采用中文键名,因为用户的指令是中文的,且提取的信息也是中文语境下的。

最终输出:
{
  "姓名": "刘五",
  "年龄": 34
}
====================完整回复====================

{"姓名":"刘五","年龄":34}
Usage:
CompletionUsage(completion_tokens=203, prompt_tokens=48, total_tokens=251, completion_tokens_details=CompletionTokensDetails(accepted_prediction_tokens=None, audio_tokens=None, reasoning_tokens=190, rejected_prediction_tokens=None), prompt_tokens_details=None)

优化提示词

模糊的提示词(如”返回用户信息”)会导致输出结构不可预期。为获得可靠的结果,建议在提示词中明确描述预期的 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客户端
client = OpenAI(
    # 若没有配置环境变量,请将下行替换为:api_key="sk-xxx"
    # 各地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 以下是北京地域base_url,如果使用新加坡地域的模型,需要将base_url替换为:https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1
    base_url="https://{WorkspaceId}.cn-beijing.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
        },
        {
            "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"),
    # 以下为华北2(北京)地域的URL,调用时请将 {WorkspaceId} 替换为真实的业务空间ID,各地域的URL不同。
    base_url="https://{WorkspaceId}.cn-beijing.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"),
        # 以下为华北2(北京)地域的URL,调用时请将 {WorkspaceId} 替换为真实的业务空间ID,各地域的URL不同。
        base_url="https://{WorkspaceId}.cn-beijing.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
模型体验
模型调优
模型压缩目录节点
用量统计与性能监控
资产中心
服务支持