在财务自动化场景中,营业执照 OCR 是“真理的标准(Ground Truth)”,而 发票 OCR 是“充满噪音的观测值”。
我们的目标是:容忍噪音,命中真理。
1. 痛点:为什么 String.Equals() 是工程灾难?
发票(尤其是增值税普票)往往打印在薄纸上,字迹由于针式打印机的原因,经常出现断墨、重影。
OCR 引擎在识别长公司名(如“新疆乌鲁木齐高新技术产业开发区…有限公司”)时,极易出现:
- 形近字错误:“日”变“目”,“贝”变“见”。
- 符号错误:英文括号
()变中文括号()。 - 漏字/多字:漏掉“省”、“市”或者“股份有限公司”中的“股份”。
如果坚持 A == B 的精确匹配,这套系统上线第一天就会被投诉打爆。
2. 核心方案:构建“标准企业库” (The Standard Repository)
首先,不能拿发票 OCR 的结果去跟员工填写的文字比。要跟 营业执照 OCR 的结果比。
第一步:建立标准库
- 批量导入:利用营业执照 OCR,将集团所有子公司、分公司的执照进行批量识别。
- 清洗入库:提取
统一社会信用代码和企业全称,存入 Elasticsearch (ES) 或数据库。这是唯一的“白名单”。
第二步:OCR 结果的预处理 (Normalization)
在比对之前,必须把发票 OCR 的结果和白名单里的名字都“扒掉一层皮”:
- 去地域:移除“四川省”、“成都市”等行政区划前缀(可选,视业务而定)。
- 去后缀:移除“有限公司”、“有限责任公司”、“股份有限公司”等通用后缀。
- 去符号:移除所有括号、空格、标点。
3. 算法核心:编辑距离与相似度打分
现在,我们拿到了两个清洗后的字符串:
- 标准库:
腾讯计算机系统 - 发票OCR:
腾迅计算机系统(错了一个字)
工程实现:Levenshtein Distance (编辑距离)
我们需要计算:要把发票上的字,变成标准库里的字,最少需要改几次?
在这个例子中,把“迅”改成“讯”,距离是 1。
置信度公式:
$$\text{Similarity} = 1 – \frac{\text{EditDistance}}{\text{MaxLength}}$$
如果相似度 > 0.85(阈值可配置),我们就认为:“这大概率是同一家公司,只是 OCR 认错了,或者打印机没墨了。” 系统自动通过校验,并自动将发票抬头修正为标准名称。
4. 进阶方案:ES 的模糊检索 (Fuzzy Query)
如果你的集团子公司多达上千家,挨个算编辑距离太慢了。
这时候要利用 Elasticsearch 的倒排索引能力。
查询 DSL 示例:
逻辑流程:
- Recall (召回):ES 返回 Top 3 最相似的标准公司名。
- Rerank (重排):在代码层计算这 Top 3 与 OCR 结果的精确编辑距离。
- Decision (决策):
- 如果 Top 1 的分数 > 0.95 -> 自动通过。
- 如果分数在 0.8 – 0.95 之间 -> 人工复核(高亮差异字)。
- 如果分数 < 0.8 -> 拒绝报销(抬头错误)。
5. 别名与同义词库 (The Synonym Dictionary)
除了 OCR 错误,还有一类是 “习惯性缩写”。
比如标准名是“中国石油天然气股份有限公司”,发票上打印的是“中石油”。
工程策略:
维护一个 Alias Table (别名表)。
Key: 中石油 ->Value: 中国石油天然气股份有限公司Key: 阿里 ->Value: 阿里巴巴(中国)网络技术有限公司
在 OCR 识别后,先查别名表。如果命中,直接替换为全称,再进行比对。
6. 总结
在企业报销场景下,营业执照 OCR 提供了“标准答案”,而 模糊匹配算法 提供了“容错空间”。
这套组合拳的价值在于:
- 降低退单率:拯救了 30% 因 OCR 误识或打印模糊导致的合规发票。
- 减轻财务压力:财务不再需要肉眼去核对每一个字,机器已经过滤掉了绝大多数噪音。
- 数据治理:确保入账系统里的每一条供应商名称,都是与工商注册信息 100% 一致的标准名。
这就是费控系统的 “柔性工程学” —— 既有原则(基于执照),又有温度(容忍误差)。