ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

轻型AI中台实践:OCR识别与自动对账如何终结重复录入

轻型AI中台实践:OCR识别与自动对账如何终结重复录入 上个月底财务负责人把一张对账差异表拍在我桌上系统记录的应收和银行流水差了八十多万明细里有六百多笔对不上。与此同时业务部门还在每天加班把供应商发来的PDF单据手工敲进ERP。这类事情在企业里太常见了——不是某个系统不好用而是系统之间靠人肉转译。我当时的判断是公司需要的不是再上一个业务系统而是把识别、抽取、匹配、回写这条链路抽出来做成一个轻量的AI服务层。这就是后来被内部称为轻型AI中台的东西。这篇文章就聊聊我从选型到落地再到踩坑修复的完整过程给正在被重复录入和对账折磨的同行一个可参考的路径。1. 先别急着上中台搞清楚自己是被哪两类问题卡住的中台这个词过去几年被宣传得有点过于隆重很多企业一听中台就觉得要搞微服务、数据治理委员会、双中台战略结果项目还没启动就先把自己吓退了。实际上中小企业遇到的核心问题往往只有两个数据重复录入和跨系统对账困难。这两个问题表面看是人的执行力问题本质其实是系统架构问题。1.1 重复录入不是员工偷懒是系统之间没有公共身份层我观察过业务部门的真实操作流程销售接了一个新客户先在公司微信群确认一遍客户信息然后在CRM建客户档案接着订单进来又要在ERP里把客户名称、地址、税号重敲一遍到了发货环节仓储WMS系统还要再维护一次收货信息。如果客户信息中途改动过一个字三个系统的记录就对不齐了。等到月底财务做账只能逐条人工核对。重复录入高发在三个节点客户/供应商主数据、订单/单据信息、支付和结算信息。它们的共性是一个业务对象同时活在多个系统里但彼此之间没有统一的身份标识。系统之间不是完全没有接口而是接口传输的是录入后的文本不是经过清洗和归一的实体。员工敲进去的北京华信科技有限公司和华信科技北京有限公司在老系统里就是两条数据但在真实世界是同一个法人主体。这就是缺了公共身份层的问题。1.2 对账难的核心是格式、口径、时间差三座大山叠在一起对账是财务部门每月最痛苦的工作之一但仔细拆解下来对不平的原因高度集中在三类格式不一致、口径不一致、时间差。格式不一致很好理解银行流水的日期格式是20250112ERP里是2025-01-12供应商对账单上金额是负的表示冲减但系统里正负号含义完全不同。口径不一致更微妙比如同一笔采购财务按含税总价记账采购部按不含税单价询价两边的金额天然差一个税率。时间差则是指款项跨天入账、部分付款、合并支付A系统只看到一笔收款B系统拆成了三笔应收。AI在这个场景里并不是什么玄学它要做的事情就是把人眼比对变成算法分诊先标准化所有字段再通过相似度匹配找出最可能的关联关系最后把不同置信度的结果分流给自动核销或人工复核。这三座大山靠人肉能翻过去但每个月翻一次财务人员迟早被逼疯。2. 我的选型逻辑和最小可用架构不追求集团级追求三周能上线我当时给团队定了一个原则不要在第一个版本里做完整的中台只做一条能够闭环的窄链路。所谓闭环就是一张单据从进来到核销归档全程不再需要人工搬运数据。遵循这个原则技术选型会变得非常简单。2.1 为什么是轻型AI中台而不是传统数据中台或业务中台传统中台的建设思路是先建统一的数据标准、统一的主数据管理、统一的流程引擎然后各个系统接入。这个思路在大集团有效但对只有几十个IT人员甚至只有几个IT人员的公司来说太重了。我曾经见过一个团队花半年梳理数据字典结果业务已经调整了两轮。轻型AI中台的思路反过来先找准两三个高频痛点场景把AI能力OCR识别、语义匹配、模糊对齐和自动化流程事件触发、任务编排组合成几个可复用的服务。它不是取代业务系统而是坐在业务系统前面负责把非结构化数据变成结构化数据再把结构化数据准确投递给目标系统。这个定位决定了它不需要庞大的基础设施两三台服务器、一个编排引擎、几个模型服务就能跑起来。成本上差距也很明显。传统中台如果按咨询实施硬件估算百万以上很正常轻型中台如果只做单据识别和对账对齐我这次从环境准备到正式上线包括人力在内大约用了六位数级别的成本——而且大部分工作量在数据清洗和规则调整不是底层平台建设。2.2 技术栈选型能用开源组件解决的问题不自己造轮子我最终敲定的组合如下组件选型理由服务框架FastAPI自带OpenAPI文档接口联调省事异步支持对OCR这类IO密集任务友好任务编排Prefect Redis队列比Airflow轻量太多适合每天几百到几千单的任务量支持失败重试和人工审批流OCR识别PaddleOCR容器服务中文单据识别效果好可私有化部署通用模型对票据类文本覆盖度高语义匹配轻量中文BERT模型部署为ONNX推理服务用于处理户名、品名等模糊字段的相似度计算不需要大模型CPU也能跑数据存储PostgreSQL启用pg_trgm扩展 MinIOPG负责结构化数据和模糊匹配候选召回MinIO存原始单据文件部署方式Docker Compose单机即可起步后续需要扩容时再迁移到容器云关于编排工具多说一句。一开始有同事建议用Airflow但我评估后放弃了。Airflow的功能当然更完整但对运维的要求也高需要独立的元数据库、调度器、执行器对一个小团队来说有点杀鸡用牛刀。Prefect的流程定义用Python写重试和超时逻辑内置和FastAPI的配合也顺足够覆盖OCR完成后触发匹配匹配完成后触发回写这类流程。2.3 最小可用闭环从一张PDF到自动核销需要走完的链路整个系统上线第一周的验证闭环是这样的财务收到供应商发来的对账单PDF丢进一个统一的上传目录同时支持邮件解析工具的转发。系统自动完成以下步骤文件进入MinIO触发任务编排。PaddleOCR识别PDF内容按单据类型提取关键字段单据号、日期、金额、对方户名。字段质检规则校验金额和明细合计是否一致、单据号是否合法、日期是否合理质检不通过的进异常队列。通过质检的单据进入匹配引擎与ERP里的采购单/应收单做候选匹配。匹配得分高于阈值的自动生成核销结果并回写ERP得分中等的推送到人工复核工作台。所有原始文件和识别结果全程归档方便追溯。这个闭环看起来简单但把重复录入和对账两大痛点都覆盖了。供应商单据不再需要手工录入ERP对账的绝大多数差异项也能在分钟级完成定位。这个思路值得想上AI中台的公司参考先画一条最痛的业务链路的从进入到归档流程图再决定哪些节点需要AI能力。3. 重复录入的根除方案给每个业务实体建一张跨系统身份证我在第一部分已经说过重复录入的根源是系统之间没有公共身份层。所以轻型AI中台落地做的第一件正事就是在平台内建立一套跨系统的实体标识体系。简单来说就是给客户、供应商、物料、银行账户这些核心实体统一生成一个ID。3.1 主数据归一化客户和供应商的同一实体识别第一步是清洗存量数据。我把CRM、ERP、WMS里的客户和供应商全部导出来做两两相似度比对。比对的维度包括企业全称去掉空格和公司性质后缀如股份有限公司有限责任公司后的文本相似度、统一社会信用代码如果两个系统都填了、开户行和银行账号。企业全称的相似度计算我用了PostgreSQL的pg_trgm再加上一个简单的编辑距离过滤准确率已经能满足需求。举个例子CRM里录的是上海澄光贸易有限公司ERP里是澄光贸易上海两个名称从排序角度看差得很远但抽取掉地域和公司后缀后核心字号部分几乎一致pg_trgm的相似度得分很高。再结合税号一致这个强特征就能确认是同一实体。确认同一实体后平台会给它生成一个规范的entity_id用税号做种子值做哈希没有税号的用规范化名称其它字段组合做哈希。业务系统的老ID全部挂到这个新ID下面形成一张映射表。后续任何系统要查询这个客户统一通过中台的API接口拿到的是经过清洗的统一信息不再允许各家系统自己再录一遍全称和税号。第二步是在写入入口强制查重。新建客户接口调用前先做一次实体查重返回已有相似实体的列表由业务人员选择关联已有实体还是确认为新实体。这一步把新的重复数据在源头拦掉了。3.2 OCR自动填单让拍照/扫描/PDF直接变成结构化数据实体身份统一解决的是同一客户在两个系统里是两条数据的问题但重复录入还有一个更麻烦的来源人类在把纸质或PDF单据敲进电脑。这个环节我直接用OCRNLP抽取替代。实际操作中OCR的坑比想象中多。首先是票据版式供应商的送货单、物流面单、增值税发票的字段位置各不相同PaddleOCR的通用模型能识别文字但哪个框里是单据号需要模板或规则来定位。我的做法是做了一个简单的模板分层对于标准化的发票和银行回单用固定坐标关键字段校验对于格式杂乱的普通单据先OCR全量文字再用正则和语义规则抽取关键字段。抽取完成后的字段质检非常关键。我设置了几个硬校验规则金额字段必须是数字且大于0单据号不满足基本格式就置为高危日期不能晚于系统当前时间超过30天。所有OCR原始识别文本保留在MinIO一旦质检不通过或者置信度低系统不会自动采用而是把单据转入人工处理队列同时把OCR结果作为参考信息展示给财务人员。这套兜底机制特别重要因为AI识别不可能做到100%在没有人工确认前宁可慢一点也不能让错误数据流进账务系统。3.3 事件驱动同步系统之间不再靠晚上跑批同步数据主数据和单据识别都做好之后还有一个问题数据怎么实时流转到各个系统很多老系统的常见做法是每天半夜跑一次批处理同步问题是第二天的数据还是隔夜的容易引发对账的时间差。我的方案是事件驱动同步。核心业务系统的主数据发生变更时通过Webhook或消息中间件推送变更事件到中台中台统一处理后向其他系统推送。没有接口的老系统怎么办两个办法一个是数据库层的CDC变更数据捕获读取在表结构允许的前提下监听变化另一个是RPA兜底对实在没有办法改动的老旧系统用RPA模拟人工操作把数据填进去。RPA不是首选方案因为维护成本高但在过渡阶段可以接受。事件同步最容易踩的坑是乱序和幂等。业务系统可能在短时间内连续推送两条该实体的变更记录网络抖动导致后发的先到如果不做处理就会覆盖成旧数据。我的做法是每条事件都带上业务时间戳接收端按时间戳更大者生效的规则执行同时所有回写操作都使用实体ID作为唯一键做upsert确保重复推送不会产生重复数据。4. 对账困难的核心拆解把人工逐笔比对变成置信度分诊对账之所以让人头疼是因为它不是单纯的数据比较而是在充满噪声的数据里找出真实业务关系的过程。要想用AI消减对账困难必须把整个过程拆成一个可计算、可解释的流水线。4.1 对账场景的三个难点以及AI介入的切入点第一个难点是字段标准化。银行流水里付款方名称可能是澄光贸易上海公司ERP里是上海澄光贸易有限公司还可能有全角半角空格、简繁体差异。这个环节靠清洗规则统一大写、去空格、规整括号为半角、抽取税号/账号特征然后分别建立匹配特征字段。第二个难点是关联关系不一定是一对一。常见的情况包括客户一笔大额付款对应多张发票合并付款把多个订单合成一笔部分核销只付了订单的一半。如果匹配逻辑只做金额完全相等大量真实关联关系会被漏掉。AI介入的做法是允许一对多、多对一甚至多对多的匹配前提是总金额勾稽关系成立。第三个难点是时间差。银行业务发生日和系统记账日可能相隔几天供应商对账单的账期和实际付款日也不一致。纯粹按日期匹配会失败所以我把日期差设定为评分特征而不是一票否决条件允许一个合理的容忍窗口。4.2 匹配引擎设计候选召回加多特征评分匹配引擎是这套系统的核心我采用了两阶段设计候选召回和特征评分。候选召回层解决的是在全量数据里快速找到疑似关联的单据。我用金额做第一道硬过滤规则是待匹配金额的0.9倍到1.1倍范围内或者拆分后可覆盖。第二道用时间窗口一般取对方单据日期前后5天第三道用户名/账号的模糊匹配用pg_trgm召回相似文本。三道召回条件的交集和并集组合把全量比对的范围压缩到几十条以内。特征评分层对每一对候选计算多个维度的相似度分数最后加权求和公式类似这样score ( 0.40 * amount_similarity 0.15 * doc_no_similarity 0.15 * counterparty_name_similarity 0.15 * date_window_score 0.15 * bank_account_match_score )金额相似度不是简单的相等判断而是考虑拆分/合并的情况如果候选金额组合后与目标金额差值在0.01元以内金额分直接给满分差值在0到2%范围内按比例扣分。单据号相似度用编辑距离如果双方都填了完整的单据号且完全一致这一项就是满分这能解决大量格式差一点的情况。户名相似度用BERT模型算向量余弦值同时叠加上文提到的别名规则。需要说明的是这些权重是在我们这家公司的业务数据上反复试出来的不同行业可以调整。比如零售行业客户数量大但单个客户交易频次高金额和日期权重可以放大制造业项目制结算多单据号匹配权重要更高。4.3 分诊输出策略高置信自动核销中置信人工复核低置信异常池评分结果本身没有业务意义必须映射到操作动作。我定义了三条分诊路径得分不低于0.95完全匹配自动核销系统生成核销凭证回写ERP和财务系统。同时记录一个自动通过的日志方便后续审计。得分在0.85到0.95之间大概率是同一笔业务但存在某些特征不完全一致比如户名差了一个字、日期差了两天推送到人工复核工作台。系统会展示最高分的三个候选并标注每一维度的得分原因让人工操作员快速判断。得分低于0.85进入异常池按差异类型打标签包括找不到对应单据金额差异超过阈值户名完全对不上日期差过大等。财务人员每周集中处理一次异常池处理方式可以是对应手工补录、联系业务方确认、或者标记为历史遗留挂账。这套分诊策略的效果是把财务从逐笔核销变成了只看异常。实测下来我们处理的对账单中大约70%落在高置信区间自动核销20%落在中置信区间需要人工快速确认剩下10%是需要追溯的异常。对账的月度关闭时间从之前的七到十个工作日压缩到了两天左右。4.4 差异归因给财务一个为什么对不平的解释刚开始推行AI自动对账时财务负责人不太敢信任黑箱结果。所以我在异常池和复核列表里都加了差异归因建议这是被很多方案忽略但实际价值很高的功能。差异归因不是简单列数据而是把差异按业务原因归类。比如同一客户的两笔应收金额接近日期相差一个月系统会提示疑似预收冲销未及时核销比如一条银行流水反复匹配到多张已核销发票系统会提示疑似重复支付请核实银行侧是否误操作。这些提示来自我总结的业务规则库大概有二十多条覆盖了长账龄挂账、部分核销、重复支付、合并付款拆分异常等高频场景。有了归因建议财务人员不用再凭借记忆和感觉去猜差异源头直接沿着系统给出的标签去翻原始凭证效率提升非常明显。5. 上线三个月后我踩过的坑以及对应的处置方式再完美的设计到了真实数据面前都会露馅。这三个月我遇到的主要问题集中在五个方面每一个都值得后来者提前防护。5.1 OCR误识别和字段丢失置信度阈值不能设得太低上线一周后财务反馈有一笔12万的付款被系统标成了1.2万。排查后台发现OCR把纸质回单上120,000.00识别成12,000.00千位分隔符被丢掉了。这是个很典型的OCR错误单个字段的置信度当时恰好通过了阈值但金额和明细总和不相等应该触发校验——问题在于我当时只写了一级校验没有要求单据金额等于明细行合计。后来我把OCR置信度阈值从0.8提高到0.9同时加了硬规则金额类型字段必须通过多重校验数字格式、范围、与业务单据金额的勾稽关系。识别存疑的单据一律转人工不自动回写。5.2 金额精度与舍入规则float把账搞差了0.01元有几天不断有对账单差一分钱的情况查到最后发现是接口返回的金额字段用了JSON数字类型部分系统底层用float存储导致0.01元的舍入误差。这个问题在数据库层必须使用numeric类型应用层计算统一用Decimal禁止float参与金额计算。另外不同系统对四舍五入的规则不统一有的按银行家舍入法有的直接截断在清洗阶段就要把所有金额字段格式化成统一的精度再做匹配。5.3 数据同步风暴和消息乱序主数据事件同步上线后有一周消息队列频繁积压。原因是某些历史客户批量更新时触发器一次性产生了数万条变更消息中台处理的TPS跟不上。处置方案是加了批量合并在短时间内对同一实体的多条变更消息只保留状态最新的一条同时把写业务系统的操作改为串行队列。乱序问题则通过业务时间戳解决之前已经说过这里再强调一次断言事件处理结果时必须比较业务时间而不是消息到达时间。5.4 历史脏数据迁移新数据要走新流程老数据要单独建批次系统上线前最大的工作量其实不是开发而是处理历史数据。ERP里有大量重复客户记录、残缺税号、已经核销但状态还挂着未核销的旧账单。我的策略是先新后旧新发生的单据第一时间进入AI中台的流程存量历史数据则单独建一个历史数据清洗批次用清洗脚本批量标准化清洗结果只作为参考不自动回写。为什么这么做因为历史数据往往存在大量异常如果自动回写可能会把旧账翻出来变成新问题。先让新流程跑顺再逐步消化历史包袱是整个项目能够按期上线的重要原因。5.5 业务人员的信任问题算法必须留痕和可解释最后是人的问题。财务同事一开始对自动核销非常抵触担心系统把错误的单据核销了后续审计要追责。我做了两个调整第一个是前两周所有自动核销结果都附加留痕说明展示系统识别到的原始单据截图、关键字段、匹配依据点击可回溯任何一步第二个是增加一个人工确认开关在上线初期所有中置信以上的单据仍要求复核运行稳定后再逐步把高置信区间放开为自动核销。两周后财务主动要求把阈值往下调因为她们发现系统推荐的候选确实比肉眼比对更全面。6. 这套方案的边界以及下一步扩容方向写完这些经验我想再泼点冷水。轻型AI中台不是万能的有些场景不适合硬套。如果你的业务流程极其简单一个Excel加邮件就能管好没必要上系统如果业务数据连基本的字段规范都没有也不建议先上AI而是先把数据治理的基本功补上如果组织内部根本没有统一数据口径的意愿那AI中台能做的只是边缘性优化价值会大打折扣。扩容的方向反而是清晰的。当前这套架构从单据识别和对账起步后续可以在三个方向延展一是把OCR和NLP能力复用到合同比对、采购单据审核、客户服务工单分类二是从感知和执行升级到流程决策比如对供应商账期和付款优先级做智能建议三是模型层可以从轻量模型逐步替换为更大规模的语义模型前提是隐私和部署资源能跟上。最后说说我个人的体会。这套系统上线三个月最让我意外的不是技术指标而是组织内的协作方式发生了微妙变化销售不再追问为什么ERP里的客户名和我录的不一样财务不再需要月底连熬几天对账IT部门的工单量也因为录入类问题而明显减少。我觉得轻型AI中台真正的价值不是证明AI多强大而是让散落在各个系统里的数据第一次有了统一的身份和一致的流转规则。这个价值恰恰是那些重金打造的传统大型中台可能没法带给中小团队的。如果你的团队正在为重复录入和对账问题头痛不妨先别急着立项采购大平台把我上面这条窄链路跑通大概率已经能解决一大半痛点。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进