结构化输出:让它的答案能直接进表格

「请用 JSON 回答」和「保证符合我给的这张表结构」是两件事。前者只保证语法合法,后者保证字段一个不多一个不少——这个差别决定了你能不能把一百份材料的结果直接拼成一张表。

2024/08/06约 7 分钟HiBridge 编译
译文本文是英文原文的中文翻译,原作者与原文链接如下。
原作者
OpenAI
原文标题
Introduction to Structured Outputs
原发布平台
OpenAI Cookbook
原发布日期
2024/08/06

译者说明:本文译自 OpenAI 官方 Cookbook。原文是可运行的 Jupyter Notebook,此处翻译全部说明性内容, 代码与 schema 片段原样保留。方法本身是通用的——Claude 和 Gemini 都有对应能力,见文末。

关于日期:Cookbook 是持续更新的仓库,页面上没有发布日期。本文的日期取自该 notebook 在 GitHub 上的首次提交日期,也就是这份内容第一次被生产出来的时间。

结构化输出(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:

JSON
{
  "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。原文建议尽可能用这个方法。

Python
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

对应的模型定义:

Python
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_formatjson_schema + strict: true(本文)
Google Gemini response_schema,可直接传 Pydantic 模型(见从 PDF 和手写表单里提取结构化数据
Anthropic Claude 用工具定义(tool schema)来约束输出结构

配套阅读:用 Claude 做分类从超长文档里提取关键信息


出处

本文译自 OpenAI Cookbook,原文 Introduction to Structured Outputs, 以 MIT 许可发布。译文与译后附记由 HiBridge 撰写。