AI 返回了合法 JSON,为什么还要用 JSON Schema 检查
JSON 能解析,只能说明语法正确。用 Python jsonschema 检查必填字段、类型、枚举与额外字段,再把格式错误和业务错误分开处理。
文章目录
让 AI 从工单里提取编号、优先级和摘要,返回内容能被 json.loads 读出来,仍可能不能直接入库:编号少了一位,优先级写成自由文本,或者多出了调用程序没准备接收的字段。解析 JSON 和接受业务数据之间,需要一道明确的校验。
把输出约定写成 Schema
以下工单结构是示例。安装 Python 的 jsonschema 库后,将代码保存为 validate_ticket.py。虚拟环境可避免改动系统 Python:
python3 -m venv .venv
. .venv/bin/activate
python -m pip install jsonschema
Schema 中把编号、优先级和摘要设为必填,并拒绝未约定的字段:
import json
from jsonschema import Draft202012Validator
schema = {
"type": "object",
"properties": {
"ticket_id": {"type": "string", "pattern": "^T-[0-9]{6}$"},
"priority": {"enum": ["low", "normal", "high"]},
"summary": {"type": "string", "minLength": 1, "maxLength": 200}
},
"required": ["ticket_id", "priority", "summary"],
"additionalProperties": False
}
Draft202012Validator.check_schema(schema)
validator = Draft202012Validator(schema)
raw = '{"ticket_id":"T-000123","priority":"urgent","summary":"无法登录"}'
item = json.loads(raw)
for error in validator.iter_errors(item):
print(list(error.absolute_path), error.message)
这组输入的 priority 不在枚举中。properties 只声明字段规则,不自动要求字段出现,所以还需要 required;只写 type: object 也不会禁止未知字段。正则两端的锚点用来限制整个编号,避免只匹配字符串中间一段。
分清三种失败
如果 json.loads 抛出异常,是语法或包装问题,例如回复外面多了一段说明。Schema 校验失败,则属于缺字段、类型不符或取值超出约定。两者都应在入库前拒绝,不要把“urgent”悄悄改成“high”,除非产品规则明确允许这种映射。
第三种更隐蔽:格式全部通过,但工单编号不存在,摘要也没有准确反映原文。Schema 不能判断这些事实。程序还要查询编号、核对权限、保留原始工单与提取结果之间的关系。让模型输出一个合法结构,不等于获得了正确结论。
对于日期、邮箱等 format,也别只写关键字就假定库会检查。jsonschema 的格式检查需要显式启用相应 FormatChecker,有些格式还依赖额外安装项。没有需求时,优先使用容易核对的类型、枚举和长度规则。
重试要有边界
可以把“priority 必须属于哪三个值”这类结构错误交回模型修正,并限制次数。每次保留原回复、错误位置和修正回复,超过上限进入人工队列。不要把异常原文连同密钥、内部路径或整份客户材料原样拼进重试提示。
收到结果后先校验,再计算、写库或调用工具。代码中的 Schema 也应纳入版本管理;字段改名时同步消费者,而不是让新旧客户端猜测。规则含义见 JSON Schema 对象文档,Python 的校验与格式检查行为见 jsonschema 文档。