一、背景
近期在做发票查验相关系统升级时,发现新版 XXX税查验流程相比旧版本发生了明显变化。除了查验入口、验证码形式、参数结构有所调整外,返回数据也变得更加完整,包含查验结果、发票状态、购销方信息、明细项目、附加标签等多层级结构。
为了适配新版查验流程,我完成了一套新版发票查验能力的工程化改造,主要包括:
- 新版验证码识别能力建设
- 验证码样本训练与合成
- 新旧版本查验流程兼容
- 协议流程分析与适配
- 返回结果标准化 JSON 输出
- 单线程与多线程调用统一接入
本文只介绍整体思路和落地效果,不涉及具体接口细节、请求参数、加密逻辑、模型结构和绕过实现。
二、目标
本次改造的目标不是简单替换一个接口,而是让系统具备完整的新版本适配能力。
主要目标如下:
- 支持新版 XXX税查验流程。
- 支持新版验证码的自动识别。
- 支持按颜色提示提取对应字符。
- 支持旧版与新版通过配置切换。
- 支持单线程和多线程统一调用。
- 返回结果改为标准 JSON 对象,而不是字符串嵌套字符串。
- 尽量降低 CPU 和内存占用,保证服务稳定运行。
三、整体流程
新版查验流程可以抽象为以下几个阶段:
输入发票信息 ↓ 判断新旧版本 ↓ 获取查验区域与访问入口 ↓ 获取验证码 ↓ 识别指定颜色字符 ↓ 提交查验请求 ↓ 解析查验结果 ↓ 输出标准 JSON在工程实现上,新版逻辑没有直接替换旧版,而是通过配置项进行切换。这样可以在生产环境中逐步灰度,不影响旧流程稳定性。
四、新版验证码识别能力
新版验证码相比旧版更复杂,不再只是简单字符识别,而是同时涉及:
- 字符识别
- 颜色识别
- 位置识别
- 有效字符判断
- 按提示颜色筛选字符
例如查验流程中可能出现类似提示:
请输入红色字符 请输入黄色字符 请输入蓝色字符 请输入黑色字符因此模型不能只输出完整字符串,还需要知道每个字符对应的颜色。最终识别流程可以理解为:
验证码图片 ↓ 模型识别每个位置的字符 ↓ 模型识别每个位置的颜色 ↓ 根据提示颜色筛选字符 ↓ 输出最终验证码这种方式相比传统单一 OCR 更适合新版验证码场景。
五、训练与样本合成思路
为了提升验证码识别稳定性,我对样本构建做了专门处理。
整体思路包括:
- 构建字符与颜色联合标注数据。
- 对不同颜色、字体、位置、干扰样式进行覆盖。
- 通过合成样本补充低频字符和低频颜色组合。
- 训练时同时关注字符准确率和颜色准确率。
- 推理时只保留业务需要的目标颜色字符。
这里不展开具体训练脚本、模型结构和样本生成规则,只说明最终目标:让模型不仅知道“是什么字符”,还知道“这个字符是什么颜色”。
六、协议适配思路
新版 XXX税查验流程与旧版本相比,主要变化体现在:
- 查验入口选择逻辑不同。
- 验证码获取方式不同。
- 验证码提示字段存在变化。
- 查验提交参数结构不同。
- 返回数据结构更加复杂。
- 返回结果中包含更多电子发票扩展信息。
在适配时,我没有把新版逻辑硬编码到旧流程里,而是保留了版本判断:
new = 0 走旧版流程 new = 1 走新版流程这样单线程和多线程都可以根据配置自动选择对应流程。
七、返回结果标准化
新版查验成功后,原始返回数据是一个多层 JSON。最开始如果直接把返回字符串塞进data字段,会出现这种情况:
{ "code": "7", "msg": "请求成功", "data": "{\"Response\":{\"RequestId\":\"...\"}}" }这种格式不利于前端或调用方解析,因为data实际上是一个 JSON 字符串。
优化后,返回结果改为标准嵌套 JSON:
{ "code": "7", "msg": "请求成功", "useTime": 478, "data": { "Response": { "RequestId": "********", "Data": { "reCode": "00", "CyjgDm": "7", "CyjgMsg": "经查验,发票信息一致", "Cycs": "4", "Cysj1": "2026-07-23 10:21:52", "DzfpFpxxVO": { "Fphm": "********", "Kprq": "2025-12-29 12:45:57", "Xsfmc": "********", "Gmfmc": "********", "Jshj": 160, "Hjje": 150.94, "Hjse": 9.06, "MxzbList": [ { "Xmmc": "餐饮服务", "Je": 150.94, "Se": 9.06, "Slv": "0.060000" } ] } } } } }这样调用方可以直接访问:
data.Response.Data.CyjgMsg data.Response.Data.DzfpFpxxVO.Jshj data.Response.Data.DzfpFpxxVO.MxzbList不需要再做二次反序列化。
八、关键返回字段说明
常见字段含义如下:
| 字段 | 含义 |
|---|---|
code | 系统返回码 |
msg | 系统返回消息 |
useTime | 请求耗时,单位毫秒 |
RequestId | 本次查验请求流水号 |
reCode | 接口处理结果码 |
CyjgDm | 查验结果代码 |
CyjgMsg | 查验结果描述 |
Cycs | 查验次数 |
Cysj1 | 查验时间 |
FpztDm | 发票状态代码 |
DzfpFpxxVO | 电子发票主体信息 |
Fphm | 发票号码 |
Kprq | 开票日期 |
Xsfmc | 销售方名称 |
Gmfmc | 购买方名称 |
Jshj | 价税合计 |
Hjje | 合计金额 |
Hjse | 合计税额 |
MxzbList | 发票明细列表 |
九、工程化处理
为了让这套能力能够稳定运行,我在工程层面重点处理了几件事:
- 模型本地化部署,避免运行时依赖外部路径。
- 验证码识别类独立封装,方便服务层调用。
- 控制模型推理并发,避免 CPU 突然拉满。
- 图片尺寸统一预处理,减少不必要的缩放开销。
- 新旧版本通过配置切换,不影响原有流程。
- 单线程和多线程调用路径保持一致。
- 返回数据统一 JSON 化,降低调用方解析成本。
十、效果
目前新版流程已经可以完成完整闭环:
获取验证码 识别指定颜色字符 提交查验 解析返回结果 输出标准 JSON一次成功查验的耗时示例约为:
useTime: 478ms实际耗时会受到网络环境、代理质量、服务响应速度、机器性能等因素影响。
十一、总结
这次新版 XXX税发票查验适配,核心并不是某一个单点功能,而是把验证码识别、协议适配、结果解析和工程稳定性整合到一起。
最终实现了:
- 新版验证码自动识别
- 颜色字符筛选
- 新版查验流程适配
- 标准 JSON 返回
- 新旧版本兼容
- 服务端批量调用支持
后续还可以继续优化的方向包括:
- 提升复杂验证码场景下的识别稳定性
- 增加更多异常返回码的归类
- 对查验结果字段进行业务级结构化封装
- 增加调用耗时、识别准确率、失败原因的监控统计
本文仅作为项目实践记录,所有能力均应在授权、合规、合法的业务场景中使用。