当PyMuPDF看不到表格:使用Azure Layout解析PDF用于RAG

当PyMuPDF看不到表格:使用Azure Layout解析PDF用于RAG

当PyMuPDF看不到表格:使用Azure Layout解析PDF用于RAG

📰 来源:Towards Data Science | 📅 翻译日期:2026年6月13日
🔗 原文查看原文
🤖 翻译:DeepSeek AI · 仅供参考

本文是《企业文档智能》系列的解析配套文章,该系列用四大模块构建企业级RAG系统。第5篇(文档解析)使用PyMuPDF(fitz)构建了解析器。本篇配套文章保持相同目标和相同的关系表,但将引擎替换为 Azure Layout(prebuilt-layout模型),这是一个更丰富的包,能恢复fitz无法处理的内容。这个差距就是我们的起点。

本篇配套文章的位置

它扩展了第5篇(文档解析),属于第二部分(四大模块),使用不同的解析引擎——作者供图

PyMuPDF(fitz) 速度快、免费,且对干净文本精确无误。但它在三个地方会“失明”,而每个地方正是企业级RAG悄然失效之处。

  • 合同第14页上的表格。Fitz逐个读取单元格并拼接它们,列结构丢失。"Renewal fee 500 Setup fee 200" 进入分块,你的模型需要猜测哪个数字对应哪个费用。
  • 文档末尾粘贴的扫描修正页。Fitz读取原生页面,对扫描页返回空字符串。用户得不到关于修正页的答案,因为解析器从未读取它。
  • 包含文本的图形。带有轴标签的图表。签名的印章。电子表格的截图。Fitz返回图像的边界框,图像内部的文本丢失。

Azure Document Intelligence 能读取以上所有内容。这是一个专有的Microsoft Azure云服务,受Microsoft在线服务条款约束。prebuilt-layout模型返回:原生表格单元格(行、列、标题)、每页OCR文本(原生或扫描)、包含内部文本的图形、段落角色(title、sectionHeading、figureCaption、tableCaption)。一次调用。与fitz相同的关系表,其中一半得到了丰富。

下游管道不关心是哪个引擎生成了字典。检索、生成、标注读取行。它们从不读取PDF。

相同的关系表,Azure丰富了其中一半——作者供图

1. Fitz的盲区

四种情况。每种情况下,fitz遗漏,Azure生效。

1.1. 表格:fitz返回散词,Azure返回单元格

合同表格有行和列。标签"Renewal fee"位于第1列,值500位于第2列。Fitz从上到下读取页面,每个文本段输出一行。一行的四个单元格以四个松散单词返回。有时,如果下方行的y坐标接近,单元格会混入。下游的分块器看到的是单词汤。使表格成为表格的行列结构消失了。

Azure的prebuilt-layout模型将每个表格检测为结构化对象。result.tables 是一个表格列表,每个表格包含按 (row_index, column_index) 索引的单元格。标题行被标记(cell.kind == "columnHeader")。单元格内容就是作者键入的精确文本。我们将表格展平为markdown行,使其像其他内容一样存在于 line_df 中。一个四单元格行 "Renewal fee | 500 | Setup fee | 200" 成为 line_df 中的一行,包含该markdown文本。标题行添加 | --- | --- | ... | 分隔符,以便下游模型读回结构。

1.2. 图像:fitz返回边界框,Azure返回文本

许多PDF包含带文本的图形。带有框标签的架构图。带有轴刻度和图例的图表。签名印章。电子表格的嵌入式截图。Fitz将每个图像作为边界框和原始字节返回。内部文本对解析器不可见。

Azure的OCR在每页上运行,包括图形区域内的像素。对于每个图形,我们收集所有边界框位于图形区域内的Azure单词,并将其合并为 ocr_text。"Multi-Head Attention Concat Linear h" 现在存在于Attention论文第4页图形的 image_df.ocr_text 中。即使答案位于图形内部的文本,检索也能匹配关于"multi-head attention"的问题。

fitz返回边界框和空文本单元格;Azure的OCR恢复图形内打印的标签——作者供图

1.3. 扫描页面:fitz返回空,Azure返回OCR

一份30页的原生合同在末尾粘有10页扫描修正页。Fitz读取原生页面,对扫描页返回空字符串。解析器不会标记这一点。下游管道安静地覆盖了文档的75%。用户不知道25%缺失了。

Azure对每页运行OCR,无论来源。原生页面和扫描页面通过相同的 result.pages[i].lines 路径返回,形状相同。line_df 上的 parsing_method 列让下游代码区分哪些行由哪个引擎生成。parsing_summary 字典中的 n_pages 字段匹配文档的实际页数,而不仅仅是包含原生文本的页数。

扫描件是像素,不是字符;fitz没有要读取的文本层,Azure对页面进行OCR——作者供图

1.4. 标题和引文:fitz使用正则,Azure有明确角色

Fitz通过每行开头的正则表达式(^Figure \d+\b, ^Table \d+\b)检测图形/表格标题。当标题像"Figure 2"时有效,但会遗漏其余部分("Fig. 2"、多行换行)。还存在误报:正文中以"Figure 2"开头的句子会被当作标题,而实际是提及。

通过正则匹配标题的两种失败模式(遗漏的"Fig."标题、错误标记的正文提及),Azure的段落角色避免了——作者供图

Azure的 paragraphs 字段包含角色标签:结果中的每个段落都带有类似 "figureCaption""tableCaption""title""sectionHeading" 的标签,告诉我们它是什么类型的块,无需任何正则。"figureCaption""tableCaption" 直接填充 object_registry"title""sectionHeading" 重建目录。该标签是Azure布局模型命名块的功能;fitz没有等价物。仍然通过相同的正则从标题文本中提取 (object_type, object_id) 连接键,以便 cross_ref_df 以相同方式回连。

输出格式与下游管道

最终输出保持与fitz完全相同的四个DataFrame:page_dfline_dfimage_dfobject_registry。但每个字段都被Azure的JSON充实。下游的检索索引、生成上下文、标注流程无需更改。代码路径现在处理更多情况,但没有新概念。


📌 *本文由 DeepSeek AI 自动翻译排版,如有不准确之处欢迎指正* 🏠 [返回首页](https://www.suiyuanlu.cn) · 📖 [查看原文](https://towardsdatascience.com/when-pymupdf-cant-see-the-table-parse-pdfs-for-rag-with-azure-layout/)
©版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

评论已关闭