结构化输出与校验
让模型输出 JSON,并在进入业务逻辑前检查格式与语义。
学完这一课,你将能够
- 设计一个最小输出契约
- 校验字段类型、范围与额外字段
- 处理非法输出而不是默默修补
学习目标
- 为模型输出设计一个最小契约。
- 区分 JSON 解析、类型校验和业务校验。
- 在输出不合法时提供明确的错误分支。
前置要求:理解 Python 字典、JSON 和异常。 本节所有代码使用标准库,完全离线运行。
结构化不等于正确
下面两个输出都可能是合法 JSON:
{ "category": "billing", "summary": "重复扣费", "needs_clarification": false }{ "category": "unknown", "summary": 42, "needs_clarification": "no" }只有第一个符合上一课的字段契约。 即使格式和类型都符合,摘要仍然可能捏造事实。 因此要把检查分成三层:语法、结构、语义。
先写最小 Schema
JSON Schema 可以被服务端校验器使用;部分模型服务也支持以它约束输出。 具体支持的关键字和严格模式限制要查所选服务当前文档。
{
"type": "object",
"properties": {
"category": { "type": "string", "enum": ["billing", "technical", "other"] },
"summary": { "type": "string", "minLength": 1, "maxLength": 40 },
"needs_clarification": { "type": "boolean" }
},
"required": ["category", "summary", "needs_clarification"],
"additionalProperties": false
}字段越多,需要满足的条件越多。 如果下游只需要类别和摘要,不必让模型输出十几个无用字段。 新增字段时要考虑旧数据如何迁移,并记录契约版本。
不依赖第三方包的完整校验器
以下代码手工校验本例契约,不是通用 JSON Schema 实现。
保存为 validate_output.py 并运行。
import json
def validate(raw):
try:
data = json.loads(raw)
except json.JSONDecodeError:
return {"ok": False, "error": "invalid_json"}
required = {"category", "summary", "needs_clarification"}
if not isinstance(data, dict) or set(data) != required:
return {"ok": False, "error": "invalid_fields"}
if data["category"] not in ("billing", "technical", "other"):
return {"ok": False, "error": "invalid_category"}
if not isinstance(data["summary"], str):
return {"ok": False, "error": "invalid_summary_type"}
if not 1 <= len(data["summary"].strip()) <= 40:
return {"ok": False, "error": "invalid_summary_length"}
if type(data["needs_clarification"]) is not bool:
return {"ok": False, "error": "invalid_boolean"}
return {"ok": True, "value": data}
samples = [
'{"category":"billing","summary":"重复扣费","needs_clarification":false}',
'{"category":"billing","summary":42,"needs_clarification":false}',
'{"category":"other","summary":"待确认","needs_clarification":"yes"}',
'这段话不是 JSON',
]
for sample in samples:
print(validate(sample))预期第一条通过,后三条分别报告类型、布尔字段和 JSON 语法错误。 把这些错误码保存进日志,比把原始内容全部展示给最终用户更容易统计。
不要悄悄把错误转换成成功
把字符串 "false" 转成布尔值,很可能得到你不期望的结果。
直接删除未知字段,也可能掩盖契约已经变化的问题。
根据场景明确选择拒绝、有限次纠正请求或交给人工检查。
如果使用纠正请求,只发送需要修正的字段与校验错误,并设置最多一次或两次。 纠正后仍要重新校验,不能假设第二次一定正确。 预算耗尽时返回“无法生成符合格式的结果”,而不是无限循环。
语义检查留在哪里
摘要是否忠实于原文,不能仅靠 JSON Schema 判断。 可以用固定规则检查关键数字、使用人工标注的评估集比较,或增加独立审核步骤。 涉及工具执行时,权限、账户归属和余额等条件必须由可信业务系统验证。 模型给出一个合法的账户 ID,不代表它有权访问该账户。
练习与验收
增加五个输入:空摘要、额外字段、缺失字段、JSON 数组、超过 40 字的摘要。 为每个输入写出预期错误码,再运行程序核对。
- 有效对象可以进入后续业务逻辑。
- 非法对象不会被默默修补后执行。
- 错误结果保持统一结构。
- 能说出一种“格式正确但事实错误”的例子。
延伸阅读
下一课会讨论模型应该看到多少资料,以及如何选择相关上下文。
让这一课,真正成为你的收获
完成练习后标记完成,也可以随时回来复习。
笔记与进度保存在当前浏览器,无需登录