AI 时代:为什么 PDF 成了绊脚石
9.1 LLM 需要什么,PDF 给不了什么
9.1.1 问题的本质
大语言模型(LLM)消费的是文本序列——一串有序的 token。RAG(Retrieval-Augmented Generation)系统的核心流程是:
文档 → 文本提取 → 切分为 chunks → 向量化 → 存入向量数据库
用户提问 → 检索相关 chunks → 拼接为 prompt → LLM 生成回答
这个流程对输入的要求很明确:有序的、结构化的、纯文本。
而 PDF 给出的是什么?
- 无序的绘图指令(文字不按阅读顺序排列)
- 无结构信息(没有"这是标题""这是表格单元格"的标记)
- 混合内容(文字、图片、公式混在一起,边界模糊)
- 编码不透明(glyph ID 而非 Unicode,需要额外映射)
PDF 就像一张拼图——人眼看去是完整的画面,但让机器去"阅读",它只看到散落一地的碎片。
9.1.2 具体有多痛
一个真实场景:你有 500 份 PDF 格式的研究论文,想构建一个 RAG 系统回答关于这些论文的问题。
文字提取阶段会遇到的问题:
| 问题 | 频率 | 后果 |
|---|---|---|
| 多栏文字跨栏拼接 | 极高 | 左栏末行和右栏首行被拼成同一段 |
| 页眉页脚混入正文 | 高 | chunk 中混入无关的页码、期刊名 |
| 表格变成乱序碎片 | 高 | 表格的行列关系丢失 |
| 数学公式变乱码 | 高 | ∫₀^∞ 变成 "R 1 0" 或空白 |
| 图片标题脱离图片 | 中 | 无法关联图片和其描述文字 |
| 连字符断词残留 | 中 | "knowl-\nedge" 提取为 "knowl-" + "edge" |
| 脚注混入正文 | 中 | 脚注内容出现在段落中间 |
这些问题导致 RAG 系统的检索精度大幅下降——用户问的问题明明和某段内容相关,但因为提取出来的文本是碎片化的,向量相似度不够高而无法被检索到。
9.2 PDF 文字提取的技术路线
9.2.1 基于内容流解析
直接解析 PDF 内容流中的文字操作符(Tj/TJ/'/"),恢复文字内容和坐标。
代表工具:
- PyMuPDF (fitz):C 实现,快速但对复杂布局重排能力有限
- pdfplumber:基于 pdfminer,对表格和布局分析有专门优化
- pdfminer.six:纯 Python,解析最细致但速度最慢
import pdfplumber
with pdfplumber.open("paper.pdf") as pdf:
for page in pdf.pages:
# 提取文字(带布局分析)
text = page.extract_text(layout=True)
# 提取表格
tables = page.extract_tables()
for table in tables:
for row in table:
print(row)
局限性:
- 依赖内容流中的坐标信息来推断布局——如果坐标信息混乱,推断就失败
- 对扫描件完全无效(没有文字操作符)
- 数学公式、特殊符号的 Unicode 映射依赖 ToUnicode 表是否存在
9.2.2 基于视觉模型(Document AI)
把 PDF 页面渲染成图片,用计算机视觉模型来理解布局和内容。
代表工具/模型:
- Nougat(Meta):专为学术论文设计的 OCR + 结构识别模型,输出 Markdown
- Marker:开源的 PDF→Markdown 转换器,结合 OCR 和布局分析
- Docling(IBM):文档理解管线,支持表格/公式/图片分离
- GPT-4V / Claude Vision:直接"看"PDF 页面图片,理解内容
# 使用 Marker 转换 PDF 为 Markdown
from marker.convert import convert_single_pdf
full_text, images, metadata = convert_single_pdf(
"paper.pdf",
max_pages=None,
langs=["English", "Chinese"]
)
# full_text 是结构化的 Markdown(有标题、表格、公式)
优势:
- 不依赖 PDF 内部的文字层——扫描件也能处理
- 能理解视觉布局(多栏、侧边栏、浮动图片)
- 表格结构可以被视觉模型直接"看出来"
劣势:
- 速度慢(需要 GPU)
- 依赖模型精度——可能引入 OCR 错误
- 处理成本高
9.2.3 混合方法
实际生产中最常用的方案是混合的:
1. 先尝试直接提取文字层(快、准)
2. 如果文字层质量差(乱码、空白),降级到 OCR
3. 用布局分析模型确定阅读顺序和区域类型
4. 表格区域用专门的表格提取器
5. 公式区域用专门的公式识别模型
9.3 表格提取:PDF 的地狱
9.3.1 为什么表格是最难的
在 PDF 内部,表格不是"表格"——它是一堆文字和线条的集合:
% 一个 2×2 表格的 PDF 内容流
% 先画边框线
0 0 0 RG 0.5 w
100 700 m 400 700 l S % 顶部横线
100 680 m 400 680 l S % 中间横线
100 660 m 400 660 l S % 底部横线
100 700 m 100 660 l S % 左竖线
250 700 m 250 660 l S % 中间竖线
400 700 m 400 660 l S % 右竖线
% 再画文字
BT /F1 10 Tf
110 685 Td (Name) Tj
260 685 Td (Age) Tj
110 665 Td (Alice) Tj
260 665 Td (25) Tj
ET
提取器需要:
- 识别出哪些线条构成了表格边框
- 由边框推算出单元格的位置
- 把文字按坐标分配到对应的单元格中
- 处理合并单元格、跨页表格、无边框表格
无边框表格是最恶心的——很多学术论文的表格只有顶线和底线(三线表),没有竖线。提取器必须靠文字的对齐关系来推断列结构。
9.3.2 表格提取工具对比
# pdfplumber 的表格提取(基于线条检测)
import pdfplumber
with pdfplumber.open("paper.pdf") as pdf:
page = pdf.pages[3]
# 自定义表格检测参数
table_settings = {
"vertical_strategy": "text", # 无竖线时用文字对齐推断
"horizontal_strategy": "lines", # 用横线检测行
"min_words_vertical": 3, # 至少 3 个字对齐才算一列
}
tables = page.extract_tables(table_settings)
| 工具 | 方法 | 有边框表格 | 无边框表格 | 跨页表格 |
|---|---|---|---|---|
| pdfplumber | 线条 + 文字对齐 | ★★★★★ | ★★★☆☆ | ✗ |
| Camelot | 线条检测 / 文字流 | ★★★★☆ | ★★★☆☆ | ✗ |
| Tabula | Java,线条检测 | ★★★★☆ | ★★☆☆☆ | ✗ |
| Table Transformer | 视觉模型(DETR) | ★★★★☆ | ★★★★☆ | ★★☆☆☆ |
| GPT-4V | 多模态 LLM | ★★★★★ | ★★★★★ | ★★★☆☆ |
多模态 LLM 在表格提取上表现惊人——直接把表格截图发给它,让它输出 Markdown 或 CSV 格式,通常效果优于传统方法。代价是 API 成本和速度。
9.4 公式识别
9.4.1 PDF 中的数学公式
数学公式在 PDF 中的表示方式决定了它有多难提取:
LaTeX PDF 中的公式:每个符号是独立的 glyph,通过坐标精确定位。上标下标、分数线、积分号都是"画"出来的。没有任何语义标记表明这些符号合起来是一个公式。
Word PDF 中的公式:可能是 OMML(Office Math Markup Language)转换而来,有时会保留一定结构信息(如果使用了 Tagged PDF),但通常也是平坦化的。
图片形式的公式:有些旧文档或扫描件中,公式就是图片。提取文字层时直接丢失。
9.4.2 公式识别模型
| 模型 | 输入 | 输出 | 特点 |
|---|---|---|---|
| Nougat | 页面图片 | Markdown + LaTeX | 学术论文专用 |
| Pix2Tex | 公式截图 | LaTeX | 单公式识别 |
| MathPix | 截图 / PDF | LaTeX | 商业服务,精度最高 |
| im2latex | 图片 | LaTeX | 早期 encoder-decoder 模型 |
对于 RAG 系统来说,公式识别的最佳实践是:
- 用布局模型检测公式区域
- 把公式区域截图发给专用模型识别为 LaTeX
- 在最终的文本 chunk 中保留 LaTeX 源码
9.5 RAG 系统处理 PDF 的最佳实践(2026)
9.5.1 完整管线
PDF 输入
│
├─ [判断类型] ─→ 纯扫描件?→ 先 OCR (ocrmypdf)
│
├─ [文字提取] ─→ PyMuPDF 快速提取
│ │
│ └─ 质量检查(乱码率 > 10%?)→ 降级到视觉模型
│
├─ [布局分析] ─→ 检测表格/图片/公式/多栏区域
│
├─ [分区处理]
│ ├─ 正文 → 按段落切分
│ ├─ 表格 → 表格提取器 → Markdown 表格
│ ├─ 公式 → 公式识别 → LaTeX
│ └─ 图片 → 描述生成(可选,用 vision model)
│
├─ [重排序] ─→ 按阅读顺序组装文本
│
└─ [切分与嵌入] ─→ 语义切分 → 向量化 → 入库
9.5.2 常见陷阱与应对
陷阱 1:盲目用 PyPDF2/PyPDF 提取文字
# ❌ 最基础但质量最差的方案
from pypdf import PdfReader
reader = PdfReader("paper.pdf")
text = ""
for page in reader.pages:
text += page.extract_text() # 文字顺序可能完全错误
这种方法不做任何布局分析,多栏文字会交叉混合。
陷阱 2:chunk 切分不考虑 PDF 结构
# ❌ 按固定字符数切分——可能把表格切成两半
chunks = [text[i:i+500] for i in range(0, len(text), 500)]
# ✓ 按段落/章节/表格边界切分
陷阱 3:忽略元数据
PDF 中可能包含有用的元数据:标题、作者、创建时间、目录(Outline)。这些信息可以用于 chunk 的标注和检索排序。
import fitz
doc = fitz.open("paper.pdf")
# 获取元数据
print(doc.metadata) # {'title': '...', 'author': '...', ...}
# 获取目录结构
toc = doc.get_toc()
for level, title, page in toc:
print(f"{' ' * level}{title} (page {page})")
9.5.3 成本与质量的权衡
| 方案 | 质量 | 速度 | 成本/页 | 适用场景 |
|---|---|---|---|---|
| PyMuPDF 直接提取 | ★★★☆☆ | ★★★★★ | ~$0 | 简单文档,大批量 |
| pdfplumber + 布局分析 | ★★★★☆ | ★★★☆☆ | ~$0 | 有表格的文档 |
| Marker (开源) | ★★★★☆ | ★★★☆☆ | ~$0 (需 GPU) | 学术论文 |
| Docling (IBM) | ★★★★☆ | ★★★☆☆ | ~$0 | 企业文档 |
| GPT-4V 逐页识别 | ★★★★★ | ★★☆☆☆ | ~$0.05/页 | 高质量要求,小批量 |
| 商业方案 (Azure/AWS) | ★★★★★ | ★★★★☆ | ~$0.01/页 | 企业级产品 |
9.6 PDF 有可能被替代吗?
9.6.1 替代品的尝试
| 格式/方向 | 特点 | 为什么没能替代 PDF |
|---|---|---|
| HTML | 响应式、可搜索、语义化 | 无法保证视觉一致性 |
| EPUB | 流式布局、适合阅读 | 不适合精确排版(合同、论文) |
| DOCX/ODF | 可编辑、结构化 | 渲染依赖软件版本,不同设备显示不同 |
| Markdown | 纯文本、易解析 | 表达能力太弱,无法做精确排版 |
| LaTeX 源码 | 精确、可重编译 | 需要编译环境,非技术用户无法使用 |
9.6.2 PDF 为什么"杀不死"
PDF 解决的核心问题——跨平台视觉一致性 + 不可篡改性 + 独立性(无外部依赖)——至今没有其他格式能同时满足。
- 合同需要双方看到完全相同的内容 → PDF
- 法院判决书需要存档几十年后仍能打开 → PDF/A
- 印刷厂需要精确到 0.01mm 的输出 → PDF
- 学术出版需要固定排版的版本记录 → PDF
只要"纸"的概念还存在——需要固定尺寸、固定布局、所有人看到完全相同的东西——PDF 就不会消亡。
9.6.3 一个可能的演进方向
与其替代 PDF,更现实的路径是增强 PDF:
- 强制 Tagged PDF:如果所有 PDF 都包含完整的结构标记树,文字提取问题就解决了 80%
- PDF 2.0 的改进:更严格的规范、更好的 Unicode 要求
- Associated Files:PDF 2.0 允许嵌入"关联文件"——比如在 PDF 中嵌入原始的 LaTeX 源码或 Markdown,让需要结构化数据的系统直接使用源文件
- AI 辅助解析:与其改变格式,不如训练更好的模型来理解现有的 PDF
9.7 本章小结
PDF 在 AI 时代的困境不是设计缺陷——它完美地实现了 1993 年设定的目标:让所有人看到一模一样的文档。只是这个目标和 2026 年的需求(让机器理解文档内容)之间存在根本性张力。
三十年来,PDF 优化的方向始终是**"人怎么看"而不是"机器怎么读"**。当 AI 突然需要读懂这几十亿份 PDF 时,我们才发现这个全世界最普及的文档格式给机器留的窗口少得可怜。
这不是 PDF 的错——它只是忠实地执行了三十年前的设计哲学。但它确实是今天 AI 工程中一块难以绕过的绊脚石。