轻量级大模型 OCR 技术实践:从发票识别到复杂 PDF 文档解析

举报
yd_54922183 发表于 2026/10/20 09:38:09 2026/10/20
【摘要】 近年来,视觉语言模型(VLM)开始进入文档解析领域,PaddleOCR-VL、MinerU2.5 等模型以约十亿级参数实现了文字识别、版面分析和结构化输出。本文介绍这类模型的工作原理,并通过发票信息提取、PDF 转 Markdown 两个案例,展示如何用 Python 将非结构化文档转成可供业务系统和大语言模型使用的数据。

一、OCR 为什么也开始使用大模型了?

假设有一张发票,上面写着:

电子发票(普通发票)

发票号码:12345678901234567890
开票日期:2026年10月20日

商品名称        金额
办公用品       200.00
税额            12.00

价税合计:¥212.00

传统 OCR 可以把文字识别出来,但可能出现一个问题:它知道有“200.00”和“12.00”,却不一定知道哪个数字对应金额、哪个对应税额。

到了复杂 PDF,这个问题更加明显。

一页文档可能同时包含双栏正文、表格、公式、图片和脚注。简单地把识别结果按坐标拼接,可能让原本正确的内容变得难以阅读。

所以,现代文档解析要解决的其实是两个问题:

  1. OCR: 图片里有哪些文字?
  2. Document Parsing: 这些文字、表格和公式在文档中是什么结构,应该按照什么顺序阅读?

这正是视觉语言模型(Vision-Language Model,VLM)进入 OCR 领域的重要原因。

1.1 技术原理

传统 OCR 往往采用:

文档图片
   │
   ▼
文字检测
   │
   ▼
文字区域裁剪
   │
   ▼
文字识别
   │
   ▼
纯文本

而以 PaddleOCR-VL 为代表的模型,可以采用:

文档图片 / PDF
       │
       ▼
   版面检测
       │
       ├── 标题
       ├── 正文
       ├── 表格
       └── 公式
       │
       ▼
 视觉语言模型 VLM
       │
       ▼
文字与结构恢复
       │
       ▼
 Markdown / JSON

以 PaddleOCR-VL 初代版本为例,其核心视觉语言模型只有约 0.9B 参数,由动态分辨率视觉编码器和 ERNIE 语言模型组成。

视觉编码器负责理解图片内容,语言模型负责生成对应的文字及结构表示。

但这里有个细节:0.9B 指的是核心 VLM,并不是整条文档解析流水线的总参数量。完整系统还包括版面分析等模块。

二、有哪些值得关注的轻量级 OCR 模型?

目前,比较有代表性的开源模型有:

模型 参数规模 特点
PaddleOCR-VL 0.9B 核心 VLM 多语言 OCR、表格、公式及文档结构解析
MinerU2.5 1.2B 复杂 PDF、论文、阅读顺序与表格还原
dots.ocr 1.7B 语言模型基础 将版面检测与内容识别整合进 VLM

以上是对应模型版本的规模,不代表这些项目的所有后续版本都具有相同参数量。

相关开源项目:

如果只是识别几行清晰文字,传统轻量 OCR 可能已经足够;但如果需要保留复杂文档的结构,VLM 文档解析模型通常更值得测试。

下面两个案例统一使用 PaddleOCR-VL 初代版本,方便复现。

三、实践案例一:发票 OCR 与关键信息提取

3.1 业务场景

假设公司财务每天需要处理大量发票。

我们的目标是从发票图片中获取:

  • 发票号码
  • 开票日期
  • 价税合计金额

最终转换为 JSON,供财务系统入库。

整个过程可以分为两步:先通过模型识别文档,再通过规则提取字段。

3.2 环境准备

建议使用独立 Python 虚拟环境。先按照 PaddleOCR 官方安装指南安装与 CPU 或 CUDA 环境兼容的 PaddlePaddle 3.2.1 及以上版本,再安装文档解析组件:

python -m pip install -U "paddleocr[doc-parser]"

首次运行通常需要下载模型文件。以下代码显式使用 v1,对应 PaddleOCR-VL-0.9B 核心模型。

3.3 Python 实现

准备一张发票图片 invoice.png:

import re
import json
from pathlib import Path
from paddleocr import PaddleOCRVL

# 加载完整文档解析流水线
parser = PaddleOCRVL(pipeline_version="v1")

# 识别发票并保存结果
out = Path("output/invoice")
out.mkdir(parents=True, exist_ok=True)

for result in parser.predict(input="invoice.png"):
    result.save_to_markdown(save_path=str(out))
    result.save_to_json(save_path=str(out))

# 读取生成的 Markdown
text = (out / "invoice.md").read_text(
    encoding="utf-8"
)

# 简单字段提取:适用于固定格式演示
def extract(pattern):
    match = re.search(pattern, text)
    return match.group(1) if match else None

invoice_data = {
    "invoice_number": extract(
        r"发票号码[::\s]*([0-9]{8,20})"
    ),
    "date": extract(
        r"开票日期[::\s]*([\d年月日./-]+)"
    ),
    "total_amount": extract(
        r"价税合计[^\d]{0,20}(\d+\.\d{2})"
    )
}

print(json.dumps(
    invoice_data,
    ensure_ascii=False,
    indent=2
))

假设发票内容如前面的示例,且识别文本符合字段匹配规则,预期输出为:

{
  "invoice_number": "12345678901234567890",
  "date": "2026年10月20日",
  "total_amount": "212.00"
}

注意,这里展示的是预期结果,不是实际运行测试。

3.4 这个方案有什么局限?

你可能已经发现:代码中仍然使用了正则表达式。

没错,OCR 模型负责识别文档,并不意味着它已经完成了可靠的业务字段抽取。

如果发票模板发生变化,例如价税合计在表格的另一列,简单的正则表达式就可能失效。

实际生产中,更合理的架构是:

发票图片
   │
   ▼
OCR / 文档解析
   │
   ▼
识别文本及版面结构
   │
   ▼
信息抽取模型或规则引擎
   │
   ▼
字段校验
   │
   ▼
财务系统

对于金额、税号等关键字段,还应增加格式校验、金额一致性检查和必要的人工复核。

四、实践案例二:复杂 PDF 转 Markdown,构建 AI 知识库

4.1 为什么不能直接提取 PDF 文字?

假设我们有一份几十页的技术报告:

  • 正文采用双栏排版。
  • 中间穿插数据表格。
  • 包含数学公式。
  • 部分页面来自扫描件。

如果直接使用普通 PDF 文本提取工具,很可能出现这种结果:

第一列第一行
第二列第一行
第一列第二行
第二列第二行

原本连续的两段正文被混在一起。

对于知识库 RAG 而言,这可能比完全识别不到文字更麻烦:检索系统会把错误拼接的内容当作真实语义。

因此,我们希望把 PDF 转换成尽量保留标题、正文、表格和公式结构的 Markdown。

4.2 Python 实现

PaddleOCR-VL 提供了多页结果重构功能。

from pathlib import Path
from paddleocr import PaddleOCRVL

# 初始化模型
parser = PaddleOCRVL(pipeline_version="v1")

pdf_file = "technical_report.pdf"
out = Path("output/report")
out.mkdir(parents=True, exist_ok=True)

# 逐页解析
pages = list(
    parser.predict(input=pdf_file)
)

# 重构多页结构
results = parser.restructure_pages(
    pages,
    merge_tables=True,
    relevel_titles=True,
    concatenate_pages=True
)

# 保存 Markdown 和 JSON
for result in results:
    result.save_to_markdown(save_path=str(out))
    result.save_to_json(save_path=str(out))

print("文档解析完成")

这里三个参数比较关键:

参数 作用
merge_tables=True 尝试合并跨页表格
relevel_titles=True 尝试恢复多级标题关系
concatenate_pages=True 合并多页结果

假设原 PDF 包含:

第一章 技术方案

1.1 模型性能

模型        准确率
模型A       92.3%
模型B       94.1%

解析后的 Markdown 可能类似:

# 第一章 技术方案

## 1.1 模型性能

| 模型 | 准确率 |
|---|---|
| 模型A | 92.3% |
| 模型B | 94.1% |

其中公式通常会尝试保留为 LaTeX,表格则可能输出为 Markdown 或 HTML 结构。

实际输出取决于原始文档质量和模型识别结果,并不能保证所有跨页表格都被正确合并。

4.3 接入 RAG 系统

生成 Markdown 后,便可以接入上一篇介绍的 Embeddings 模型:

原始 PDF
    │
    ▼
PaddleOCR-VL
    │
    ▼
结构化 Markdown
    │
    ▼
文本分块 Chunking
    │
    ▼
Embeddings
    │
    ▼
向量数据库
    │
    ▼
知识检索 + LLM 回答

这样就能把原本不适合直接处理的扫描 PDF 转换成 AI 可以检索的知识内容。

不过,真实项目里还要做好两件事:保留页码和原文位置,方便答案溯源;对表格、公式设置合理的分块策略,避免它们被拆散。

五、生产环境中有哪些坑?

1. 模型会把文字“认错”,也可能直接编造内容。

VLM 具备文本生成能力,但这不代表它可以随意补全文档。遇到模糊文字、印章遮挡或低分辨率图片时,必须警惕模型生成原图中不存在的内容。

2. 轻量模型不等于一定跑得快。

参数量虽然小,但高分辨率图片、版面检测、多区域裁剪以及逐页推理都会带来额外开销。

真正需要衡量的是端到端处理时间,而不只是 VLM 的模型推理速度。

3. 不要把所有 PDF 都送进 OCR。

对于可以直接提取文字、结构相对简单的电子 PDF,优先使用 PyMuPDF 等工具往往更省资源。

OCR 更适合扫描件、图片 PDF 和直接提取效果不佳的复杂页面。

4. 评估指标要看业务。

建议重点关注:

指标 评价内容
CER 文字字符错误率
TEDS 表格结构识别质量
字段准确率 发票号码、金额等字段是否正确
阅读顺序准确率 多栏文档是否按正确顺序还原
P95 延迟 文档处理的耗时表现

对于财务票据,金额和发票号码正确可能比整页 CER 更重要;对于论文解析,表格和公式结构可能是核心。

六、总结

OCR 技术正在经历一个很有意思的变化:它不再只是把图片转成文字,而是逐渐具备了理解文档布局和恢复内容结构的能力。

通过本文两个案例,我们看到了两种典型应用:

  • 发票 OCR: 将文档图片转成文字,再进一步抽取业务字段。
  • PDF 文档解析: 将复杂文档还原成 Markdown,为 RAG 和知识库提供可用数据。

把它与前面介绍的 ASR、Embeddings 和决策模型放在一起,可以形成更完整的 AI 系统:

图片 / 扫描件 / PDF
          │
          ▼
    OCR 文档解析
          │
          ▼
       文本内容
          │
          ▼
    Embeddings 检索
          │
          ▼
    LLM / 决策模型
          │
          ▼
      业务处理

ASR 解决“听到了什么”,OCR 解决“文档里有什么”,Embeddings 解决“哪些内容相关”,决策模型和 LLM 则进一步完成判断与处理。

但有一点始终值得记住:

一个模型能够识别文字,不代表它能够理解所有业务含义;一个模型能够还原表格,也不代表表格里的数字就一定正确。

真正可靠的文档 AI 系统,不仅需要好的模型,还需要结构校验、业务规则和必要的人工复核。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。