结构化输出:让它的答案能直接进表格
「请用 JSON 回答」和「保证符合我给的这张表结构」是两件事。前者只保证语法合法,后者保证字段一个不多一个不少——这个差别决定了你能不能把一百份材料的结果直接拼成一张表。
- 原作者
- OpenAI
- 原文标题
- Introduction to Structured Outputs
- 原发布平台
- OpenAI Cookbook
- 原发布日期
- 2026/08/06
译者说明:本文译自 OpenAI 官方 Cookbook。原文是可运行的 Jupyter Notebook,此处翻译全部说明性内容, 代码与 schema 片段原样保留。方法本身是通用的——Claude 和 Gemini 都有对应能力,见文末。
结构化输出(Structured Outputs)保证模型生成的响应始终符合你提供的 JSON Schema。
它通过在 API 调用中设置参数 strict: true 来启用,可以配合已定义的响应格式或函数定义使用。
它和「JSON 模式」的差别
在此之前,response_format 参数只能用来指定模型应当返回合法的 JSON。
与 JSON 模式不同,结构化输出约束的是 JSON 的形状,而不只是它的合法性。
这个差别在生产级应用中很关键。原文列出的典型用途:
- 拿到结构化的答案,以便在界面上按特定方式展示
- 用从文档中提取的内容填充数据库
- 从用户输入中提取实体,用来调用带明确参数的工具
更一般地说,任何需要取数、执行动作,或者建立在复杂工作流之上的场景,都能从结构化输出中受益。
例一:把解题过程拆成步骤
原文的第一个例子是做一个数学辅导工具,把解题过程输出成一个结构化对象的数组——这样每一步可以单独展示,让用户按自己的节奏推进。
系统提示词(原文照录):
You are a helpful math tutor. You will be provided with a math problem,
and your goal will be to output a step by step solution, along with a final answer.
For each step, just provide the output as an equation use the explanation field to detail the reasoning.
对应的 schema:
{
"type": "json_schema",
"json_schema": {
"name": "math_reasoning",
"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
},
"strict": true
}
}
更省事的写法
新版 SDK 引入了 parse 辅助方法,让你可以直接给出自己的 Pydantic 模型,而不必手写 JSON Schema。原文建议尽可能用这个方法。
from pydantic import BaseModel
class MathReasoning(BaseModel):
class Step(BaseModel):
explanation: str
output: str
steps: list[Step]
final_answer: str
completion = client.beta.chat.completions.parse(
model=MODEL,
messages=[...],
response_format=MathReasoning,
)
拒绝回答的情况
当结构化输出遇到用户生成的输入时,模型偶尔会出于安全原因拒绝完成请求。
由于拒绝并不符合你在 response_format 里提供的 schema,API 新增了一个 refusal 字段来标示模型拒绝作答。
这很有用——你可以在界面上把拒绝单独渲染出来,也避免了尝试反序列化成你的格式时报错。
例二:按固定结构总结文章
第二个例子要求模型按指定 schema 总结文章。如果你需要把文本或视觉内容转换成结构化对象——比如为了以特定方式展示,或者为了填充数据库——这就有用了。
提示词(原文照录):
You will be provided with content from an article about an invention.
Your goal will be to summarize the article following the schema provided.
Here is a description of the parameters:
- invented_year: year in which the invention discussed in the article was invented
- summary: one sentence summary of what the invention is
- inventors: array of strings listing the inventor full names if present, otherwise just surname
- concepts: array of key concepts related to the invention, each concept containing a title and a description
- description: short description of the invention
对应的模型定义:
class ArticleSummary(BaseModel):
invented_year: int
summary: str
inventors: list[str]
description: str
class Concept(BaseModel):
title: str
description: str
concepts: list[Concept]
注意这里的一个细节:提示词里对每个字段都写了一句说明(「如果没有全名就只写姓」)。字段名本身不足以传达你的意图,字段说明才是。
译后附记:不写代码也能拿到八成好处
如果你不调 API,「保证符合 schema」这一条拿不到。但那句关键的设计思路可以拿到:先定字段,再让它填。
在对话框里的等效做法,是把 schema 写成一张表头:
从下面这份访谈稿里提取信息,输出成一张 Markdown 表格,表头固定为: | 受访者角色 | 提到的痛点 | 原话摘录 | 提到的品牌 | 价格敏感度(高/中/低/未提及) | 规则: - 每一行对应一个痛点,同一个人有多个痛点就拆成多行 - 「原话摘录」必须是稿子里的原文,不要改写 - 稿子里没有的信息,写「未提及」,不要推测 - 不要增加表头以外的列,不要合并单元格
复制为纯文本,换行与缩进原样保留,可直接粘贴进对话框。
对照原文,这段提示词对应了结构化输出的三个要素:固定的字段(表头)、每个字段的说明(规则)、以及缺失时的行为(写「未提及」)。最后一条尤其重要——不写这一条,它会自己编。
要真正的保证,三家都有对应能力:
| 厂商 | 能力 |
|---|---|
| OpenAI | response_format 的 json_schema + strict: true(本文) |
| Google Gemini | response_schema,可直接传 Pydantic 模型(见从 PDF 和手写表单里提取结构化数据) |
| Anthropic Claude | 用工具定义(tool schema)来约束输出结构 |
配套阅读:用 Claude 做分类、从超长文档里提取关键信息。
出处
本文译自 OpenAI Cookbook,原文 Introduction to Structured Outputs, 以 MIT 许可发布。译文与译后附记由 HiBridge 撰写。