译文里的数字:怎样不丢掉一个编码或一笔金额
一份译好的报关单里出现一句别扭的话,代价是多读一遍。HS 编码里错了一位数字,代价是一票货被退。这两种失效在后果上相差数个数量级,而在你多半正在跑的任何质量指标里,它们相差为零。
BLEU 分不出数字和形容词。COMET 也分不出,判断流畅度与充分性的大模型同样分不出:一份丢了企业注册代码的译文可以拿 100 分,因为作为语言它没毛病。如果你翻译文件,数字完整性必须单独测量、用确定性方法测量,并作为一个独立的数字报告出来。
本文讲我们怎么做,包括在它真正生效之前,我们把这项检查本身搞砸的两种方式。
为什么通用指标在这里无能为力
质量指标的设计目标,是奖励保住含义的语言。而数字不是语言。它没有同义词、没有可接受的改写、也没有部分得分:2537143416 和 2537143415 一样错,也一样流畅。
更糟的是,这种失效从输出侧看不见。一份 28 个数字里保住 27 个的报关单,读起来和保住 28 个的一模一样。没有人会注意到,直到接收方的关员注意到。
所以这项检查必须是比较,而不是判断。比较便宜、确定,而且不可能凭空开出一张健康证明。
检查本身,以及我们搞砸它的第一种方式
朴素的实现会把两段文本都切成词元,再比较看起来像数字的那些词元。它会报出并不存在的丢失。
原因是标点。原文里这个值处在句中,写作 2537143416,;译文里它结束一行,写作 2537143416。按词元看这是两个不同的字符串,于是检查报出一个丢失的数字外加一个多出来的数字。在密集表单上,这种噪声会把真正的发现埋掉——而一项没人信的检查,就是一项没人跑的检查。
修法是比较最长的连续数字串,用正则取出,而不是比较词元:
原文: "код 2537143416, дата 02.07.2026"
数字串:2537143416、02、07、2026
去掉所有非数字字符,取出最长的不间断序列,再比较这两个多重集合。标点、引号、括号和换行都不再要紧——这正是我们想要的:它们都不是数字的一部分。
搞砸它的第二种方式:日期
一旦开始比较数字串,日期立刻会带来误报——因为日期恰恰是文件翻译理应改变的那一类数字。
中国报关单里的 20260702,在俄语译文里变成 02.07.2026。这是正确行为:目标语言区的日期写法不同。但在数字串比较看来,这是一个数字消失、三个数字出现。
所以日期需要自己的通道:识别出来,把两边归一化到同一种形式,再作为日期比较。其余一切按原始数字串比较,任何变化都算缺陷。
这条一般原则值得说出来,因为它不止适用于日期:检查必须知道哪些变换是合法的。 一项会给正确行为打标记的检查,会训练人们忽略它,而那比没有这项检查更糟。
真实文件上的数字长什么样
一次完整运行,中国出口货物报关单译成俄语:
| 追踪的原文数字 | 28 |
| 原样输出 | 26 |
| 有意改写(日期) | 1 |
| 真正丢失 | 1 |
唯一真正的丢失才是有意思的那个。原文的发货人一行是 (91330206MAD62XJF0Y)(33029600GQ)——两个企业代码,不是一个。抽取模式只声明了一个字段。第一个代码保住了,第二个无处安放,而输出看上去很完整。
在按模板填充的文件上,多数数字丢失都是这个形状,值得把话说准:模型正确读出了这个值,而表单没有对应的栏位。 因此数字完整性不只是翻译的属性,它同时是模式和表单的属性——而这项检查一次性抓住三种失效:没读对、译错了、无处安放。
搞砸它的第三种方式:尺子本身
代价最大的一课不是关于数字的,而是关于测量它们的工具。
我们做了一套评测框架,用来对着基准答案给抽取打分,它报出了 24 个缺失值。没有一个是真的。
这套框架拿模型的原始回答与参考答案比对。而生产路径做了框架没做的事:它在校验之前会对齐并归一化载荷——摊平分组输出、映射字段名——所以框架看作缺失的值,在生产中其实已经交付了。这次测量评的是一条并不存在的流水线。
这条教训适用于你写的任何检查:尺子必须走生产走的那条路。 一项跳过了生产会执行的归一化步骤的检查,会报出没人能复现的失败,而团队会学会不看这份报告——恰恰是在那一刻,一个真实的缺陷从它旁边溜了过去。
检查该放在哪里
三个位置,各自回答不同的问题:
抽取之后,对照原文。 我们是否读到了页面上的每一个数字?抓 OCR 掉字和视觉误读。
翻译之后,原文值对照译文值。 每个数字是否都挺过了翻译?抓经典的误译和掉位。
渲染之后,抽取值对照成品文件。 每个数字是否都到达了输出?这一个抓的是"表单没有栏位",而多数流水线恰恰省掉了它。
如果只能负担一处,就选第三处。它离客户拿到的东西最近,而且在某种意义上包含了前两处:任何在上游丢失的数字,在这里同样是缺的。
怎样报告才会被人据以行动
数字检查产出的是计数,而计数比分数更可执行。我们定下三条规则:
- 与质量分分开报告。 不要折进一个综合分里,那样流畅度的 100 分会掩盖一个丢失的编码。两个数字并排放。
- 点名具体数值,而不只给计数。 "丢了一个数字"是指标;"
33029600GQ出现在原文、在输出中缺失"是缺陷报告。 - 区分"被改写"与"被丢失"。 两者的修法不同——一个是语言区规则,一个是缺陷——把它们合并会让指标在两个方向上都失去意义。
要点
- 没有任何通用质量指标看得见数字丢失。 少了海关编码的译文读起来完美、得分也相应地高;这项检查必须独立且确定。
- 比较最长数字串,而不是词元。 附着的标点会让词元比较报出并不存在的丢失,而嘈杂的检查就是被忽略的检查。
- 日期是合法的例外,需要自己的归一化比较;给正确行为打标记的检查会教人忽略它。
- 表单上多数真实丢失是"无处安放"。 值被正确读出,而目标表单没有该字段——所以数字完整性也是模式的属性。
- 让尺子走生产的路。 我们那把尺子报了 24 个缺失,全部是框架跳过、而生产执行的一个归一化步骤所造成的假象。
FAQ
为什么 BLEU 或 COMET 抓不到错误的数字?
因为它们衡量的是保住含义的语言,而数字不是语言。它没有同义词也没有部分得分——改一位数字和不改一样流畅,指标什么也看不见。
数字完整性到底该怎么查?
把原文与译文中最长的连续数字串作为多重集合来比较,并单独识别与归一化日期,因为日期会合法地改变形式。这是一次确定性比较,成本为零,产出一个计数外加具体数值。
为什么比较数字串而不是词元?
因为标点会黏在数字上。2537143416, 和 2537143416 是不同的词元、同一个数字,于是每一个靠近逗号的数字都会让词元比较报出一次假丢失和一次假新增。这些噪声会埋掉真正的发现。
如果某个数字是被合法改写的呢?
让日期走自己的通道——识别、把两边归一化、作为日期比较——其余一切按精确匹配处理。把"被改写"和"被丢失"分开报告,因为前者是语言区规则在正确工作,后者是缺陷。
这项检查该放在流水线的哪一步?
理想情况是三次:抽取后、翻译后、渲染后。如果只跑一次,就跑最后一次——把抽取值与成品文件对照,能抓到所有上游问题,外加目标表单没有对应字段的那种情况。
结语
数字完整性是一种少见的质量属性:测量它很便宜,弄错它很昂贵——这使它成为任何文件流水线上第一个该装仪表的地方。它是比较而不是判断:不需要模型调用、不需要阈值、不需要相关性研究。
结果最难的不是这项检查本身,而是围绕它的纪律:比较对的东西、允许那些合法的变换、并确保测量走的是与生产相同的路径。这些搞错了,你就会得到一份满是幻影失败的报告——而一个真实的失败,正是这样被忽略掉的。
如果你要翻译报关单、证书或登记摘要,并希望把数字完整性作为一个独立数字看到,试试 KTTC。
