主题
字号
CHAPTER 09 ≈ 22 MIN READ

AI 时代:为什么 PDF 成了绊脚石

9.1 LLM 需要什么,PDF 给不了什么

9.1.1 问题的本质

大语言模型(LLM)消费的是文本序列——一串有序的 token。RAG(Retrieval-Augmented Generation)系统的核心流程是:

文档 → 文本提取 → 切分为 chunks → 向量化 → 存入向量数据库
用户提问 → 检索相关 chunks → 拼接为 prompt → LLM 生成回答

这个流程对输入的要求很明确:有序的、结构化的、纯文本

而 PDF 给出的是什么?

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/'/"),恢复文字内容和坐标。

代表工具:

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)

局限性:

9.2.2 基于视觉模型(Document AI)

把 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(有标题、表格、公式)

优势:

劣势:

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

提取器需要:

  1. 识别出哪些线条构成了表格边框
  2. 由边框推算出单元格的位置
  3. 把文字按坐标分配到对应的单元格中
  4. 处理合并单元格、跨页表格、无边框表格

无边框表格是最恶心的——很多学术论文的表格只有顶线和底线(三线表),没有竖线。提取器必须靠文字的对齐关系来推断列结构。

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 中的表示方式决定了它有多难提取:

9.4.2 公式识别模型

模型 输入 输出 特点
Nougat 页面图片 Markdown + LaTeX 学术论文专用
Pix2Tex 公式截图 LaTeX 单公式识别
MathPix 截图 / PDF LaTeX 商业服务,精度最高
im2latex 图片 LaTeX 早期 encoder-decoder 模型

对于 RAG 系统来说,公式识别的最佳实践是:

  1. 用布局模型检测公式区域
  2. 把公式区域截图发给专用模型识别为 LaTeX
  3. 在最终的文本 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 就不会消亡。

9.6.3 一个可能的演进方向

与其替代 PDF,更现实的路径是增强 PDF

  1. 强制 Tagged PDF:如果所有 PDF 都包含完整的结构标记树,文字提取问题就解决了 80%
  2. PDF 2.0 的改进:更严格的规范、更好的 Unicode 要求
  3. Associated Files:PDF 2.0 允许嵌入"关联文件"——比如在 PDF 中嵌入原始的 LaTeX 源码或 Markdown,让需要结构化数据的系统直接使用源文件
  4. AI 辅助解析:与其改变格式,不如训练更好的模型来理解现有的 PDF

9.7 本章小结

PDF 在 AI 时代的困境不是设计缺陷——它完美地实现了 1993 年设定的目标:让所有人看到一模一样的文档。只是这个目标和 2026 年的需求(让机器理解文档内容)之间存在根本性张力。

三十年来,PDF 优化的方向始终是**"人怎么看"而不是"机器怎么读"**。当 AI 突然需要读懂这几十亿份 PDF 时,我们才发现这个全世界最普及的文档格式给机器留的窗口少得可怜。

这不是 PDF 的错——它只是忠实地执行了三十年前的设计哲学。但它确实是今天 AI 工程中一块难以绕过的绊脚石。