Day 9:Structured Output 工程实践

学习目标

昨天你学会了调用模型 API 的基本方法。今天要解决的问题是:怎么让模型稳定地输出你想要的格式。

在 Week 1 的 Day 4 中,你已经学过结构化输出的概念——为什么需要 JSON、什么是 JSON Schema、Pydantic 怎么用。今天是那个基础概念的工程落地。不是”知道结构化输出是什么”,而是”在实际项目中怎么让结构化输出稳定工作”。

你要掌握的核心能力包括:使用 JSON Mode 强制模型输出合法 JSON、用 JSON Schema 精确定义输出结构、用 Pydantic BaseModel 做数据校验、处理格式错误和字段缺失、设计自动重试机制、把结构化结果存入数据库。

完成今天的学习后,你的模型调用不再是一次”可能成功也可能失败”的赌博,而是一个有校验、有重试、有兜底的可靠流程。

核心概念

一、JSON Mode

JSON Mode 是模型 API 提供的一种特殊输出模式。当你开启 JSON Mode 后,模型会被强制约束,只输出合法的 JSON 格式文本。

在普通模式下,你在 Prompt 里写”请以 JSON 格式输出”,模型大概率会照做,但它可能在 JSON 前面加一句”好的,以下是你要求的分析结果:“,或者在 JSON 后面加一句”希望这些信息对你有帮助”。这些额外的文字对人是友好的,但对程序来说是灾难——你的 JSON 解析器会因为这些非 JSON 文本而报错。

JSON Mode 解决的就是这个问题。开启后,模型的输出保证是一个合法的 JSON 字符串,不会包含任何额外的解释文字、标记符号或格式装饰。

但 JSON Mode 有一点经常被误解:它只保证输出是合法的 JSON,不保证 JSON 的结构符合你的期望。什么意思?你期望模型输出一个包含 industry_name、market_size、challenges 三个字段的对象,模型可能输出一个包含 name、size、issues 的对象。JSON 格式本身是合法的(花括号配对、引号正确、冒号到位),但字段名和结构与你的预期不符。

所以 JSON Mode 是”格式层面的保证”,不是”内容层面的保证”。要实现内容层面的保证,需要配合 JSON Schema。

在实际使用 JSON Mode 时有几个注意点:

开启方式因服务商而异。OpenAI 需要在请求参数中设置 response_format 为 json_object,同时在 system 消息或 user 消息中明确提及 JSON 输出。Anthropic 的做法是在 system 消息中描述输出格式,并在工具调用中定义结构。不同服务商的实现细节不同,但核心思想一致——告诉模型”你必须输出 JSON”。

Prompt 配合。即使开启了 JSON Mode,你仍然应该在 Prompt 中描述期望的输出结构。JSON Mode 保证格式合法,Prompt 中的结构描述引导模型输出正确的内容。两者配合才能得到既合法又正确的 JSON。

性能开销。JSON Mode 通常比普通模式略慢,因为模型需要在生成过程中额外关注格式约束。这个开销很小(通常增加 10%-20% 的延迟),但值得知道。

二、JSON Schema 深入实践

在 Week 1 的 Day 4 中,你已经知道 JSON Schema 是定义 JSON 结构的规范语言。今天我们从工程实践的角度深入讨论。

设计一个好的 JSON Schema 不是随便定义几个字段就完事了。它需要考虑模型的能力边界、业务需求的完整性、以及校验的可操作性。

先说字段设计的原则。

字段名要有自解释性。用 industry_name 而不是 name,用 annual_growth_rate 而不是 rate。模型看到 industry_name 就知道这个字段要填行业名称,看到 rate 可能产生歧义——是增长率、利率还是评分?

每个字段都要有描述。JSON Schema 支持 description 属性,用一句话解释这个字段的含义和期望内容。这个描述不仅是给你自己看的,也是给模型看的——模型在生成内容时会参考 Schema 中的描述来理解每个字段的意图。

类型要精确。字符串就用 string,数字就用 number,布尔值就用 boolean,数组就用 array,嵌套对象就用 object。不要所有字段都用 string——如果市场规模是数字,就定义为 number,这样模型会输出纯数字而不是”约100亿”这种文字描述。

再说约束的设计。

必填与选填。通过 required 数组来指定哪些字段必须出现。核心字段设为必填(如行业名称、市场规模),辅助字段设为选填(如备注、补充说明)。必填字段太多会增加模型出错的概率——模型可能在某个字段上卡住导致整体格式错误。一般建议必填字段不超过 7 个。

枚举值。当一个字段的值只能从有限的几个选项中选择时,用 enum 来定义。比如行业阶段可以是”初创期”、“成长期”、“成熟期”、“衰退期”四个选项。枚举值约束能有效防止模型输出意料之外的值。

数值范围。用 minimum 和 maximum 来约束数字字段的范围。比如增长率设 minimum 为 -100、maximum 为 1000(百分比),防止模型输出离谱的数字。

字符串长度。用 minLength 和 maxLength 来约束字符串字段的长度范围。比如行业概述设 minLength 为 50、maxLength 为 500,避免模型输出一句话就完事或者写了一篇小论文。

数组长度。用 minItems 和 maxItems 来约束数组的长度。比如主要挑战设 minItems 为 2、maxItems 为 5,确保模型至少列出两个挑战但不超过五个。

嵌套结构的控制。尽量避免三层以上的嵌套。深层嵌套不仅让模型更容易出错(漏掉花括号、搞错层级关系),也让校验和错误定位变得更困难。如果一个结构确实很复杂,考虑拆分成多个独立的 Schema,让模型分步骤生成。

一个工程实践中的技巧:先设计最简版本的 Schema,只包含核心必填字段。验证模型能稳定输出后,再逐步增加字段和约束。一上来就设计一个包含 20 个字段、10 层嵌套的 Schema,几乎一定会出问题。

三、Pydantic BaseModel 实践

Pydantic 是 Python 生态中数据校验的事实标准。它和 JSON Schema 的关系是:Pydantic 模型可以自动导出 JSON Schema,也可以用 JSON Schema 来校验数据。

在 AI 应用中使用 Pydantic 的典型流程是这样的:

第一步,定义 Pydantic 模型。用 Python 的类型注解定义数据结构,每个字段加上描述。Pydantic 的 Field 函数支持设置默认值、描述、约束条件(最小值、最大值、正则表达式等)。

第二步,导出 JSON Schema。从 Pydantic 模型自动生成 JSON Schema,把这个 Schema 传给模型 API,告诉模型按这个结构输出。这比手写 JSON Schema 要方便得多,而且保证了 Pydantic 模型和 JSON Schema 始终一致。

第三步,校验模型输出。模型返回 JSON 后,用 Pydantic 模型来解析和校验。如果 JSON 缺少必填字段、类型不对、值超出范围,Pydantic 会抛出 ValidationError,你捕获这个异常就知道哪出了问题。

第四步,使用校验后的数据。校验通过后,你就得到了一个类型安全的 Python 对象,可以用点号访问字段值,IDE 会提供自动补全,代码更安全也更易读。

Pydantic 的一些高级用法在 AI 应用中特别有用:

Optional 字段。不是所有字段每次都有值,用 Optional 类型标注选填字段。校验时如果这个字段缺失,Pydantic 不会报错,而是设为 None。

默认值。给字段设置默认值,当模型没有输出这个字段时使用默认值而不是报错。比如风险等级可以默认为”中”。

自定义校验器。用 Pydantic 的 validator 或 model_validator 定义自定义校验逻辑。比如检查日期格式是否合理、检查增长率和市场规模是否逻辑自洽(不能市场规模 10 亿但增长率 5000%)。

嵌套模型。一个 Pydantic 模型可以包含另一个 Pydantic 模型作为字段类型。比如行业分析模型包含一个市场分析子模型、一个竞争分析子模型。这让复杂数据结构的定义更清晰。

枚举类型。用 Python 的 Enum 配合 Pydantic 来限制字段值为预定义的选项。比如行业类型用 Enum 定义所有允许的值,模型输出不在枚举范围内的值就会校验失败。

四、输出字段约束

字段约束是在 JSON Schema 层面和 Pydantic 层面同时施加的,目的是缩小模型输出的自由度,让结果更可控。

为什么需要约束?因为模型的输出是概率性的。没有约束的情况下,模型可能把”市场规模”输出为”大概一百多亿吧”,把”增长率”输出为”挺高的”。这些表述在自然语言中没问题,但在结构化数据中无法被程序处理。

常见的约束类型:

类型约束。每个字段必须是指定的类型——字符串就是字符串,数字就是数字,布尔就是布尔。这是最基础的约束,防止模型把数字输出为字符串(“100”而不是 100),或者把布尔值输出为”是/否”。

格式约束。字符串字段可以要求特定格式——日期必须是 YYYY-MM-DD 格式,邮箱必须是合法邮箱格式,URL 必须以 http 或 https 开头。

范围约束。数字字段必须在指定范围内——评分在 1-10 之间,百分比在 0-100 之间,年份在 2000-2030 之间。

长度约束。字符串字段必须在指定长度范围内——标题不超过 50 字,描述在 100-500 字之间。

枚举约束。字段值必须是指定列表中的一个——风险等级只能是”低”、“中”、“高”。

条件约束。字段之间存在逻辑关系——如果选择了”有竞争壁垒”,则必须填写”壁垒类型”;如果”市场规模”小于 1 亿,则”投资建议”不能是”强烈推荐”。

约束的设计原则是:足够严格以保证可用性,又足够宽松以允许合理的输出变化。如果约束太严(比如要求每个字段精确到某几个字),模型很难稳定满足要求,重试次数会暴增。如果约束太松(比如所有字段都是可选的字符串),结构化输出就失去了意义。

五、输出枚举值

枚举值约束是字段约束中特别重要的一类,值得单独展开讨论。

在很多业务场景中,某个字段的值只能从有限的几个选项中选择。比如 AI 机会的优先级只能是”高”、“中”、“低”;落地的难度评级只能是”容易”、“中等”、“困难”;推荐的模型类型只能是”对话模型”、“推理模型”、“Embedding 模型”。

为什么枚举值这么重要?

第一,保证下游系统的可处理性。如果风险等级可以是任意字符串,你的下游系统就需要处理无数种可能的值。如果只能是”低”、“中”、“高”三个值,下游系统只需要处理三种情况。

第二,保证数据的可统计性。只有枚举值才能做有效的统计和聚合。你可以说”高优先级的机会有 5 个,低优先级的有 3 个”。但如果优先级是自由文本,你根本无法统计。

第三,限制模型的自由发挥空间。模型在处理”风险等级”这类字段时,可能输出”较低”、“中等偏上”、“一般般”等各种表述。枚举值把选择范围固定下来,模型的输出更可控。

枚举值的设计有几个注意点:

枚举选项要互斥。“低”和”较低”之间界限模糊,模型容易选错。改成”低”、“中”、“高”三个明确互斥的选项更好。

枚举选项要覆盖所有可能。如果你只定义了”制造业”和”服务业”两个行业类型,模型分析金融行业时就会遇到问题。要么在枚举中增加更多选项,要么加一个”其他”选项作为兜底。

枚举选项不要太多。超过 10 个选项会让模型选择困难,增加选错的概率。如果确实需要很多选项,考虑用层级结构——先选大类,再选小类。

枚举值的定义应该同时出现在两个地方:JSON Schema 的 enum 字段中(让模型看到约束),以及 Prompt 的文字描述中(解释每个选项的含义和选择标准)。双重约束比单一约束更有效。

六、必填字段

必填字段的设计直接决定了结构化输出的稳定性。

哪些字段应该设为必填?一个简单的判断标准:如果这个字段缺失,下游系统无法正常工作,它就是必填的。如果缺失后可以用默认值替代或者可以接受为空,它就是选填的。

举个例子。行业分析结果中,“行业名称”是必填的(没有名称就无法标识这个分析结果),“市场规模”是必填的(这是核心输出),“备注”是选填的(没有备注不影响主要结论)。

必填字段的设计要避免一个常见错误:把所有字段都设为必填。这种做法看起来很完美——你想要所有信息,所以要求所有字段都填。但实际上,必填字段越多,模型出错的概率越高。某个字段模型不知道怎么填,它可能编造一个值来应付,或者干脆输出一个不合法的 JSON。

一个实用的策略是”核心必填、边缘选填”。只把真正不可或缺的 3-5 个字段设为必填,其他字段设为选填。在 Prompt 中说明”以下字段尽量填写:xxx、xxx”,用软约束代替硬约束。这样模型有更大的灵活度,输出更稳定。

如果确实需要很多必填字段怎么办?拆分任务。不要让模型一次输出 20 个必填字段的结构,而是拆成两三次调用,每次输出 5-8 个字段。虽然增加了调用次数,但每次的成功率更高。

七、格式修复

无论你的约束设计得多好,模型偶尔还是会输出格式错误。可能是 JSON 多了一个逗号,可能是某个字段用了中文引号,可能是嵌套结构的花括号没对齐。

格式修复是在严格校验之前的一道缓冲。它尝试修复常见的格式问题,把”差不多正确”的 JSON 变成”完全正确”的 JSON。

常见的格式修复策略:

去除非 JSON 内容。模型有时在 JSON 前后添加文字说明。用正则表达式提取 JSON 部分(找到第一个 { 和最后一个 } 之间的内容)。

修复常见语法错误。中文引号替换为英文引号、尾部多余逗号删除、单引号替换为双引号、缺失的引号补上。

修复 Unicode 转义。模型有时输出未经转义的中文或特殊字符,需要规范化。

补全不完整的 JSON。如果模型输出被截断(Max Tokens 不够),JSON 可能不完整。检测到截断时,尝试补全缺失的结束符(}、])。这个策略有风险——补全的 JSON 在结构上可能不完整,但在某些场景下”部分完整”比”完全不完整”要好。

格式修复的原则是:只修复确定性的格式问题,不要猜测内容。如果一个字段缺失了,不要自己填一个值。如果一个值明显不对,不要自己改。格式修复只处理”形式”问题,不处理”内容”问题。

八、自动重试

格式校验失败后,自动重试是保障输出质量的最后一道防线。

重试策略和 Day 8 学的 API 调用重试有相似之处,但关注点不同。API 调用重试关注的是网络和服务端的临时性错误,结构化输出重试关注的是模型输出的格式和内容不符合要求。

结构化输出重试的流程:

第一次调用模型,获取输出。尝试解析 JSON,如果解析失败,尝试格式修复后再次解析。解析成功后,用 Pydantic 校验字段,如果校验失败,进入重试。

重试时,把上一次的错误信息告诉模型。比如”你上次输出的 JSON 缺少 required 字段 market_size,请修正”。这种”带反馈的重试”比无脑重试有效得多——模型知道哪里出了问题,可以在下一次输出中修正。

重试次数不要太多。结构化输出的重试通常设 2-3 次就够了。如果重试了 3 次还是不满足要求,说明问题可能不在随机性上,而是 Prompt 设计或 Schema 设计有问题。继续重试只是浪费 Token。

重试时可以尝试调整参数。把 Temperature 调低一点(比如从 0.3 降到 0.1),减少模型的随机性,提高格式遵从率。

如果所有重试都失败了,要有兜底方案。一种做法是返回一个半结构化的结果——把模型输出中能提取的信息提取出来,缺失的字段用默认值填充。另一种做法是降级为自由文本输出,让用户看到原始结果,由人工判断。

九、结构化结果入库

结构化输出的最终归宿通常是数据库。因为只有存入数据库,数据才能被查询、统计、分析、展示。

入库涉及几个设计决策:

数据库选择。对于结构化数据,关系型数据库(PostgreSQL、MySQL)是首选。JSON 字段可以直接存为 JSON 类型(PostgreSQL 原生支持 JSONB),也可以拆成多个关系字段。对于半结构化或频繁变化的数据,MongoDB 等 NoSQL 数据库也是选择之一。

表结构设计。一个基本的设计是创建一张 analysis_results 表,包含:id(主键)、task_type(任务类型,如”行业分析”、“岗位分析”)、input_params(输入参数的 JSON)、result(模型输出的 JSON)、model_name(使用的模型)、token_usage(Token 消耗)、status(状态:成功、失败、部分成功)、created_at(创建时间)。

这个设计的核心思想是:把原始结果完整保存。不管你后续怎么处理这些数据,原始输出永远可以追溯。不要在入库时丢掉信息。

索引设计。根据查询需求建索引——按任务类型查、按创建时间查、按状态查。如果需要按 JSON 内容中的某个字段查(比如”行业名称”),可以考虑提取这个字段作为独立列并建索引。

数据质量标记。入库时标记数据质量——校验通过的是”clean”,格式修复后通过的是”repaired”,校验失败的兜底数据是”degraded”。后续分析数据时可以按质量标记过滤。

入库后的数据就变成了你的资产。随着时间积累,你会拥有大量的行业分析、岗位分析、流程分析的结构化数据。这些数据可以用来做趋势分析、Prompt 效果评估、模型对比测试。

概念关系图

+------------------+     +------------------+     +------------------+
|   Prompt +       |     |   JSON Schema    |     |  Pydantic Model  |
|   JSON Mode 开启 |---->|   定义输出结构    |<--->|  Python 端校验    |
+------------------+     +------------------+     +------------------+
         |                        |                        |
         v                        v                        v
+--------------------------------------------------------------+
|                     模型 API 调用                              |
|          (输出 JSON 格式的结构化数据)                            |
+--------------------------------------------------------------+
         |
         v
+------------------+     +------------------+     +------------------+
|   JSON 解析      |---->|  格式修复         |---->|  Pydantic 校验   |
|   (合法性检查)   | Yes |  (修复常见错误)   | Yes |  (字段完整性)    |
+------------------+     +------------------+     +------------------+
         | No                     | No                     | No
         v                        v                        v
+--------------------------------------------------------------+
|              自动重试 (带错误反馈, 最多 2-3 次)                  |
+--------------------------------------------------------------+
         | 通过校验                              | 重试耗尽
         v                                       v
+------------------+                    +------------------+
|   结构化数据对象  |                    |   兜底降级处理    |
|  (类型安全可操作) |                    |  (部分填充/人工)  |
+--------+---------+                    +------------------+
         |
         v
+------------------+
|   数据库入库      |
| - 完整保存原始结果 |
| - 质量标记        |
| - 索引支持查询    |
+------------------+

实战分析

任务一:设计行业分析结构体

行业分析是一个典型的结构化输出场景。你需要定义一个完整的行业分析数据模型。

设计思路

先确定分析维度。一个行业分析通常包含:行业基本信息(名称、简介、规模、增长趋势)、市场分析(目标客户、竞争格局、进入壁垒)、关键岗位列表、AI 机会列表。

然后确定每个维度的字段。行业基本信息需要行业名称(必填字符串)、行业简介(必填字符串,100-300 字)、市场规模(必填数字,单位亿元)、年增长率(选填数字,百分比)、发展阶段(必填枚举:初创期/成长期/成熟期/衰退期)。

注意事项

字段粒度要适中。不要把”市场规模”和”增长趋势”合并成一个字段叫”市场概况”,模型会在里面写一长段文字。也不要拆得太细——把市场规模拆成”国内市场规模”、“国际市场规模”、“线上市场规模”、“线下市场规模”会让模型很为难。

任务二:设计岗位分析结构体

岗位分析需要分析一个岗位的多个维度:岗位名称、所属部门、核心职责、KPI 指标、日常任务列表、使用的工具和系统、痛点列表、AI 机会列表。

设计思路

日常任务列表和 AI 机会列表是嵌套数组结构。每个任务是一个子对象,包含任务名称、频率(每天/每周/每月)、耗时(小时)、价值评级(高/中/低)、是否适合 AI 辅助。

这种嵌套结构要注意控制深度。任务对象内部不要再嵌套更深的结构了。AI 机会也类似——包含机会描述、推荐方式(Copilot/Agent/自动化)、预期效果,不要再嵌套更细的子结构。

任务三:设计 AI 机会评分结构体

AI 机会评分是对一个具体 AI 应用场景的多维度量化评估。

设计思路

评分维度参考 Day 5 学过的模型:高频程度、信息密度、人力成本、决策复杂度、数据可得性、付费意愿、落地阻力、风险等级。每个维度是一个 1-10 的评分。再加一个综合评分和优先级判定(高/中/低)。

每个评分维度需要配套一个评语字段(解释为什么给这个分),但评语字段设为选填——模型有时评得很好但解释不清楚,不要因为解释不好就判定整个输出失败。

注意事项

评分字段的约束要严格——必须是 1-10 的整数。模型偶尔会输出 0 或 11,需要在 Schema 中明确约束。

任务四:校验与重试机制

把上述三个结构体统一到一个校验-重试流程中。

设计思路

定义一个通用的”结构化调用函数”。输入是 Prompt 和对应的 Pydantic 模型类。函数内部:调用模型获取输出 解析 JSON 校验格式 Pydantic 校验 成功则返回校验后的对象 失败则带错误信息重试 超过重试次数则返回降级结果。

这个通用函数是结构化输出的核心组件。所有需要结构化输出的场景都通过它来调用模型,不需要每个场景单独写一套校验和重试逻辑。

当日产物说明

Structured Output Demo

一个完整的演示,展示结构化输出的完整流程。包含:定义三种 Pydantic 模型(行业分析、岗位分析、AI 机会评分);对每种模型进行一次成功的结构化输出演示;至少一次校验失败后自动修复/重试的演示;最终展示校验后的结构化数据对象。

Pydantic Schema 文件

一个 Python 模块,包含所有定义好的 Pydantic 模型。文件结构清晰——每个模型单独定义,相关的枚举类型集中定义,校验器独立定义。每个字段都有 Field 描述,每个模型都有 docstring 说明用途。

结构化输出测试记录

一份测试报告,记录至少 10 次结构化输出的测试结果。每次记录:输入内容摘要、模型输出是否合法 JSON、格式是否正确(字段名和类型是否匹配)、Pydantic 校验是否通过、如果不通过是什么原因、重试几次后成功。

这份记录的目的是让你直观感受到结构化输出的成功率——在合理的 Schema 设计下,成功率应该能达到 90% 以上。

常见误区与避坑

误区一:过度依赖 JSON Mode 而忽视 Prompt 设计

开启了 JSON Mode 就觉得万事大吉,Prompt 里不描述输出结构,让模型自己猜你要什么字段。JSON Mode 保证的是 JSON 格式合法,不是内容正确。模型可能输出一个字段名完全不对的合法 JSON。正确的做法是 JSON Mode + Schema 描述 + Prompt 中的格式说明,三管齐下。

误区二:JSON Schema 设计得太复杂

一上来就设计包含 30 个字段、5 层嵌套的 Schema。模型面对这种复杂结构很容易出错——不是漏了字段就是嵌套层级搞混了。先从最简版开始,确认模型能稳定输出后,再逐步增加复杂度。

误区三:校验失败就直接报错

Pydantic 校验失败就给用户抛一个 500 错误。很多校验失败其实是小问题——多了一个字段、某个可选字段类型不对。应该先尝试格式修复,修复不了再重试,重试不行再降级,给用户一个可用的结果而不是一个错误页面。

误区四:不考虑模型输出被截断的情况

Max Tokens 设置太低,模型输出一个不完整的 JSON。你尝试解析一个不完整的 JSON,直接报错。应该在解析前先检查 finish_reason——如果是 “length”,说明输出被截断了,可以增加 Max Tokens 后重试。

误区五:入库时丢掉原始输出

模型输出的 JSON 校验通过后,只把解析后的结构化数据存入数据库,原始 JSON 被丢弃。这是一个损失——原始 JSON 包含了模型输出的完整信息(包括你未来可能需要但目前没有提取的字段)。应该同时保存原始 JSON 和解析后的结构化数据。

延伸思考

结构化输出是 AI 应用从”能跑”到”可靠”的关键桥梁。

在今天之后,你应该养成一个习惯:任何需要被程序处理的模型输出,都通过结构化输出获取。不要用自然语言输出然后手动解析——那是一条越走越窄的路。

在后续的学习中,结构化输出会无处不在。Day 10 的 Function Calling 本质上也是一种结构化输出——模型输出的不是自然语言,而是一个函数调用指令(结构化的 JSON)。Day 11 的 Prompt 模板库中,每个模板都需要定义输出格式(JSON Schema)。Day 12 的后端接口,返回值就是基于结构化输出的数据。

更长远来看,Week 3 的 RAG 系统中,检索结果的格式是结构化的。Week 4 的 Agent 系统中,Agent 的每一步输出都是结构化的(计划、观察、决策、行动)。Week 5 的 Eval 系统中,评估标准本身就是一套 JSON Schema。

结构化输出还有一个深层价值:它强迫你在调用模型之前想清楚”我要什么”。设计 JSON Schema 的过程就是梳理需求的过程。很多人直接问模型”帮我分析一下这个行业”,得到一段模棱两可的文字后不知道怎么用。如果你先定义好”我需要哪些字段、每个字段什么类型、值在什么范围”,模型输出就能直接进入你的业务流程。

自测问题

  1. JSON Mode 保证的是什么?它和 JSON Schema 的约束有什么区别?
  2. 设计 JSON Schema 时,为什么字段名要有自解释性?举个例子说明。
  3. Pydantic 在结构化输出流程中扮演什么角色?它和 JSON Schema 的关系是什么?
  4. 什么类型的字段适合用枚举值约束?设计枚举值时需要注意什么?
  5. 为什么不应该把所有字段都设为必填?必填字段太多会导致什么问题?
  6. 格式修复的策略有哪些?它和内容修改的边界在哪里?
  7. 结构化输出重试时,为什么要”带反馈”重试?这比无脑重试好在哪里?
  8. 结构化数据入库时,为什么建议同时保存原始 JSON?
  9. 如果模型输出的 JSON 总是缺少某个必填字段,你应该怎么排查和解决?
  10. 从工程角度,为什么说”先设计最简版 Schema,逐步增加复杂度”是好策略?

关键词

  • JSON Mode:API 层面的输出模式,强制模型输出合法 JSON 格式
  • JSON Schema:定义 JSON 数据结构的规范语言,指定字段、类型、约束
  • Pydantic BaseModel:Python 数据校验库,用类型注解定义数据结构并自动校验
  • 字段约束:对输出字段施加的类型、范围、长度、枚举等限制
  • 枚举值(Enum):限定字段值只能从预定义的选项中选择
  • 必填字段(Required):结构化输出中必须出现的字段,缺失则校验失败
  • 格式修复:对模型输出的小型格式错误进行自动修正的预处理步骤
  • 自动重试:校验失败后带着错误反馈重新调用模型的机制
  • 结构化入库:将校验后的结构化数据存入数据库,保留原始输出
  • 降级处理:所有重试失败后的兜底方案,返回部分结构化或自由文本结果
  • ValidationError:Pydantic 校验失败时抛出的异常,包含详细的字段错误信息