Schema、分层校验与错误修复
分类、抽取和命令需要不同契约
分类返回封闭枚举,抽取允许未知,转换保留原信息,命令则要表达具体副作用。若把抽取结果直接作为命令执行,会把“文字里提到购买”误当成“用户已授权购买”。先定义结果的用途,再定义字段。
JSON Schema 的 properties 描述字段,required 指定键必须出现,additionalProperties 控制额外键;null 是合法值的一种,不能与缺键混淆。default 通常是注解,不保证校验器自动补值。Python 类型注解与 TypeScript 接口不会自动校验网络输入。
在 Python 3.12 空目录建立环境:
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install 'jsonschema>=4,<5'
python -m pip freeze > requirements.lock保存 validate.py,运行 python validate.py。这是真实 JSON Schema 校验器实验,不调用模型。
import json
from jsonschema import Draft202012Validator
schema={'type':'object','properties':{
'sku':{'type':['string','null']},
'quantity':{'type':'integer','minimum':1,'maximum':5}},
'required':['sku','quantity'],'additionalProperties':False}
Draft202012Validator.check_schema(schema)
v=Draft202012Validator(schema)
def parse(raw):
data=json.loads(raw)
v.validate(data)
if data['sku'] is None:raise ValueError('need sku before ordering')
return data
assert parse('{"sku":"A","quantity":2}')['quantity']==2
for raw in ['{"sku":"A","quantity":0}',
'{"sku":"A","quantity":true}',
'{"quantity":2}',
'{"sku":"A","quantity":2,"admin":true}']:
data=json.loads(raw)
assert not v.is_valid(data)
assert v.is_valid({'sku':None,'quantity':2})
print('schema contract passed')最后一个对象结构有效,但不能下单,因为 SKU 未知。这说明结构校验与业务状态有不同职责。语法错误由 json.loads 报,结构错误由校验器报,业务缺信息由应用报;三者不能统一包装成“请再试一次”。
有界修复而非无限纠错
格式错误可把结构化错误路径反馈模型一次,例如 quantity 应为整数。不要把包含密钥或用户私密资料的整个异常栈发回模型。权限失败不能靠“让模型换一个参数”修复;业务未知应向用户补充信息。截断需重新分配预算或缩短任务,手工补右括号可能把半个对象变成错误完整对象。
原生结构化输出支持的是平台规定的 JSON Schema 子集,不能把本地校验器支持全部关键字推断到模型平台。跨平台 schema 最好保留一份业务完整版,再为平台生成受支持约束;最终仍回到本地完整版校验。
参阅 JSON Schema 对象 和各供应商结构化输出课程。
练习
添加字段 confidence,允许 number 或 null,并要求它出现;非 null 时只能在 0 到 1 之间。验证 0、1、null 合法,-0.1、1.1、true 非法。
先记录自己的输出与解释,再核对本章答案。