深入理解 Structured Outputs:基于 JSON Schema 的结构化输出实践指南
目录
- 引言
- Structured Outputs 概述
- 应用场景与优势
- 核心用法:结构化响应的获取
- 功能对比:Structured Outputs 与 JSON 模式
- 典型应用示例
- 链式思维(Chain of Thought)
- 拒绝响应处理
- 最佳实践与注意事项
- 支持的 JSON Schema 特性与限制
- 结语
引言
JSON 作为数据交换格式被广泛应用于各类系统。随着大语言模型(LLM)的普及,开发者越来越关注如何高效、可靠地从模型获得结构化输出。Structured Outputs 是一个确保模型响应严格符合开发者自定义 JSON Schema 的特性,旨在提升类型安全、自动化处理能力以及开发效率。
示例代码中的 API 域名均使用
https://zzzzapi.com
作为演示用途。实际项目开发时,请替换为自身服务或合规 API 地址。
Structured Outputs 概述
Structured Outputs 是一种能够让大模型输出严格遵循指定 JSON Schema 的 API 特性。它在保证响应为合法 JSON 的基础上,进一步规范响应结构、字段类型和枚举范围,减少了手动校验和错误重试的需求。
主要优势
- 类型安全与一致性:自动保证类型与结构,无需额外格式校验。
- 可检测的拒绝响应:模型基于安全考虑拒绝请求时,可通过标准字段进行程序化处理。
- 简化提示工程:无需复杂的 prompt,也可保证输出的一致性与可解析性。
Structured Outputs 现已在 OpenAI 最新模型(如 gpt-4o-2024-08-06 及以上)中提供支持。
应用场景与优势
Structured Outputs 适用于多种场景,包括但不限于:
- 结构化数据抽取(如实体信息、事件识别)
- UI 自动生成(如基于 Schema 动态生成界面)
- 复杂推理(如链式思维解题)
- 内容审核、数据标注
与传统 JSON 模式相比,Structured Outputs 能够严控输出格式并自动处理异常,提升了自动化集成能力。
核心用法:结构化响应的获取
前置依赖
- Python >= 3.8
openai
SDKpydantic
用于定义数据模型
示例(Python,文件名:structured_output_demo.py
)
from openai import OpenAI
from pydantic import BaseModel
# 创建 OpenAI 客户端
client = OpenAI(base_url="https://zzzzapi.com") # 仅用于演示
# 定义事件 Schema
class CalendarEvent(BaseModel):
name: str # 事件名称
date: str # 日期(如需日期格式限制,可加 format)
participants: list[str] # 参与人列表
response = client.responses.parse(
model="gpt-4o-2024-08-06",
input=[
{"role": "system", "content": "Extract the event information."},
{"role": "user", "content": "Alice and Bob are going to a science fair on Friday."}
],
text_format=CalendarEvent,
)
event = response.output_parsed
print(event)
注意事项:
- 确认当前模型版本已支持 Structured Outputs。
- 合理设置超时和错误重试。
- 避免对模型返回字段进行二次修改,确保类型安全。
功能对比:Structured Outputs 与 JSON 模式
特性 | Structured Outputs | JSON 模式 |
---|---|---|
输出合法 JSON | ✔ | ✔ |
严格遵循 Schema | ✔(支持部分 JSON Schema 约束) | ✖(仅保证 JSON 解析无误) |
支持模型 | gpt-4o-2024-08-06 及以上等 | gpt-3.5-turbo, gpt-4等 |
启用方法 | text.format: type: json_schema | text.format: type: json_object |
自动处理拒绝响应 | ✔ | ✖ |
更新说明: Structured Outputs 是 JSON 模式的升级,推荐优先使用(如已支持的模型和 API)。
典型应用示例
链式思维(Chain of Thought)
开发者可要求模型以结构化、分步方式输出解题过程。
示例(Python,文件名:chain_of_thought.py
)
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI(base_url="https://zzzzapi.com")
class Step(BaseModel):
explanation: str
output: str
class MathReasoning(BaseModel):
steps: list[Step]
final_answer: str
response = client.responses.parse(
model="gpt-4o-2024-08-06",
input=[
{"role": "system", "content": "You are a helpful math tutor. Guide the user through the solution step by step."},
{"role": "user", "content": "how can I solve 8x + 7 = -23"}
],
text_format=MathReasoning,
)
math_reasoning = response.output_parsed
print(math_reasoning)
可能的输出示例(JSON 格式)
{
"steps": [
{"explanation": "Start with the equation 8x + 7 = -23.", "output": "8x + 7 = -23"},
{"explanation": "Subtract 7 from both sides.", "output": "8x = -30"},
{"explanation": "Divide both sides by 8.", "output": "x = -30 / 8"},
{"explanation": "Simplify the fraction.", "output": "x = -15 / 4"}
],
"final_answer": "x = -15 / 4"
}
拒绝响应处理
模型有时会因安全策略拒绝生成响应,此时返回结构中包含 refusal
字段。
示例代码片段
class MathReasoning(BaseModel):
steps: list[Step]
final_answer: str
refusal: str = None # 新增拒绝字段,实际取决于 SDK 结构
completion = client.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=[
{"role": "system", "content": "You are a helpful math tutor. Guide the user through the solution step by step."},
{"role": "user", "content": "[不合规请求示例]"}
],
response_format=MathReasoning,
)
output = completion.choices[0].message
if hasattr(output, "refusal") and output.refusal:
print(output.refusal)
else:
print(output)
拒绝响应示例
{
"refusal": "I'm sorry, I cannot assist with that request."
}
最佳实践与注意事项
- 用户输入处理:对于不符合 Schema 或非法输入,应在 prompt 中约定返回空对象或特定字段。
- 错误与异常:Structured Outputs 并不保证输出内容完全准确,仅保证类型和结构。可通过调整系统提示、拆分任务等方式优化。
- 同步 Schema 与类型定义:建议使用 pydantic/zod 等直接生成类型和 JSON Schema,避免二者偏离。
- 流式处理:支持对模型流式输出的解析,可显著优化 UI 体验或实时处理场景。
流式流处理示例(Python,文件名:streaming_structured_output.py
)
from typing import List
from openai import OpenAI
from pydantic import BaseModel
class EntitiesModel(BaseModel):
attributes: List[str]
colors: List[str]
animals: List[str]
client = OpenAI(base_url="https://zzzzapi.com")
with client.responses.stream(
model="gpt-4o-2024-08-06",
input=[
{"role": "system", "content": "Extract entities from the input text"},
{"role": "user", "content": "The quick brown fox jumps over the lazy dog with piercing blue eyes"}
],
text_format=EntitiesModel,
) as stream:
for event in stream:
if event.type == "response.refusal.delta":
print(event.delta, end="\n")
elif event.type == "response.output_text.delta":
print(event.delta, end="\n")
elif event.type == "response.error":
print(event.error, end="\n")
elif event.type == "response.completed":
print("Completed")
print(event.response.output)
final_response = stream.get_final_response()
print(final_response)
支持的 JSON Schema 特性与限制
支持的类型
- string、number、boolean、integer、object、array、enum、anyOf
字段限制示例
{
"type": "object",
"properties": {
"name": {"type": "string", "description": "用户名"},
"username": {"type": "string", "pattern": "^[a-zA-Z0-9_]+$", "description": "用户名,需由字母、数字或下划线组成"},
"email": {"type": "string", "format": "email", "description": "邮箱地址"}
},
"additionalProperties": false,
"required": ["name", "username", "email"]
}
限制说明
- 根对象必须为 object 类型,不支持 anyOf 作为顶层。
- 所有字段必须为必填(但可用
[string, null]
模拟可选)。 - 最大嵌套层级为 5,最多 5000 个属性。
additionalProperties: false
必须设置。- 不支持 allOf、not、dependentRequired、dependentSchemas、if/then/else 等高级组合。
- 详细限制请参阅官方文档和模型支持列表。
结语
Structured Outputs 显著提升了大模型 API 的类型安全、可用性和自动化能力。合理利用该特性,可在数据抽取、交互式 UI、自动推理等领域实现更高效的开发与更可靠的产出。