结构化输出的三层校验
结构化输出不是“模型返回了 JSON”这么简单。解析器只回答字符串是不是合法 JSON;schema 校验回答字段和类型是否符合接口;业务校验还要检查范围、权限、对象存在和跨字段不变量。三层应分别记录失败原因,不能把所有错误都重新发送给模型。
第一个可运行实验:语法、结构和业务分层
使用 Python 3.12 保存 contract.py,运行 python contract.py。示例只使用标准库,业务规则是订单数量必须为正,折扣订单必须有原因。
python
import json
def validate(raw):
try:
data = json.loads(raw)
except json.JSONDecodeError:
return 'syntax_error'
if not isinstance(data, dict) or not isinstance(data.get('quantity'), int):
return 'schema_error'
if data['quantity'] <= 0:
return 'business_error:quantity'
if data.get('discount', 0) > 0 and not data.get('reason'):
return 'business_error:reason'
return 'ok'
assert validate('{"quantity": 2}') == 'ok'
assert validate('{"quantity": }') == 'syntax_error'
assert validate('{"quantity": "2"}') == 'schema_error'
assert validate('{"quantity": -1}') == 'business_error:quantity'
assert validate('{"quantity": 2, "discount": 1}') == 'business_error:reason'
print('validation layers passed')流式 JSON 可以先作为草稿展示,但只有缓冲区闭合、解析成功、schema 和业务校验都通过后,才允许写库、发通知或触发下一次工具调用。null、缺少字段和空字符串可能代表三种不同含义,应在契约中明确。
变体实验
把 quantity 改成 0、浮点数和超大整数;分别说明它们属于业务错误、schema 错误还是需要额外的范围规则。再加入 currency 与 amount,禁止金额为负,并写出跨字段校验。
练习
- 为结果增加
schema_version,日志中同时记录模型版本和 schema 版本。 - 让校验返回结构化错误列表,而不是只返回一个字符串。
- 设计截断响应的状态,确保它不会被当成空对象提交。