客户给了一批真实单据,让 AI 把出口报关单录出来。"抽得准不准"这件事, demo 里看两票感觉都挺好,但要上生产,得有一个自己都不敢质疑的数。 这篇记录我怎么把这个数做出来,以及做出来之后发现的第一个问题不在模型,而在尺子。
先给测量工具做评测,再谈模型准不准。尺子歪的时候,所有差异都是假差异。
01 · 拿什么当标准答案
每一票的输入是客户发来的一堆文件:发票、装箱单、托书、有时还有压缩包。 标准答案是报关行已经申报出去的预录入报关单——那是真实过关的版本,不是谁拍脑袋写的。 对拍按逐格来:18 个表头字段,加上每一项商品的 9 个字段,一格一格比。
除了"逐格一致率",我另加了两列。商品行 我/答:我方抽出几行、答案里几项,不相等说明拆合并方式不同。 要素填错:申报要素里我方填了但填错的格数——填空不算,空着只是让报关员补一格, 填错才会写进真实申报单。这一列才是危险指标。
02 · 第一轮:17 票 66%,还有三票要作废
| 分档 | 票数 | 逐格一致率 | 说明 |
|---|---|---|---|
| 好 | 5 | 81% – 87% | 单商品或结构规整的票 |
| 中 | 7 | 66% – 79% | 多商品行,拆合并方式与答案不同 |
| 差 | 2 | 54% – 57% | 一票把 2 项商品拆成了 12 行 |
| 作废 | 3 | 18% – 22% | 真实单据在 rar 里没解开,抽取只看到舱单 |
合计 436 / 665 = 66%。最后三票我直接标了"成绩不算数":输入不完整时的分数, 既不能说明模型差,也不能拿来平均。评测里最容易自欺的地方,就是把这种票悄悄算进分母里让平均数好看一点, 或者悄悄剔掉让平均数更好看一点。两种都不行,写清楚原因放在表里。
03 · 先修尺子:答案解析器 20 票全错
第二轮拿到更多真实申报单,我先跑了一遍答案解析器,结果 20 / 20 全部解析错: 发货人全空,一半的票成交数量抠不出来。也就是说第一轮对拍里相当一部分"差异"根本不是抽取错, 是尺子错。
报关单 PDF 抽出来的正文是等宽两段式,两块规律不同,混用一种解法必错: 表头是"标签行 / 取值行"成对、左对齐,按标签起始列切取值行;商品行一项占 2 到 4 行、行数不固定, 只能按词元形态分类,列位置只用来消歧。三个具体的坑:
- 列锚点不能从表头行算。PDF 抽出的文字里,表头与数据行整体错开约一列,锚点只能从数据行自己取。
- 「数量及单位」有 2 项或 3 项,取决于有没有法定第二单位;顺序恒为法定第一、可选的法定第二、成交,所以取首尾。
- 规格型号不能按空白切词再拼,否则
松木 PINUS RADIATA会被拼成一坨,把本来对的值判成错。
评分工具同期改了两处:申报要素改成逐格评分,整串比太粗,改对一格仍显示"不同";
归一化不再无条件按数值比较,否则海关代码 0110 会被压成 110,
一边有前导零一边没有也假装一致。
04 · 六条口径,每条带样本量
尺子修好后,真正的差异露出来了。我给每条修正规则都数了样本, 只落实零例外的那一侧,有反例的一律不自动改:
- 单价 = 总价 ÷ 数量取 4 位(44/44)。发票印的是谈价
12.68,报关单要求乘起来对平,报的是12.6835。照抄发票两边永远对不上。 - 成交计量单位以单据为准,不必是法定单位(17/44 就不是)。这一条推翻了三天前按单票判例写下的"不是法定单位就换算"——那条规则会把 17 项全部改报成千克,是会写进真实申报单的错。
- 成交单位等于法定第一单位时,法定第一数量等于成交数量(27/27)。法定第二那条只有 18/20 成立,不实现。
- 品牌写「无品牌」则品牌类型必为 0(19/19)。反向不成立:有品牌名时 22 次是 3、3 次是 0,交给人判。
- 只写一个「无」字的要素补成完整说法,平台校验明说不可仅申报单个文字;其他写法一律原样透传。
- 13 位商品编号取前 10 位。不归一会让要素模板、法定单位、平台模板三处同时静默落空,表现成"要素怎么全是空的",根因藏在编号上。
另加一条确定性校验:表头净重、毛重与各商品行之和对不上就告警,不自动改。
它抓的是"漏抄一位"——实测一票表头 775.22、行内 7756.22,两边格式都合法,
下游零报错,只有到平台申报那一步才会被拒。
05 · 结果:54% 到 67%,零额外模型调用
同一批票的一致率从 54% 提到 67%。这一轮全部是改解析与口径代码,
用历史保存的 result.json 离线复算,没有多花一次模型调用。
这也是我坚持把每一票的原始抽取结果落盘的原因:评测应该便宜到可以随手跑。
06 · 顺带的实验:AI 复核 AI 值不值
很多人的直觉是"再让模型看一遍总不会更差"。我用同一套业务规则让模型对最终 JSON 做二次复核, 每票跑两遍看提议稳不稳,再对答案打分:
| 实验 | 基线错格 | 复核后错格 | 修对 | 改坏 |
|---|---|---|---|---|
| 整体复核(312 格) | 12 | 11 | 1 | 0 |
| 地址折行复核(40 格) | 14 | 17 | 1 | 4 |
整体复核净收益是修对 1 格,几乎白跑;折行专项复核则修 1 破 4,越复核越差。 另一组重复 3 次的稳定性测试里,输出完全一致的比例只有 53%。 结论不是"复核没用",而是复核不是免费午餐,上线前必须先量它的净收益。
07 · 收尾
这轮做完,我对"评测"这两个字的理解变了:它不是最后跑一遍看分数, 而是先怀疑尺子、再怀疑输入、然后才轮到怀疑模型;每条规则带样本量, 每个作废的样本写清原因。数字不好看没关系, 不自欺的 67% 比自欺的 90% 值钱得多。