处理数百万份 PDF,以及为何 Gemini 2.0 能改变一切 [译]

在任何 RAG 系统中,将 PDF 进行分块(将其转换为简洁且机器可读的文本片段)一直是个头疼的问题。市面上既有开源也有专有的解决方案,但它们都没有在准确性、可扩展性和成本效益之间达到理想的平衡。

  1. 现有的 端到端模型 在面对真实世界文档中复杂的版面布局时仍然力不从心。其他常见的开源方案通常需要组合多个专用的机器学习模型,用于版面检测、表格解析以及 Markdown 转换等环节。比如 NVIDIA 的 nv-ingest,需要在 Kubernetes 上跑 8 个服务,加上 2 块 A/H100 GPU,整体部署相当繁琐,而且性能也不算理想。

  2. 付费的专有解决方案通常也在复杂布局和保持一致的高准确度方面表现不佳,同时在大规模数据集上的成本会成倍上升。对于我们需要处理上亿页文档的场景,使用商业供应商的价格几乎不可接受。

在理论上,大型基础模型似乎是处理这类任务的理想选择。但在实际应用中,它们并没有表现出比商用解决方案更高的成本效益,而且一些微妙的不一致性也会给生产环境带来难题。举例来说,GPT-4o 在解析表格时,常常会平白生成一些额外的单元格,导致在生产系统中难以直接使用。

Gemini Flash 2.0 的出现

Gemini Flash 2.0 的到来让人眼前一亮。
虽然从开发者体验上来看,我个人觉得谷歌还是落后于 OpenAI,但是他们在性价比上确实无可挑剔。不像 1.5 Flash 会出现各种细微的不一致而难以在生产环境中依赖,我们在内部测试时发现,Gemini Flash 2.0 不仅能实现接近完美的 OCR 准确率,而且价格也相当便宜。

提供方 模型 PDF 转换为 Markdown,每美元可处理的页数

Gemini

2.0 Flash

🏆 ≈ 6,000

Gemini

2.0 Flash Lite

≈ 12,000 (尚未测试)

Gemini

1.5 Flash

≈ 10,000

AWS Textract

商用服务

≈ 1000

Gemini

1.5 Pro

≈ 700

OpenAI

4o-mini

≈ 450

LlamaParse

商用服务

≈ 300

OpenAI

4o

≈ 200

Anthropic

claude-3-5-sonnet

≈ 100

Reducto

商用服务

≈ 100

Chunkr

商用服务

≈ 100

注:上述所有 LLM 提供方均基于批量定价估算。

准确度是否会因此降低?

在文档解析的所有环节中,最具挑战性的是表格的识别和提取。复杂的布局、不常规的排版以及不一致的数据质量,都让表格提取变得异常困难。

因此,评估模型性能时,表格往往是最合适的“试金石”。我们使用了 Reducto 的一部分 rd-tablebench 数据集来测试模型。这些样例都是在真实环境中采集的,包括模糊的扫描件、多语言文本以及复杂的表格结构,远比科研论文中的示例更加考验模型的能力。

下面是测试结果(准确率通过 Needleman-Wunsch 算法 测得):

提供方 模型 准确率 备注

Reducto

0.90 ± 0.10

Gemini

2.0 Flash

0.84 ± 0.16

近乎完美

Anthropic

Sonnet

0.84 ± 0.16

AWS Textract

0.81 ± 0.16

Gemini

1.5 Pro

0.80 ± 0.16

Gemini

1.5 Flash

0.77 ± 0.17

OpenAI

4o

0.76 ± 0.18

有细微的数值“幻觉”

OpenAI

4o-mini

0.67 ± 0.19

表现较差

Gcloud

0.65 ± 0.23

Chunkr

0.62 ± 0.21

Reducto 自家的模型在这个基准上仍稍强于 Gemini Flash 2.0(0.90 vs 0.84)。不过仔细查看那些低分样例,其中大多是一些结构层面的微小差异,不会对 LLM 理解表格的内容造成实质影响。

更重要的是,我们几乎没有看到数字信息本身被误读的情况,说明 Gemini 出现的“错误”大多数都只是格式层面的差异,而不是对数据本身的误识。后文的 [1] 处列出了具体的失败案例示例。

除了表格解析之外,Gemini 在 PDF 到 Markdown 转换的其他所有环节也都能稳定输出接近完美的结果。综合来看,你可以构建一个流程简单、可大规模扩展且成本低廉的文档索引管线。

如果我们再加上分块呢?

Markdown 提取只是第一步。如果要真正将文档应用到 RAG 流程中,我们还需要将文档拆分成更小、在语义上高度相关的段落。

最新的研究 表明,在这一步中使用大型语言模型(LLM)能在检索准确度方面优于其他策略。这其实也很好理解 —— LLM 善于理解上下文和辨别语义边界,能生成更符合自然语义的片段。

问题在于:成本高昂。到目前为止,基于 LLM 的分块方法在大规模应用时的费用几乎不可承受。但由于有了 Gemini Flash 2.0,这一点又被彻底改变。它的价格让大规模使用 LLM 进行文档分块成为了一种切实可行的方案。

举例来说,我们可以用 Gemini Flash 2.0 解析总计超过一亿页的文档,花费在 5000 美元左右,甚至比一些 向量数据库托管服务 的月度账单还要低。

甚至可以把分块和 Markdown 提取结合起来。从我们非常有限的测试来看,这对提取质量几乎没有任何负面影响,依然能保持优异的准确度。

CHUNKING_PROMPT = """\
OCR the following page into Markdown. Tables should be formatted as HTML. 
Do not sorround your output with triple backticks.

Chunk the document into sections of roughly 250 - 1000 words. Our goal is 
to identify parts of the page with same semantic theme. These chunks will 
be embedded and used in a RAG pipeline. 

Surround the chunks with <chunk> </chunk> html tags.
"""

但是我们失去了边界框信息?

虽然 Markdown 提取和分块在文档解析上能解决很多问题,但也带来一个关键的限制:无法保留文字在原始 PDF 中的坐标信息(bounding box)。这意味着用户无法在可视化界面中准确定位某段文本在源文档中的位置,引用通常只能精确到页面号或某段文字。

这样一来,用户对数据来源的信任度就会下降。边界框信息对于将提取到的数据和源文档的精确位置对照起来至关重要,可以让用户清楚地知道自己看到的内容并不是幻觉或被篡改。

这也是我对大多数分块库最不满意的地方。


一个在原文档中展示引用位置的示例。

可喜的是,LLM 在空间理解方面也表现出惊人的潜力。(Simon Willis 的示例里,Gemini 可以为一大群紧挨在一起的鸟生成相当准确的边界框)让人感觉这项能力完全可以用来把文本和文档中的确切位置对应起来。

这本来也是我们的一个重要期望。但现实情况是,Gemini 目前在这方面依然很吃力。无论我们怎么提示,它生成的边界框都相当离谱,说明在预训练数据中对文档排版的学习还明显不足。不过,我认为这是一个暂时的问题。

如果谷歌能在训练中加入更多文档结构数据 —— 或者针对文档版面进行特定的微调 —— 那么我们就很有可能解决这个问题。它的潜力是毋庸置疑的。

GET_NODE_BOUNDING_BOXES_PROMPT = """\
Please provide me strict bounding boxes that encompasses the following text in the attached image? I'm trying to draw a rectangle around the text.
- Use the top-left coordinate system
- Values should be percentages of the image width and height (0 to 1)

{nodes}
"""


这是地面真实标注的示例,可以看到三组明显的边界框,用来分别圈出表格的不同部分。

(上面只是一个示例提示,我们其实尝试过很多种方法,但截至 2025 年 1 月,仍然无法得到理想效果。)

为什么这些进展如此重要

综合利用这些方案,我们能够构建一个既简单又能大规模扩展、且在成本上极具竞争力的文档索引流水线。我们未来会把这套流程开源出来,当然也相信很多其他团队会做出类似的项目。

最关键的是,一旦我们在文档解析、分块和边界框检测这三大难题上达成较为完善的解决方案,就基本意味着解决了将文档“喂给”LLM 的问题(仍然会有一些细节需要注意)。这个进展让我们距离“让文档解析变得极其简单,不论应用场景”又近了一步。

P.S. 如果你在谷歌工作,对 AI 初创公司的优惠计划有任何建议,欢迎给我发邮件


附录

[1] 关于错误案例的分析
我们对比了 Gemini 与 Reducto 的 HTML 输出,以及原始 PDF,发现大多是结构上的微小差异。