PaddleOCR + Spring AI + Qwen3.8:企业发票报销实战,从上传识别到人工确认卡
🌐产品手册:https://ruoyioffice.com/
👇 文章底部提供智能体与业务系统两种体验入口 👇
💬 :17156169080(获取 AgentOS 产品咨询)
员工上传发票后,识别出739.11元只是报销准备的一部分。系统还需要知道谁报销、使用什么账套、选择什么费用类型,以及最终准备使用的附件和金额是否一致。
本文用原创合成票据与专用测试员工,展示Windows Coder390 Q3从识别到真实确认卡的链路。文中Qwen3.8沿用本轮第三方权重命名。确认前能力为A级实测;OCR门禁尚未通过,没有实际创建财务草稿、付款或发起审批。
部署两类模型服务,观察一条报销链路
这次本地部署同时包含两个不同职责的服务:llama.cpp在18084加载27B Coder390 Q3,负责对话理解、工具选择和后续补问;CPU OCR在48082提供票面处理与结构化字段,使用独立Python环境。Qwen和PaddleOCR的依赖、资源与日志分开维护,OCR没有与27B推理争抢GPU显存。
Qwen侧沿用8K上下文、q8_0 KV、单请求、4线程、关闭思考/MTP及串行工具调用。OCR侧使用Windows兼容环境PaddlePaddle CPU2.6.2、PaddleOCR2.9.1和PP-OCRv4,并保留PDF文字路径。两侧各有健康检查,OCR请求由后端携带令牌,浏览器不保存该令牌。
Invoke-RestMethodhttp://127.0.0.1:18084/health powershell-NoProfile-File ruoyi-office-addon/modelsvc/deploy/windows-cpu/Install-OcrCpu.ps1 powershell-NoProfile-File ruoyi-office-addon/modelsvc/deploy/windows-cpu/Start-OcrCpu.ps1Invoke-RestMethodhttp://127.0.0.1:48082/health安装与启动命令引用现有部署脚本,需先完成独立环境准备;这里没有把重复启动命令执行到正在运行的服务上。
报销链路的先后顺序是:上传附件→Qwen决定调用OCR工具→OCR结果绑定当前会话→结果回填Qwen→员工说明业务目的→Qwen查询可用分类并提出准备参数→应用生成确认卡。每次补充可能触发新的本地模型请求。
本图对应历史运行447、448。OCR工具步骤观测340ms,分类查询步骤422ms;这些不是PaddleOCR纯推理速度,也不是所有图片的识别时延。
本例两轮SSE请求约27.68和34.00秒,含模型与工具往返。就算某张PDF的工具步骤很快,后续模型生成、补问和业务准备仍有等待;不能只拿OCR接口耗时代表整条报销体验。
一、上传票据,先保留识别结果与来源
员工上传原创合成文件SYN-002.pdf,要求列出票面与明细、检查金额关系,并明确不创建草稿、不发起审批。模型调用OCR能力,结果进入当前员工与会话的OCR上下文。
来自会话342首轮,对应OCR上下文70。票号、交易与企业名称均为原创测试材料,不是客户真实票据。
本例不含税金额681.66元,税额57.45元,价税合计739.11元。三项明细金额135.75、288.51和257.40相加为681.66元。
PDF有可用文字层时可先提取文字;字段缺失或质量不足再转图片OCR。两种路径都需要继续检查结构化字段,原始文字可读不等于购销方、明细、税率已正确解析。
识别服务使用CPU,与本地27B模型的GPU推理分开部署。模型在对话里调用OCR工具,票面识别与自然语言解释的责任需要分别检查。
结论:发票报销准备需要保留附件、识别结果与上下文引用;OCR读出的文字和模型解释,都不能直接代替业务字段校验。
二、用业务上下文补齐票面没有的信息
第二轮员工说明个人垫付、非差旅,并要求读取当前公司、默认账套、员工档案中的测试收款信息及可用费用类型。
本轮按评测指令选择“办公用品(模型评测专用)”。示例票包含不同服务明细,统一归类只用于测试链路,不代表正确的自动会计分类。
这里有两组不同来源的数据。票号、日期、金额和销方来自识别结果;员工归属、账套、收款和分类选项来自业务系统。模型应在有效选项中组织建议,不能自行发明费用类型编码。
本例后台读取到的日常费用报销类型为2、费用类型为19、账套为10。它们只属于本次员工与测试环境,不能复制成通用业务常量。员工默认账套和管理员账套可能不同。
多轮对话还必须引用实际OCR上下文。现有实现按租户、用户、会话、状态和有效期读取可用记录:
if(stored==null||!Objects.equals(stored.getTenantId(),tenantId)||!Objects.equals(stored.getUserId(),userId)||!Objects.equals(stored.getConversationId(),conversationId)||!List.of("recognized","ready").contains(stored.getStatus())||stored.getExpireTime()==null||!stored.getExpireTime().isAfter(now)){returnnull;}returnstored.getId();摘自AgentosReimburseContextService.latestAvailableId;stored来自当前归属条件的查询。历史记录中模型猜测上下文ID被拒绝的失败另行保留,不放宽归属匹配。
结论:账套、收款和费用分类需要从当前员工的有效业务上下文取得;OCR结果应绑定租户、用户和会话,不能靠模型猜测记录ID。
三、金额、附件和分类一起进入确认卡
第二轮生成真实确认记录41,对应运行448。卡片展示日常费用、学习账套、不可支付的测试银行、脱敏收款账号、报销事由和票据预览。
历史确认卡重新截图,有效期已过。没有点击“确认生成报销草稿”,界面中的“草稿”是准备内容,不能理解为已经落库的财务单据。
对于这张票,需要核对价税合计739.11与整票占用金额一致,分类ID确实来自查询,OCR引用与附件指向同一来源。
金额检查至少分为两个层次:681.66加57.45是否等于739.11,以及可核验的明细是否与票面金额相符。税率、合法空值、重复票据和财务政策还需要各自的校验,不能由一次加法覆盖。
下面是本轮准备参数的节选,保留字段层级,不是可直接执行的完整请求:
{"sourceSystem":"agentos","sourceRequestId":"agentos-context-70","bookId":10,"reimburseType":2,"invoiceItems":[{"ocrResultId":"ocr-447-1","priceTaxAmount":739.11,"expenseTypeId":19,"occupyAmount":739.11}]}真实请求还包含附件与金额明细,公开稿不复制完整文件地址或收款参数。只有参数、确认记录与卡片一致,才能认为确认前准备完成。
结论:报销确认卡应同时核对票据金额、附件引用、费用分类与员工业务上下文;模型声称“草稿已生成”不能替代真实确认记录或实际单据。
四、成功卡片之外,还要检查模型解释
报销部署调优先看调用链,不只看单个模型
历史任务曾对同一附件重复识别11次,另产生77次上限拦截,追加的工具结果又推高上下文占用。同条件原始模型返回证明了多工具调用来源;显式parallel_tool_calls=false后单次调用与协议回归通过。应先定位重复在哪一段发生,再判断是模型请求、工具编排还是OCR解析的问题。
OCR调优需要另外核对PDF文字层、购销方、明细及税率解析。把票据转成更多图片或增加大模型上下文,不能直接修复结构化字段遗漏。模型的费用分类和文字解释,也必须回到业务字典、票种规则与财务核对。
首轮回复用57.45除以681.66,得出约8.43%并称其为非标准税率。对于含不同服务和不同税率明细的票据,这个合计比值不能直接用于判断税率异常。缺少明细税率时也不能反推一个税率补齐。
页面还出现“发票代码为空,不影响报销使用”的文字。是否允许缺省应由票种规则与业务校验决定,这句话本身没有证明规则通过。
本例把多种服务明细按员工评测指令整票归入办公用品,验证了分类查询与参数传递,未验证会计分类建议的正确性。模型解释、结构化校验与财务决定需要分别验收。
其他历史轮次还出现只有完成文字、编造单号,却没有真实pending或写步骤的情况。该类轮次判为失败,不把虚构单号放到成功展示中。
五、OCR门禁与业务门禁分别报告
本轮100笔原创合成独立交易来自10个模板家族。修复后Windows与WSL2关键字段完整识别均为84/100,低于95%目标;被接受的结果为91/100。接受数量与完整字段数量采用不同判据,不能混成“91%整票准确率”。
金额关系通过率仅针对接受子集。最终人工真值复核和真实票据分布尚未验收,因此不能推广为客户实际票据的准确率。
WSL2完成200次连续请求,Windows在24次后因主机异常重启中断,没有续跑拼成200次稳定成绩。Windows Q3员工报销确认前任务为3/3,WSL2为2/3;管理员分别为2/3与1/3。小样本不能承诺生产成功率。
本轮106张OA/finance表分阶段COUNT与MAX(id)未观察到变化;技术会话、附件、OCR上下文和确认记录仍会增加。真实建单、幂等、回滚和审批需另行验收。
六、常见问题
1. OCR成功返回,就可以自动生成报销单吗?
不能。还要检查字段、金额、票种、业务上下文和人工确认;本轮只到确认卡。
2. 个人购方没有税号,需要补一个吗?
票面合法缺省应保持空值。具体必填条件按票种确定,不能编造税号。
3. 模型可否自动判断全部税率和费用科目?
本例没有验证这项能力。合计比值与评测分类都不能替代逐行税率校验和财务政策。
4. 确认卡成功是否证明OCR生产可用?
不证明。样例确认卡与全语料门禁分别验收;当前OCR未放行。
七、让模型参与准备,让核对有真实依据
这条链路把票面识别、员工补充、系统查询和操作预览连接起来。每一步都有可追溯来源,也有需要人工与程序继续检查的边界。
你更关注发票识别的字段完整性,还是从票面走到报销准备时的分类、账套和确认问题?
如果这篇对你有用,点个「在看」或收藏。
🤖在线体验·智能体:https://ruoyioffice.com/ai/work
🏢在线体验·业务系统:https://ruoyioffice.com/web/
📘产品手册:https://ruoyioffice.com/
💬微信:17156169080(备注「AgentOS」)
可以直接打开智能体,也可以先进入业务系统,再通过右下角“小擎”使用嵌入式助手。