结构化提取

字段缺失和字段为 null,是两种不同的失败

“字段没找到”和“字段是空值”,在界面上都可能显示一片空白,进入程序后却不应该混成一回事。再把空白补成数字零,问题会更隐蔽:下游收到的是一个合法数值,却以为它来自原文。

阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。 “字段没找到”和“字段是空值”,在界面上都可能显示一片空白,进入程序后却不应该混成一回事。再把空白补成数字零,问题会更隐蔽:下游收到的是一个合法数值,却以为它来自原文。 先把三种状态分开 在本文的合成契约中, amount 必须存在,允许数值或 null 。没有这个键表示输出结构不完整;键存在且为 null 表示当前没有可用金额;零则是一个明确数值。真实业务可以采用别的协议,但必须写清楚,不能让每个调用方自行猜测。 JSON Schema 的 required 负责键是否存在, type 负责值的类型。只有 required ,并不会自动禁止 null ;只在 properties 里写了字段,也不会自动要求它出现。这两个常见误解,适合直接放进回归测试。 用四个输入检验契约 from jsonschema import Draft202012Validator schema = {"type": "object", "required": ["amount"], "properties": {"amount": {"type": ["number", "null"]}}, "additionalProperties": False} validator = Draft202012Validator(schema) valid = lambda value: not list(validator.iter_errors(value)) assert valid({"amount": None}) assert valid({"amount": 0}) assert not valid({}) assert not valid({"amount": "unknown"}) assert not valid({"amount": None, "guessed": True}) 需要安装 jsonschema 。代码是内存中的结构检查,不调用提取模型,也没有证明某个金额与原文一致。金额如果要求精确小数表示,可以另选十进制字符串协议;不要因为示例用了 number 就直接把二进制浮点计算当成财务处理方案。 界面也要把状态说清楚 数据 应表达的状态 不应显示成 没有 amount 键 输出契约异常 金额为零 amount 为 null 未得到可用值 提取成功 amount 为 0 有明确零值 缺失 amount 为字符串 unknown 不符合本契约 自动转成 null 后静默通过 缺失原因不要塞进数值字段 若需要区分“原文未提供”“图片不可读”“候选存在冲突”,可以另加 status 或 reason ,并为它定义允许值。不要把原因写成金额字符串的一部分,再让下游从里面拆数字。未知也不是失败的同义词:有些文档本来就没有该字段,正确结果就应保留未知。 交付前检查来源 结构通过后,仍要看金额的币种、出处与对应标签。翻译与提取并用时,这些字段可以成为译后核对清单,帮助确认关键数字没有被误改,而不是替代原文审阅。本文不声称 OmniDoc(产品入口) 内部使用这套 schema,也不把合法 JSON 当成提取准确率。 参考: JSON Schema 对象与 required 。 - 1 -
更新于 2026-10-08