AI 课堂

结构化输出与校验:JSON 正确不等于内容正确

2026-09-17

本课结构 点击折叠
  1. 一句话定义
  2. 生活化类比(建筑行业版)
  3. 本质与能力边界
  4. 实战演练:一条问题数据过关的全过程
  5. 建工案例:台账入库的四道闸
  6. 供应商话术拆解
  7. 常见问答
  8. 自测
  9. 概念卡片
  10. 延伸阅读

从“模型说了什么”到“系统能用什么”,中间隔着三层格式约束和一层业务校验。分清它们,才算真正入门 AI 应用。

本课回答的业务问题:为什么模型输出的 JSON 不能直接入库?JSON mode、严格 Schema、程序校验分别保证什么、不保证什么?

前置课程:第 1 课(提示工程)。

读完本课你将能够

  1. 分清“提示词要求 → JSON mode → 严格 Schema → 业务校验”四层各自保证什么、不保证什么;
  2. 以“字段名: 值”的填表方式读懂 JSON 输出,核对字段、类型与状态标注,不需要任何编程基础;
  3. 为合同台账写出四类业务校验规则:数值范围、枚举合法、逻辑一致、引用回查;
  4. 说清一条数据从模型输出到入库要过的四道闸,以及每道闸各拦什么错;
  5. 识破“无需人工干预即可入库”的话术,向供应商问出关键问题。

一句话定义

结构化输出指让模型按预定的数据结构(通常是 JSON)返回结果。约束分三层:提示词要求(文本约束)→ JSON mode(保证可解析)→ 严格 Schema(保证字段与类型);三层都只管“格式”,不管“事实”——金额对不对、原文有没有,靠业务校验。

这句话拆开有三层意思:

  • “预定的数据结构”就是填表。自由文本像一段情况说明,结构化输出像一张填好的表——每个值前面有字段名(“预付款比例: 20”),程序才能按字段名取值、入台账、做汇总。JSON 只是这种“字段名: 值”表格的通用写法:一行一个字段,大括号圈住一张“表”,方括号圈住一“组”并列条目,null 表示“空、未提及”。看到 JSON 不必想编程,想填表就够了。
  • 三层约束逐级收紧。第一层在提示词里写“只输出 JSON、字段如下”,是约定意图——模型通常照办,但没有强制力;第二层 JSON mode 是接口开关,承诺“吐出来的内容一定能被解析成 JSON”;第三层严格 Schema 把字段名、类型、必填项逐项锁死,多一个字段、类型不对都过不去。一层比一层硬,但全停在格式层。
  • “只管格式、不管事实”是本课总纲。格式指结构合法——系统能不能把它读进来;事实指内容正确——数字对不对、引用的原文存不存在。三层约束的极限是“结构合法”,事实正确一寸都不保证。分不清这条线的人,会把“Schema 校验通过”当成“数据没问题”,把编造的数据放进台账——这正是本课要防的事故。

生活化类比(建筑行业版)

三层格式约束像工程验收的三个层级:

层级 类比 保证什么 不保证什么
提示词写“返回 JSON” 图纸说明里写“按表格式填报” 约定意图 承包商可能漏填、错填、夹带说明文字
JSON mode 收标书时先查“是不是 PDF、有没有盖章” 文件可解析 内容对不对页、数字对不对不管
严格 Schema 清单计价规范校验:字段名、单位、类型逐项核对 结构与类型合法 单价是不是填错了、量是不是虚的不管
业务校验 造价工程师复核:单价与市场价比、合价重算 内容合理 ——

标书格式完全合规,不代表没有围标——JSON 同理。

类比成立在哪:第一,四层各自“只查自己那层”——收标员不核单价,清单校验不管量虚不虚,造价复核不管格式;JSON 流水线同样分层设卡,每道闸只拦自己职责内的错,越层的错它看不见。第二,层级越深问题越隐蔽、代价越大——格式错在门口就被退回,一分钟重报;内容错要等结算甚至审计才发现,代价翻着倍涨。JSON 同理:解析失败当场重试,编造的依据可能安静地躺台账里半年。

类比失效在哪:造价工程师的复核有法定职责和执业签字,错了要担责;业务校验只是你程序里的几条规则——规则写漏了没人兜底,所以规则清单本身要评审、要维护,别指望它有“执业本能”。另外,人工复核的标准会随经验自然生长,程序校验是机械执行:写进代码的规则才存在,没写的永远不查——别高估它,也别忘了它只有你写的那么多。

本质与能力边界

1. 三层格式约束:一层比一层硬,但全停在格式层

提示词层:在提示词里规定输出结构,价值是把口径写清(null 什么时候用、“未提及”和“明确无”怎么分)——这是后面两层表达不了的业务语义。但它没有强制力:模型偶尔会在 JSON 前后垫一句“好的,以下是抽取结果”,或自作主张加一个你没要的字段。这一层管的是“约”,不是“保”。

JSON mode:接口开关,承诺输出按 JSON 语法生成——系统拿到手不会因为格式散架而读不了。它只管“成文”,不管字段:返回的内容可以字段名全错、可以是空壳,只要语法上是合法 JSON,它就放行。注意这个承诺有个前提:输出完整。中途被截断的半截 JSON 照样散架(见下面第 3 节),所以实际系统里这一层要配“解析检查+失败重试”当闸用,不能开了开关就当万事大吉。

严格 Schema:接口能力,把字段名、类型(数字/文字/一组值)、必填项逐项锁死,多余字段拒绝、类型不符拒绝,大幅降低解析失败和字段错位。但到“结构合法”为止——Schema 合格不保证事实正确:字段类型全对,金额照样可能错,“依据”里引用的原文照样可能不存在。

一句话记住三层的分工:第一层定口径,第二层保成文,第三层锁结构——三层叠满,也只是保证“这张表填得规整”,不保证“这张表填得对”

再补一个机制直觉,回答很多人追问的“严格 Schema 凭什么能锁死”:它不是生成完再检查,而是生成过程中就动手——模型每写下一个字符,系统先把“写下去就接不上 Schema”的候选字符全部禁掉,只放行接得上的。所以它对结构的强制是硬约束,不存在“模型偶尔不听话”;但也正因为同一个机制,它对内容完全无能为力——“20”和“200”在 Schema 眼里同样合法,都只是“一个数字”。结构上的铁面无私和内容上的不管不问,是同一条机制的两面。

2. 业务校验是应用自己的责任:四类规则

格式三层是通用能力,业务校验是写在你自己系统里的规则,供应商和模型厂商都替不了你——因为规则本身就是你的业务口径:

  • 数值范围:比例必须在 0–100、金额非负、日期不晚于竣工日期。拦的是“数字合法但数值离谱”——预付款比例 200,Schema 只确认“它是个数字”,不管它多大;
  • 枚举合法性:“状态”只能取正常/未提及/含糊待复核/冲突四值之一,出现第五种即非法。拦的是模型自造词汇;
  • 逻辑一致性:状态为“冲突”时必须同时存在两条依据;付款节点比例合计不应超过 100。拦的是“每一格都对、合在一起不对”。算个例子:预付款 20%+进度款合计 85%+质保金 5%=110%——三个数字各自都在 0–100 内,范围规则全部放行,只有合计校验抓得到;
  • 引用回查:把“依据”字段里的引用文字放回输入材料逐字查找,查不到即标“证据存疑”。四类里性价比最高的一道——规则最简单(本质是文字精确匹配),拦的错最致命:模型编的数字可以碰巧合理,编的“原文”必然在原文里找不到。这一条能拦住大部分编造。

3. 错误路径要设计:拒绝、截断、报错都不是意外

模型可能拒绝回答(判断无法完成或触发安全策略)、输出中途被截断(超长输出被切断,半截 JSON 必然解析失败)、接口直接返回错误码。这三种情况不是“万一”,是放量之后每周都会遇到的日常。系统对每种情况的兜底是什么——重试几次、何时转人工、失败记不记日志——必须在上线前设计好。把“拿到响应就当成功”写进流程,等于把事故写进代码:半截 JSON 会让程序崩溃或灌入脏数据,一次拒绝可能被当成“该合同无付款条款”安静入库。

4. 入库前双保险:格式层+内容层,谁也不能替谁

格式层交给 Schema(自动、全量检查),内容层交给业务校验(规则自动)+抽样人工复核(抽一部分人看)。两者都不能省:省了格式层,脏结构入库,下游程序天天报错;省了内容层,格式完美的编造数据安静入库——后者更隐蔽、代价更大。抽样比例按风险定:物料名称类低风险字段抽查即可,金额、比例类高风险字段建议逐条人工终审(本课程统一口径:AI 辅助初审、人做终审)。

一句话记住这条流水线:模型负责填表,程序负责核表,人负责拍板。

实战演练:一条问题数据过关的全过程

场景(虚构):青柏项目 300 份合同付款台账的入库流水线已按四道闸搭好。现在盯一条最容易出问题的数据走完全程——补充协议 QB-HT-01-补:预付款 30%,与主合同 20% 冲突(贯穿案例口径)。

输入材料(虚构节选):主合同“签约后支付合同价款的 20% 作为预付款”;补充协议“预付款比例调整为合同价款的 30%”。

第 1 道:提示词口径。抽取提示词(上一课的 v2)规定:比例用 0–100 数字或 null、冲突双口径上报、依据逐字引用。模型第一次输出(示意):

{
  "合同编号": "QB-HT-01-补",
  "预付款比例": "30%",
  "状态": "正常"
}

两个问题:比例写成了带引号的“30%”(文字,不是数字);冲突漏报。提示词是君子协定,偶尔会被违反——这一道的价值是让大多数输出天生规整,拦不住的交给后面。

第 2 道:JSON mode。检查整段输出能否被完整解析为 JSON——没有夹“以下是结果”之类的说明文字、没有中途截断。本次通过。这一道拦的是“输出成文失败”:解析失败自动重试一次,仍失败转人工。

第 3 道:Schema 校验。逐项核对:合同编号是文字、预付款比例必须是数字或 null、状态只能是四个枚举值之一。“30%“在这里被拦下——类型不符,退回重试(附上错误信息让模型修正)。重试后的输出:

{
  "合同编号": "QB-HT-01-补",
  "付款方式": "银行转账",
  "预付款比例": null,
  "付款节点": [
    {"触发条件": "进度款:按月计量", "支付比例": "已完工程量的 80%"}
  ],
  "违约金条款": "按每日未付款项的 0.03% 支付违约金",
  "冲突明细": [
    {"来源": "主合同 QB-HT-01", "比例": 20,
     "依据": "签约后支付合同价款的 20% 作为预付款"},
    {"来源": "补充协议 QB-HT-01-补", "比例": 30,
     "依据": "预付款比例调整为合同价款的 30%"}
  ],
  "状态": "冲突"
}

这次字段名、类型、枚举全部合规,且没有 Schema 之外的字段(严格 Schema 下,模型想临时加塞一个没登记的字段同样过不了)——放行到第 4 道。

第 4 道:业务校验。规则逐条跑:范围——冲突明细里 20 和 30 都在 0–100 内,通过;逻辑——状态为“冲突”时必须存在至少两条依据,通过;引用回查——把两条“依据”放回输入材料逐字查找,两句都命中,通过。这道闸要拦的典型:引用的句子在原文里根本不存在,或被模型改写(“20%“写成”百分之二十”)——查不到就标“证据存疑”转人工。

入库结果:四道全过,写入台账,状态“冲突”,进入人工终审队列。注意这条数据“过关”的准确含义:系统确认它结构合法、证据真实、状态如实;但 20% 还是 30% 的业务判断,从头到尾都是人的活。

再补一个诚实的盲区:假如重试后模型把冲突漏了——比例填 30(数字,类型对)、状态“正常”(枚举值,合法)、依据真实存在——四道闸会全部放行。校验拦得住“报了冲突没证据”,拦不住“该报冲突而没报”;前者靠闸,后者靠第 1 道的口径规则和抽样复核。这就是“双保险谁也不能替谁”的具体含义。

建工案例:台账入库的四道闸

青柏项目(虚构)把 300 份合同的付款信息抽取入台账,流水线四道闸(单条数据的完整走查见上文实战演练):

  1. 第 1 道(提示词):字段口径写清——比例用 0–100 数字或 null;“未提及”不填 0;
  2. 第 2 道(JSON mode):解析失败自动重试一次,仍失败转人工;
  3. 第 3 道(Schema):类型锁定——预付款比例: number | null付款节点: array
  4. 第 4 道(业务校验):比例范围校验、节点比例合计校验、依据原文回查(在原合同文本中逐字查找,找不到即标记“证据存疑”)。

放量结果(虚构示例数字,仅示意数量级):300 份中,第 2 道拦下 11 次(多为超长合同的输出截断),重试后 9 次通过、2 次转人工;第 3 道拦下 6 次(类型不符),全部重试通过;第 4 道拦下 4 次——3 次是依据被改写,1 次是拼错位:JSON 完全合法,“预付款比例: 20”,但依据引用的条款在原文中不存在——模型把两份合同的条款拼错了位。没有引用回查,这个错误会安静地躺进台账。另有 5 份状态为“冲突”(主合同 20% 对补充协议 30%,贯穿案例口径),连同 4 次“证据存疑”一起进入人工终审队列——9 条内容终审,加上第 2 道转来的 2 条,人工共处理 11 条,占比约 3.7%。这 3.7% 就是“无需人工干预”话术在真实项目里的真实答案。

供应商话术拆解

话术:“我们支持严格 Schema 输出,数据可直接入库,无需人工干预。”

拆解四问,以及合格回答应该长什么样

  1. Schema 只保证结构——内容错误率有多少,怎么发现的?——合格回答能给出内容层的指标和测法:拿标注好的样本集测过,编造率、改写率是多少,靠什么发现(校验规则+人工抽查双轨)。只复述“Schema 很严格”,是把格式层当内容层卖;
  2. 引用回查做了吗?金额、单位、日期的校验规则有哪些?——合格回答能列出规则清单(范围、枚举、逻辑一致、原文回查),并说明查不到时怎么处置(标存疑、转人工)。没听过“引用回查”四个字的供应商,产品里多半也没有;
  3. 拒绝、截断、超时的处理流程是什么?——合格回答有明确的错误路径:重试几次、何时转人工、失败留不留痕。“这些情况很少见”不是流程,是没设计;
  4. “无需人工”的口径是低风险字段还是全部字段?——物料名称抄录和预付款比例终审能同日而语吗?合格回答会主动划出建议保留人工复核的高风险清单;把“全部免人工”当卖点,要么没跑过真实数据,要么准备让你自己发现。

合格回答的共同样子:分层承认边界——格式层敢承诺(Schema 可验证),内容层给数据(错误率与发现机制),高风险字段建议留人。能把三层责任一口讲清的回答,才值得继续谈。

常见问答

Q1:JSON 到底是什么?我要先学编程吗? 不用。JSON 就是“字段名: 值”一行一项的通用填表格式:大括号是一张表,方括号是一组并列条目,null 是“空、未提及”。你要会的只是像核对台账一样核对字段和值——本课所有 JSON 都按这个读法处理。

Q2:有了严格 Schema,提示词里还要写输出格式吗? 要。两者分工不同:Schema 锁“形”(字段名、类型),提示词定“义”(null 什么时候用、“未提及”和“明确无”怎么分、依据怎么引用)。没有口径的 Schema 只能保证表填得规整,保证不了表填得对。

Q3:引用回查会不会误伤?模型把“20%“改写成”百分之二十“就会被拦。 会拦,而且应该拦——被改写过的引用已经不是证据。处置方式:查不到就标”证据存疑“转人工,人工核对原条款无误的可以放行。宁误拦、不漏放:误拦的代价是一条人工复核,漏放的代价是编造入库。

Q4:模型输出到一半断了(截断),怎么处理? 截断的 JSON 必然解析失败,在第 2 道被拦下——所以错误路径要提前设计:自动重试一次,仍失败转人工。根本缓解是长合同分段抽取、输出字段精简,别让模型一口气吐长文。

Q5:校验规则应该由谁来写? 业务口径由业务定:null 的含义、比例范围、冲突的处理,是合约、法务的知识;程序实现交给开发。你的角色是把口径写成明确的规则清单——“比例必须是 0 到 100 的数字”能变成代码,“比例要合理”变不成。

Q6:让模型输出一个“置信度”字段,低于 90% 的转人工,行不行? 不建议依赖。模型自报的置信度是生成出来的文字,不是仪器读数——它会自信地错。可靠的分层靠外部校验(范围、引用回查)和抽样复核,不靠它的自我感觉。

Q7:台账里 null 太多,是不是抽取失败了? 先分清状态:null+“未提及”是诚实的结果(合同确实没写);null+“待补”是材料缺口(附件没归档);只有“抽取失败”才是技术问题。null 多,说明的是合同和档案的真实状况——把它当发现,别当失败。

Q8:我要的明明是 Excel 台账,为什么不直接让模型填 Excel? 因为 Excel 是给人看的呈现层,JSON 是给程序交接的中间层。模型输出 JSON,程序校验通过后由程序转成 Excel、写入数据库——转换是机械的、零出错的;让模型直接操作 Excel 或数据库,等于跳过全部校验闸,还把格式的自由度(合并单元格、多表头)交给模型自由发挥。记住分工:模型产出结构,程序负责搬运和落库。

自测

抽取结果 JSON 完全符合 Schema,但两个问题:①“预付款比例”填了 200;②“依据”引用的条款号在原文中不存在。分别该在哪一层拦住?怎么拦?

参考要点(先自己作答,再展开对照)
  • 比例 200:业务校验层拦——数值范围规则(0–100)。推理:Schema 的承诺只到“这个字段是数字”为止,200 是完全合法的数字,三层格式约束全部放行;“数字多大才合理”是业务口径,只有应用自己的范围规则知道。
  • 条款号不存在:引用回查拦——把“依据”字段的引用内容放回输入原文逐字查找,查不到即标“证据存疑”、退回人工。它拦的正是“格式全对但内容编造”,恰好是 Schema 的盲区。
  • 共同点与结论:两个错误都格式合法,说明三层格式约束到“结构合法”为止,事实正确必须靠业务校验加抽样复核,双保险缺一不可。
  • 优先级建议:先做引用回查——实现最简单(文字精确匹配),能拦住大部分编造型错误;范围、枚举、逻辑规则随后补齐。

概念卡片

名词 一句话定义
JSON mode API 功能:保证输出可解析为 JSON,不约束字段内容
严格 Schema API 功能:按定义锁定字段名与类型,拒绝越界结构
业务校验 应用侧规则:范围、枚举、逻辑一致性、引用回查
引用回查 把模型给的“原文依据”放回输入材料逐字核对,拦截编造
错误路径设计 拒绝、截断、报错的兜底流程,上线前必须定义
格式 vs 事实 格式三层的极限是“结构合法”,事实正确靠校验与复核

延伸阅读

  • 参考:OpenAI Structured Outputs,核验于 2026-09-16。各平台对严格 Schema 的支持程度不同,接入时查当时文档。
  • 下一课:结构解决了“单次输出”,多轮任务里“喂什么给模型”是另一门功夫——上下文工程。

← 课程目录