GuidesModels
用 Structured Outputs 拿到可解析的模型结果
用 json_schema + strict 约束 Chat Completions 输出,让结果可以直接解析进入应用逻辑。
基于 OpenAI Cookbook 整理 · 官方资料 ↗
把模型接到产品里时,最常见的失败不是“答案不对”,而是“答案长得不对”。你要填表单、写库、驱动下一步工作流,却拿到一段看起来像 JSON、实际少字段、多字段、或夹着解释文字的字符串。
Structured Outputs 解决的就是这件事:你先声明真正需要的数据结构,再让 API 按 schema 约束返回。启用 strict 后,结果形状由协议保证,而不是靠提示词碰运气。
这篇按 OpenAI Cookbook 的数学辅导示例,走完定义 schema、调用 Chat Completions、再直接 json.loads 的最短路径。
为什么“让模型返回 JSON”还不够
只在 system prompt 里写“请返回 JSON”,模型通常会配合,但应用侧仍然脆弱。字段可能缺失,类型可能漂移,还可能夹带 Markdown 代码围栏或额外说明。
JSON mode 能把输出约束成合法 JSON,仍然不保证键名、嵌套结构和必填项与你的业务对象一致。你还得写一堆校验、重试和兜底解析。
Structured Outputs 更进一步:你把 JSON Schema 交给 API,并打开 strict。请求要么按 schema 返回,要么在 schema 本身不合法时被拒绝。应用代码可以按契约读取字段,而不是先猜字符串形态。
先定义你真正需要的数据结构
先别急着调模型。先想清楚下游代码要读什么。Cookbook 的数学辅导示例要两块数据:分步推理解释,以及最终答案。
schema 名叫 math_reasoning。根对象包含 steps 数组和 final_answer 字符串;steps 里每一项都有 explanation 与 output。每个 object 都要设 additionalProperties: false,并在 json_schema 上设 strict: true,这样不能偷偷多塞字段。
升级 openai SDK(官方 Cookbook)
pip install -U openaimath_reasoning schema
response_format = {
"type": "json_schema",
"json_schema": {
"name": "math_reasoning",
"strict": True,
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {"type": "string"},
"output": {"type": "string"}
},
"required": ["explanation", "output"],
"additionalProperties": False
}
},
"final_answer": {"type": "string"}
},
"required": ["steps", "final_answer"],
"additionalProperties": False
}
}
}把 schema 交给模型
把上面的 response_format 直接传给 chat.completions.create。Cookbook 示例模型是 gpt-4o-2024-08-06;你账号若不可用同名模型,需换成同样支持 Structured Outputs 的版本。
from openai import OpenAI
from textwrap import dedent
client = OpenAI()
MODEL = "gpt-4o-2024-08-06"
response = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": dedent("You are a helpful math tutor.")},
{"role": "user", "content": "solve 8x + 7 = -23"},
],
response_format=response_format,
)这里没有再写“请用 JSON 返回”。形状约束来自 response_format 里的 json_schema,而不是额外提示词。
直接拿到可解析结果
成功时,message.content 就是一段符合 schema 的 JSON 字符串。直接 json.loads,再读 final_answer 和 steps。
import json
data = json.loads(response.choices[0].message.content)
print(data["final_answer"])
print(len(data["steps"]))
for step in data["steps"]:
print(step["explanation"], "->", step["output"])这一步的验收标准很具体:能解析、有 final_answer、steps 每项都有 explanation 与 output。若这些都成立,就可以把同一段解析结果接到 UI 或数据库写入逻辑上。
schema 不匹配时会发生什么
有两类“不匹配”,表现完全不同。
第一类是你提交的 schema 本身不合 Structured Outputs 规则——例如 required 不完整、object 漏了 additionalProperties: false。这时 API 会直接拒绝请求,你根本拿不到模型输出。
第二类是 schema 合法且 strict: true。此时模型输出会被约束到该 schema:不会悄悄少必填字段,也不会多出未声明键。你仍然要处理业务语义是否正确,但不需要再为“JSON 长得不对”写大量防御代码。
Structured Outputs 什么时候真正有价值
它真正值钱的地方,是输出马上要进入确定性代码路径:渲染分步 UI、写入表结构、组装下游工具参数、驱动状态机。字段名和嵌套关系一旦稳定,应用边界就清晰了。
开放式长文、探索性草稿、或你本来就要人工阅读的回复,通常没必要硬套 schema。Cookbook 也同时覆盖了 function calling 的 strict 模式;当你需要的是“选工具 + 填参数”,那是另一条同族能力。
实用建议:先把业务对象写成 schema,再让模型填它。不要先拿自由文本,再在应用层用正则硬拆。
最容易踩的坑
API 拒绝 schema
检查每个 object 是否都有 additionalProperties: false、required 是否覆盖全部 properties,以及模型是否支持 Structured Outputs。
仍得到不合 schema 的内容
确认走的是 response_format.type = "json_schema" 且 json_schema.strict = True,而不是只开了 JSON mode 或只在 prompt 里要求 JSON。
json.loads 失败或字段对不上
先打印 message.content;确认没有包在代码围栏里。再核对你读的键是否与 schema 一致(steps / final_answer)。
模型名不可用
Cookbook 使用 gpt-4o-2024-08-06。若账号无此模型,换成当前支持 Structured Outputs 的可用模型后再试。
官方资料
OpenAI Cookbook
Introduction to Structured Outputs ↗