← 返回AI

我给律师工作做了一套本地 OCR:认出文字只是第一步

一次真实材料测试说明:OCR 认出文字并不等于律师可用。证据模式与结构模式必须分开,关键事实始终回到原页人工终审。

本地 OCR 认出文字只是第一步
案件材料进入大模型之前 · 03

《案件材料进入大模型之前》第三篇

这套本地 OCR 第一次处理真实材料时,程序给出的结果是:PASS

九页扫描材料全部跑完,识别文件完整生成,原件没有被改动。从程序的角度看,任务成功了。

然后我打开识别结果,发现第 2、3 页根本不能用。

这两页原本是横向表格。程序确实认出了一部分项目名称、单位和数字,却没有先把页面转正,也没有保住表格的行列关系。项目名称在一处,工程量、单价和合价散在另一处。

字认出来了,事实关系却丢了。

如果把这样的全文直接交给大模型,它仍然可以生成一份语气完整、结构清楚的分析。危险之处正在这里:模型未必知道数字已经找错了对象。

那次实测让我确认了一件事:

律师需要的 OCR,不是“成功导出文字”,而是关键内容能不能重新钉回原页,错误能不能在进入案件分析前被发现。

自动检查通过,不等于律师可以使用

先说清楚,第一次的 PASS 并不是程序撒谎。

它检查的是另一组问题:九页是否都已处理,规定的文件是否完整,页图和识别结果能否打开,原件是否保持不变。

这些检查很重要,但它们回答的是“程序有没有按设计运行”,不是“这份材料能不能安全用于办案”。

一张表格里,十个数字全部认对,却分别落到错误的项目下面,程序可以完整运行,律师却不能使用。一个姓名只错一个同音字,全文仍然流畅,后面的当事人匹配和检索却可能全部偏掉。

所以,我后来把验收分成了两层:

  • 技术验收:产物是否齐全、格式是否有效、原件是否被改动;
  • 业务验收:主体、金额、日期、期限、案号、账户、签章和表格对应关系,能否回到来源页核对。

前一层可以自动完成很多。后一层不能交给一句 PASS

律师其实需要两份不同的结果

继续修改这套工具时,我发现“识别得准”和“排得好读”并不是同一件事。

律师一方面需要准确位置:某句话来自哪一页、页面什么位置、机器有多大把握。另一方面又需要阅读结构:标题在哪里,段落顺序怎样,一张十列表格怎样恢复成可以阅读的行列。

一个输出很难同时把两件事都做好。

所以,我现在把 OCR 分成两个彼此独立的模式。

证据模式使用本地 PP-OCRv6 识别逐行文字,再由 PP-LCNet 判断页面是 0°、90°、180°还是 270°。它保存页码、文字坐标、置信度、方向判断、表格候选和质量报告。

它解决的是:这段文字识别成了什么,来自哪里,哪些地方需要复核。

这里的“证据模式”只是我给功能起的名字,不表示 OCR 文字已经成为法律上的证据,更不表示可以脱离原件引用。

结构模式使用在本机运行的 HunyuanOCR-1.5,帮助恢复段落、阅读顺序和 Markdown 表格。它生成的阅读副本更整齐,更适合快速浏览复杂版面。

但当前结构结果没有逐行坐标和置信度。它解决的是“怎样读”,不能单独证明“原页究竟写了什么”。

因此,两种结果分开保存。遇到姓名、数字、日期和表格单元格冲突时,不自动选一个,也不悄悄拼成一份更漂亮的全文,而是保留冲突,回到原页。

证据模式与结构模式分开保存,冲突时回到原页人工终审
证据模式与结构模式分开保存,冲突时回到原页人工终审

第一次返工解决横向表格,又暴露了手写问题

针对那两页横置表格,我先加了页面方向判断。

原始页图始终保留;需要转正时,另存一张处理页,再在转正后的页面上识别文字。这样既不覆盖原件,也能让后续复核知道机器实际看的是哪一张图。

接着,我按表格线和文字坐标恢复行列。重新跑那份九页材料后,第 2、3 页被自动转正,表头和数据行恢复成十列。原来散开的项目与数字,重新回到了相应单元格。

这个问题改善以后,我又加入结构模式,希望复杂页面能够更好读。

印刷表格确实改善了。

但同一页底部有一处潦草手写,结构模型没有停下来承认看不清,而是替它补出了一句看似合理、实际上并不可靠的话。

这比输出“无法辨认”更危险。

无法辨认会提醒律师回看原件。一句流畅的错话却可能直接混进事实摘要,之后再被引用、比较和推理。

从那以后,我不再允许结构模型承担精确抄字。它可以帮助恢复阅读顺序,却不能因为表达更完整,就覆盖带位置的识别结果。

置信度很高,也不能放过关键事实

OCR 会给每一行一个置信度。最简单的做法,是设一条统一分数线:低于某个数就复核,高于就放行。

对律师材料,这样不够。

普通叙述错一个标点,影响可能很小;金额少一个零、日期错一天、主体名称错一个字,后果完全不同。错误风险取决于内容,不只取决于模型分数。

我现在的规则是:

  • 普通叙述行低于 0.85,进入复核;
  • 姓名、主体、金额、日期、期限、案号、证件号、账号、文号、联系方式、地址和签章语境,无论分数多少都进入复核;
  • 0.95 只用于安排高风险内容的复核先后,不代表可以免检;
  • 手写、签名、印章和指印始终需要人工终审。

这套规则不假装已经算出一个适用于所有材料的“最佳阈值”。它只是承认:同样一次识别错误,落在普通叙述和落在付款金额上,不是同一种风险。

当前版本的一页真实测试中,共识别出 64 行,系统挑出 2 行复核:一行因为置信度低于 0.85,另一行虽然分数不低,却因内容属于关键字段被强制留下。

后者正是这套规则存在的意义。

模型视觉只能提意见,不能改原文

发现需要复核的行以后,另一个问题出现了:难道还要把整页扫描件再交给视觉模型看一遍?

我的做法是先生成一个复核包,只裁出需要检查的最小区域。视觉模型只看这些小裁块,对现有识别结果给出三种意见:一致、可能的其他读法,或者无法辨认。

它不能直接修改正式 OCR 记录。

即使视觉模型认为某个字应该换成另一个字,这也只是一条候选意见。原来的识别文字保持不变,最终是否更正,仍然由人对照原页决定。

这条限制是故意的。

如果模型可以在后台自动把 OCR 文字改得更顺,最后得到的也许是一份很好读的文本,却没人知道哪些字来自原识别,哪些字是后来猜出来的。

还要说明:最小裁块不等于已经脱敏。裁块里仍可能有姓名、金额或账号。是否可以交给外部视觉模型,仍要根据材料性质和使用条件另行判断;不适合提交的,就只作人工复核。

减少范围,不等于取消资料边界。

我最后留下的,不是一份 TXT

一套适合律师工作的 OCR,最后不应只剩一份连续全文。

我现在要求保留的东西包括:

  • 原始文件;
  • 逐页渲染图,以及必要时的转正处理图;
  • 带页码、坐标、置信度和复核规则的正式识别记录;
  • 便于阅读的结构副本;
  • 表格候选和质量报告;
  • 需要复核的最小裁块;
  • 模型候选意见和人工终审状态。

原件不覆盖,校正生成新的衍生文件。证据模式与结构模式不混写。模型候选不能回填正式文字。

这些文件看起来比一个 TXT 麻烦,却回答了律师真正会追问的问题:这句话从哪里来,机器哪里没有把握,谁核过,改动依据是什么。

程序通过,只证明程序按规则跑完

现在这套 glex-ocr 已经迭代到 0.4.0。当前自动化测试是 24 项全部通过,本地识别、结构处理和复核包都可以正常运行。

但我不会据此宣传一个统一准确率,也不会说律师可以放心把材料交给它自动处理。

自动化测试证明的是:工具会按规定保存原件、生成产物、标记复核项,并阻止视觉模型悄悄修改正式结果。

它不能证明下一份模糊复印件、手写收条或复杂流水一定认得对。

我给律师工作做这套本地 OCR,最后追求的并不是“机器永远不出错”。这不现实。

我更在意三件事:

错误能不能被发现,疑点能不能回到原页,最终由谁确认。

认出文字只是第一步。

让文字保留出处,让不确定性留在结果里,让机器不能越过律师替案件事实定稿,才是这套工具真正要解决的问题。


资料说明

本文分享的是一套仍在迭代的个人工作方法,不构成对任何 OCR 模型或部署方案的购买建议,也不承诺公开发布代码或 Skill。文中的真实测试已经去除客户名称、案情、金额、文件路径和其他可识别信息。

技术资料核验截至 2026 年 7 月 20 日:

文中版本、测试数量和返工经过,依据本机 glex-ocr 0.4.0 的现行实现,以及 v0.1 至 v0.4 的匿名化测试记录整理。自动测试通过只表示工具按既定规则运行,不代表任何新材料已经识别正确。