阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。
上周的
amount
表示“分”,这周改成“元”,字段名却没变。类型校验仍然通过,业务结果却可能差两个数量级。提取接口最危险的升级,往往不是显式报错,而是悄悄改变含义。
版本号要跟语义一起走
增加字段与改变单位不是一回事。可以给每个输出带上
schema_version
,并按版本选择验证器和迁移函数。版本号本身不会保护系统:如果所有版本都走同一条未经区分的解析逻辑,它只是一个装饰字段。
下面演示从整数分转换成十进制金额字符串。迁移是明确的数据转换,不是把旧数据直接贴上新版本标签。
一个可审计的迁移函数
from decimal import Decimal
def migrate(record):
if record.get("schema_version") != "v1":
raise ValueError("unexpected input version")
cents = record.get("amount_cents")
if type(cents) is not int:
raise ValueError("integer cents required")
return {"schema_version": "v2",
"amount": format(Decimal(cents) / Decimal(100), ".2f"),
"currency": record["currency"]}
old = {"schema_version": "v1", "amount_cents": 12345, "currency": "USD"}
new = migrate(old)
assert new["amount"] == "123.45"
assert old["amount_cents"] == 12345
assert migrate({**old, "amount_cents": -25})["amount"] == "-0.25"
try:
migrate({**old, "amount_cents": True})
except ValueError:
pass
else:
raise AssertionError("bool is not a monetary integer here")
此例假设输入币种使用百分单位关系,且输出保留两位小数。它不是覆盖所有货币单位的通用转换器。
type(cents) is int
刻意排除了 Python 中作为整数子类的布尔值,避免把
True
接受成一分钱。
迁移记录应该留下什么
信息
用途
缺失的风险
输入与输出版本
选择正确解释规则
同名字段含义混乱
迁移程序版本
重现转换
更新后结果无法解释
原始记录身份
找回来源
新旧数据无法对应
失败原因
分流人工处理
不合格数据被补默认值
不要无限兼容历史错误
若旧记录的单位本身不确定,迁移函数不应猜测。可以返回明确失败,保留旧数据并要求补证据。对已经消费旧接口的下游,也应安排版本切换,而不是期望它自动发现数值语义改变。
译后核对也需要版本意识
把提取字段用于检查
OmniDoc(产品入口)
译稿时,应说明字段由哪个协议生成。源文件、提取规则或目标语言变化,都可能影响比对方式。保留版本信息,能让“这次为什么和上次不同”成为可排查的问题,而不是一句模型不稳定。
参考:
JSON Schema 通用关键字
。
- 1 -
更新于 2026-10-08