从第1章自然走到第2章
路线12 章中的位置
本章目录
阅读过程中可按 Ctrl + Z 快速返回当前页面的本章目录;也可以点击右下角按钮。
本章思维导图
知识流向:先完成左侧基础,再进入中间机制,最后用右侧工程控制把它变成可上线能力。节点可直接点击跳转。
结构化数据基础
按照本模块顺序完成以下知识点,再进入下一模块。
S00结构化输出在 API 调用链中的位置
说明提取什么
传入 Schema
填写 JSON
解析与校验
查询或执行
response = 模型SDK.生成(
model = "支持结构化输出的模型",
messages = [用户的退款描述],
response_format = 退款意图Schema
)
result = 解析(response)
校验Schema(result)
校验订单数据库(result)
校验当前用户权限(result)谁设置:AI 应用工程师在后端代码中设置。何时生效:每次模型生成答案时。输入:Prompt 加 Schema。输出:符合指定外形的 JSON,或者拒答、截断、API 错误。
一定分清:Schema 约束“表单外形”,不会去订单数据库核对“表单内容是否真实”。
S01固定字段与结构化输出的必要性
“看起来像是退款问题,建议尽快处理,金额大概是299元。”
人能看懂,但程序不知道意图、金额和是否应建工单分别在哪里。
{
"intent": "refund",
"amount": 299,
"create_ticket": true
}表格类比:自然语言像顾客写的一段留言;结构化输出像填写固定表格。程序只有拿到稳定字段,才能继续查询订单、分配客服或创建工单。
S02用户语言到业务对象的转换
“鞋子小了,退掉”
提取与分类
intent=refund
再决定行动
模型擅长把模糊语言转换为固定字段;程序擅长检查字段并执行确定规则。成熟系统让二者各做擅长的部分。
S03JSON 数据格式基础
JSON 不是三个不同的东西。JSON 是一种把信息写成“程序容易读取的固定表格”的文本格式;JSON Mode 和 JSON Schema 是围绕 JSON 的两种控制手段。
人平常说的话
“订单 A10086 的顾客想退款,金额是 299 元,需要人工处理。”
人能看懂,但程序很难稳定判断哪一段是订单号、金额和处理方式。
同一信息写成 JSON
{
"order_id": "A10086",
"intent": "refund",
"amount": 299,
"need_human": true
}快递单类比:JSON 就是一张填写好的快递单。左边的 order_id、amount 是栏目名称;右边的 A10086、299 是实际填写的值。
| JSON 写法 | 小白解释 | 例子 |
|---|---|---|
{ } | 一整张信息表 | 一条订单信息 |
"字段名": 值 | 栏目名称和填写内容 | "amount": 299 |
| 字符串 | 文字,要放在双引号中 | "refund" |
| 数字 | 可以计算的数,不加引号 | 299 |
| 布尔值 | 只有真或假 | true / false |
null | 明确表示目前没有值 | "order_id": null |
S04JSON、JSON Mode 与 JSON Schema 的边界
| 概念 | 解决的问题 | 仍然不能保证 |
|---|---|---|
| 提示“请输出 JSON” | 只是文字要求 | 可能夹带解释、漏字段或格式损坏 |
| JSON Mode | 主要保证能解析成合法 JSON | 字段名、类型和业务含义一定正确 |
| JSON Schema | 约束对象结构、字段、类型、枚举和必填项 | 数据符合真实业务、当前状态和用户权限 |
Schema 是“表格模板”,不是“事实审计员”。它能要求金额必须是数字,却不知道真实退款金额到底是不是 299 元。
S05结构化输出的三层约束
“请填快递单”
保证像一张可读表
规定有哪些栏目
核对内容真假
JSON 是填好的表 | JSON Mode 保证表能打开 | Schema 规定表的栏目 | 业务校验核对内容真假
API 结构化输出
按照本模块顺序完成以下知识点,再进入下一模块。
S06结构化输出完整示例
顾客说:“订单 A10086 的鞋子小了,我想退掉,花了 299 元。”程序希望模型把这句话整理成固定字段。
这只是一句普通要求,类似经理口头说“请按表格交给我”。模型可能返回:
好的,整理结果如下:
{
"order_id": "A10086",
"intent": "refund",
"amount": 299
}
希望能帮到你。里面确实有 JSON,但前后夹着解释。只想读取 JSON 的程序可能因此解析失败。
这相当于规定:“只能交一张程序能打开的表,不准在前后写客套话。”模型会返回合法 JSON:
{
"dingdan": "A10086",
"what_to_do": "退货",
"money": "二百九十九"
}语法是合法的,程序可以打开;但字段名是模型临时想的,金额还是文字,可能与程序期待的字段不一致。
开发者提前规定空白模板:必须有 order_id、intent、amount;订单号必须是文字;意图只能是 refund、shipping 或 other;金额必须是数字。
模型按模板填写:
{
"order_id": "A10086",
"intent": "refund",
"amount": 299
}现在程序既能打开,也知道每个字段在哪里、是什么类型。
程序再去真实订单数据库核对:A10086 是否存在、是否属于当前用户、实付金额是否为 299、是否在退款期限内。只有这一步才开始判断内容在现实中是真是假。
JSON = 填好的具体表单 | JSON Mode = 保证表单语法能打开 | Schema = 事先规定空白模板和填写规则
S07JSON Schema 字段约束
{
"type": "object",
"properties": {
"intent": {
"type": "string",
"enum": ["refund", "shipping", "other"]
},
"order_id": {"type": ["string", "null"]},
"confidence": {"type": "number", "minimum": 0, "maximum": 1},
"need_human": {"type": "boolean"}
},
"required": ["intent", "order_id", "confidence", "need_human"],
"additionalProperties": false
}type
规定对象、字符串、数字、布尔值、数组或空值。
required
规定哪些字段不能缺失;字段允许为空和字段可以不出现是两件事。
enum
把分类结果限制在程序认识的固定集合中。
additionalProperties
禁止模型临时发明程序不认识的新字段。
业务结果校验
按照本模块顺序完成以下知识点,再进入下一模块。
S08可空字段与可选字段
字段存在,但值为 null
{"order_id": null}程序明确知道模型没有找到订单号。
字段完全不存在
{"intent": "refund"}可能代表允许省略,也可能是模型漏填;程序必须根据 Schema 判断。
工程建议:对于下游程序一定会读取的重要字段,通常让字段始终存在;未知时明确返回 null,比忽然消失更容易处理。
S09结构化配置位置与责任边界
“表格”只是类比。真实开发时,是你的后端程序通过模型厂商提供的 SDK 或 HTTP API 调用模型。开发者准备请求,模型生成响应,响应再回到你的程序。
准备 API 请求
响应格式
JSON 结果
再处理业务
JSON:通用数据格式,不是模型开关
JSON 不是 AI 独有的,也不是一个 API 参数。它是一种记录和传递数据的写法,可以出现在 API 请求和返回结果中。结构化输出讨论的是:让模型把答案用 JSON 格式交回程序。
{
"intent": "refund",
"order_id": "A10086",
"amount": 299
}JSON Mode:调用模型 API 时设置的响应格式选项
开发者调用模型时,除了传入模型名称和聊天消息,还可以选择希望模型用 JSON 格式返回。不同厂商和 SDK 的参数名称不同,下面是用于理解的伪代码:
response = 模型客户端.生成(
model = "某个模型",
messages = 聊天消息,
response_format = "json" // 在这次 API 调用中开启 JSON Mode
)| 问题 | 答案 |
|---|---|
| 谁设置? | 编写后端程序的 AI 应用工程师 |
| 放在哪里? | 调用模型 API 的请求参数中 |
| 何时生效? | 模型处理这次请求、生成答案时 |
| 返回什么? | 语法上可以被解析的 JSON |
| 仍可能怎样失败? | 字段名、类型或内容不符合业务需要 |
JSON Schema:开发者编写并随 API 请求传入的字段规则
开发者根据后续程序需要,先写出字段模板:
schema = {
"type": "object",
"properties": {
"intent": {"type": "string", "enum": ["refund", "shipping", "other"]},
"order_id": {"type": "string"},
"amount": {"type": "number"}
},
"required": ["intent", "order_id", "amount"]
}调用模型时,再把 Schema 放进结构化响应相关参数:
response = 模型客户端.生成(
model = "某个模型",
messages = 聊天消息,
response_format = {
"type": "json_schema",
"schema": schema
}
)模型生成时按 Schema 填字段;返回后,程序还可以用同一份 Schema 再检查一次。随后必须查询真实订单、检查权限和业务规则。
所在位置一句话:JSON Mode 和 JSON Schema 都是在“你的程序调用模型 API”时由开发者设置的;它们控制模型怎样把答案交回程序,不是用户界面的按钮,也不负责证明答案为真。
S10Schema 的 API 参数配置
首选:放在模型 API 专门提供的结构化输出参数里。不同厂商可能把它叫做 response_format、structured_output 或其他名称,具体写法看所用 SDK,但它属于请求配置,不是普通聊天文字。
System Prompt: 请返回 JSON,必须有 intent 和 amount, amount 必须是数字。
这只是自然语言要求。模型可能漏字段、改字段名或添加解释。
调用模型(
messages = [...],
response_format = {
"type": "json_schema",
"schema": schema
}
)模型服务把 Schema 当作结构化输出约束,通常比单纯写进 Prompt 稳定。
Prompt 还负责什么
Prompt: intent 表示用户真正想办理的业务; 只有明确要求退款时才填 refund; 没说金额就返回 null,不要猜。
Schema 负责什么
intent 必须是字符串,只能选 refund/shipping/other; amount 必须是数字或 null; 两个字段必须存在。
解释怎样判断
约束结果长相
事实、状态和权限
为什么有些教程把 Schema 写进 Prompt?可能是所用模型/API 不支持原生结构化输出,只能退而求其次;也可能是在补充字段的业务含义。API 原生支持 Schema 时,应优先使用专门参数。
S11模型 API 兼容性
截至 2026-09-15,下面这些主流平台的官方 API 已提供 Schema 结构化输出。这里列的是适合建立认识的主流系列,不应把它当作永久不变的完整名单;模型版本和接口会更新,写项目时仍要查看所选模型的官方能力页。
| 平台 | 当前能力示例 | 大致放置方式 |
|---|---|---|
| OpenAI | 当前 GPT 系列中支持 Structured Outputs 的模型;常见项目使用 GPT-5.x、GPT-4.1、GPT-4o 系列的相应 API 能力 | response_format/json_schema 或 Responses API 的结构化文本格式;严格模式只支持 JSON Schema 子集 |
| Google Gemini | 当前 Gemini 3.x,以及 Gemini 2.5 Pro、Flash、Flash-Lite 等系列的结构化输出接口 | 响应格式设为 JSON,并在 schema 字段传规则;支持 JSON Schema 子集 |
| Mistral | 提供 JSON Mode 与 Custom Structured Outputs | 自定义 Schema 作为结构化输出请求配置 |
| xAI Grok | 例如 Grok 4.6 的 Structured Outputs | response_format.type=json_schema,并传入 Schema |
| Cohere | Command A/A+、Command R/R+ 等官方列出的兼容系列 | Chat API 的 response_format;工具场景另有严格工具参数 |
同一厂商并非所有旧模型、实时语音模型、图片模型或每个端点都支持同一种 Schema 参数。选择模型时,不能只看模型名称,还要看“所用端点 + SDK 版本 + Structured Outputs 能力”。
“保证符合 Schema”究竟保证什么
- 返回是合法 JSON
- 必须字段存在
- 字段类型符合支持的规则
- 枚举值来自指定集合
- 通常不会凭空增加禁止的字段
- 用户意图一定识别正确
- 提取的金额一定是真实金额
- 订单一定属于当前用户
- 资料没有过期
- 这项操作有权限执行
用户说:“这个我不想要了。”
Schema 可以保证模型只能返回:
{"intent": "refund"} 或 {"intent": "other"}
但 Schema 不能保证模型一定选对 refund 还是 other。还要处理的例外:模型可能拒绝回答;响应可能因长度或网络中断而不完整;Schema 使用了厂商不支持的关键字时,请求可能报错;API 本身也可能超时或限流。因此程序仍要检查响应状态、解析结果和失败分支。
原生 Schema 提高“机器可读性” ≠ 消灭模型的理解错误
官方参考:OpenAI API · Gemini · Mistral · xAI · Cohere
S12五层结果校验
生成约束
语法解析
程序校验
事实检查
执行前复核
S13结构正确与业务正确的差异
{
"action": "refund",
"order_id": "A10086",
"amount": 99999,
"need_confirmation": false
}这段 JSON 可以完美通过语法和类型校验,但仍可能同时存在四个问题:
事实错误
订单实付只有 299 元。
对象错误
订单可能属于另一位用户。
状态冲突
订单可能已经退款。
流程违规
高额退款可能必须人工确认。
铁律:模型输出只能成为“业务操作候选”,不能直接成为“已批准的业务操作”。
S14结构校验与业务校验
结构校验
- 字段是否存在
- 类型是否正确
- 枚举是否合法
- 数字是否在基本范围内
回答:“数据长得合不合规?”
业务校验
- 订单是否真实存在
- 是否属于当前用户
- 金额是否匹配数据库
- 当前状态能否退款
回答:“这件事在现实业务中能不能成立?”
S15生产环境风险控制
你的判断是正确的:模型是概率系统,只要让它负责“理解用户意思”,就不可能仅靠 Schema 获得百分之百的语义正确率。高级工程的目标不是假装错误不会发生,而是让错误难以造成严重后果、能够被发现、可以恢复和追责。
低风险:可以直接自动化
改写语气、生成摘要、给客服推荐回复。即使偶尔分类错,通常不会直接改变用户资产。
中风险:校验后自动化
分配工单、选择知识库类别。结合必填字段、规则、置信阈值和异常监控;不确定就转人工。
高风险:模型只能提议
退款、转账、删数据、改权限。程序查询真实数据库、检查权限和状态,并要求用户或人工确认。
极高风险:确定性流程主导
医疗处置、重大金融操作等。模型只能辅助整理信息,不能成为最终审批者。
“用户想退款”
所有者与实付金额
期限·状态·额度
最后确认
真正执行一次
核心边界:模型可以识别“他可能想退款”,但退款金额不让模型猜,用户身份不让模型判断,能不能退不让模型拍板,真正执行也不让模型直接完成。
S16模型置信度的可信边界
模型输出的 confidence: 0.95 仍然是模型生成的数字,不是天然准确的概率。模型可能很自信地判断错。
只要模型自报置信度超过 0.9,就自动退款。
先用真实评测集检查这个分数是否可信,再结合信息完整性、数据库事实、固定规则、风险等级和人工确认。
例如在历史 1,000 个真实问题上,模型自报 0.9 以上的案例实际只有 82% 正确,那么这个分数就没有达到“90%正确”的含义,需要校准或调整流程。
S17置信分数的解释与校准
假设模型读完顾客的话后输出:
{
"intent": "refund",
"confidence": 0.95
}它表达的是:“我给自己的退款意图判断打了 0.95 分,我觉得很确定。”但这个数字可能只是模型根据语言生成的自评分数,并没有自动获得数学保证。
0.95 天然表示模型每判断 100 次就一定正确 95 次。
0.95 先只代表模型报出了一个很高的分数。它是否真的对应 95% 正确率,要用有标准答案的历史案例验证。
校准是怎样做的
人工标好答案的问题
并输出 confidence
的案例放一组
实际答对多少
举例:有 100 条问题,模型都给出了大约 0.95 的置信分数。人工核对后发现:
| 模型自报 | 案例数量 | 实际答对 | 结论 |
|---|---|---|---|
| 约 0.95 | 100 条 | 95 条 | 这个分数比较可信,校准较好 |
| 约 0.95 | 100 条 | 82 条 | 模型过度自信;0.95 实际只对应约 82% 正确率 |
重要:即使真的达到 95% 正确,也意味着平均每 100 次仍可能错 5 次。用它自动给工单分类也许可以接受,但自动退款风险仍然太大,所以高风险操作还必须查数据库、走固定规则并人工或用户确认。
校准 = 比较“模型声称多确定”和“历史上实际上多正确”
S18校验失败处理策略
| 失败类型 | 推荐处理 | 例子 |
|---|---|---|
| 轻微格式问题 | 在可信边界内程序修复,或让模型有限重试 | 多余空格、可明确纠正的格式 |
| 缺少必要信息 | 向用户追问,不要猜 | 退款请求没有订单号 |
| 模型理解不确定 | 降级到人工或安全默认流程 | 意图置信度过低 |
| 业务规则不满足 | 拒绝执行并说明原因 | 退款金额超过实付金额 |
| 高风险操作 | 人工确认或确定性审批 | 大额退款、删除数据 |
| 服务暂时失败 | 有限重试,仍失败则降级 | 模型超时、429 |
不要无限重试。模型连续收到相同信息,可能连续犯相同错误,只会增加延迟和费用。
S19JSON 修复的安全边界
有些系统会在解析失败后,再让另一个模型把坏 JSON 修好。这可以处理格式问题,但不能偷偷改变业务含义。
原输出没有金额,修复模型自己补成 299。
保留原含义,只修复明确的括号、引号或字段包装;修复后仍重新校验。
涉及钱、权限、身份、医疗或法律信息时,缺失字段通常应该追问或拒绝,而不是自动猜补。
S20完整结构化输出链路
和 Schema
候选数据
结构校验
业务校验
拒绝 / 人工
可靠结构化输出 = 受约束的生成 + 确定性的程序校验 + 安全的失败处理
S21结构化输出工程原则
- 给人看的内容可以自然语言;给程序使用的内容要结构化。
- “请输出 JSON”只是提示,Schema 才能明确字段契约。
- JSON Mode 主要保证语法,Schema 主要保证结构,两者都不能证明业务事实。
- 模型输出是候选数据,而不是数据库真相或操作授权。
- 先做结构校验,再做业务、权限和实时状态校验。
- 缺少关键事实时追问,不要让模型猜补。
- 重试必须有上限,高风险操作必须走确定性规则或人工确认。
- 日志要记录原始输出、校验错误、重试次数和最终处理方式,便于以后回放。
本章总结:从哪里来,解决什么,为什么继续
下一章
第 03 课:Embedding、向量与语义检索基础
会用“在地图上找附近商店”的类比,详细解释向量、维度、余弦相似度、语义检索、关键词检索,以及向量数据库为什么能找到“意思相近但文字不同”的内容。