RAG 处理 PDF 表格时怎么避免只提取正文文本
来源:17golang原创
时间:2026-09-08 09:58:52 244浏览 收藏
PDF 放进 RAG 后只能搜到正文,通常不是向量数据库的问题,而是摄取阶段已经把表格和图片丢掉了。处理这类文档时,应先把页面拆成正文、表格、图片等元素,再为每类元素保留合适的文本或视觉表示,并把页码、元素类型写进元数据。这样检索结果才有机会回答“表格中的数值是多少”,而不是只返回表格前后的说明段落。
最小可行方案是:PDF 解析开启布局和表格识别,表格保留结构化文本或 HTML,图片保留图像/描述;随后按内容类型建立表示,召回时检查 page 与 element_type,最后再送入生成模型。
- 文本抽取速度快,但会漏掉扫描页、表格结构和图表语义。
- 表格不要只拼成无列名的长字符串,至少保留行列关系、页码和元素类型。
- 多模态检索不是“所有内容都转图片”,而是按查询和文档形态组合文本、结构化表格与视觉表示。
先把 PDF 拆成可检索的元素,而不是一段正文
先抽查一份真实 PDF:能否复制文字、表格是否有清晰行列、扫描页是否只有图片、图表旁边是否有解释。如果直接采用 text-only 或快速规则抽取,最容易得到一串连续段落;表格的列关系、图片里的文字和页面布局就不会进入索引。
NVIDIA RAG Blueprint 的配置文档把表格、图像、信息图和 PDF 解析方式拆成独立选项;其摘要文档也明确区分了跳过 OCR/表格/图片处理的浅层文本路径与完整多模态摄取。独立实验时,Unstructured 的 PDF 表格示例则使用 hi_res 和表格结构推断,并从元素元数据取 HTML。两种路径的共同原则是:先保留元素边界,再谈切块。

摄取阶段同时保留结构和可回溯元数据
下面的示例只演示一个独立的抽取检查点,不代表所有 RAG 框架的固定 API。关键不在于把表格转成某种特定格式,而在于每个元素都能回到原页,并且表格仍能表达行列关系。
from unstructured.partition.pdf import partition_pdf
# hi_res 让解析器关注页面布局;表格元素保留结构推断结果
elements = partition_pdf(
filename="reports/quarterly.pdf",
strategy="hi_res",
skip_infer_table_types=False,
)
records = []
for element in elements:
# 只保存可回溯字段,避免把整个对象直接塞进向量库
kind = getattr(element, "category", "Unknown")
metadata = getattr(element, "metadata", None)
page = getattr(metadata, "page_number", None)
table_html = getattr(metadata, "text_as_html", None)
text = table_html if kind == "Table" and table_html else element.text
if text and page is not None:
records.append({
"text": text,
"page": page,
"element_type": kind,
})
# 写入索引前检查表格是否仍带有列结构
table_count = sum(item["element_type"] == "Table" for item in records)
print({"records": len(records), "tables": table_count})
这里的检查结果只回答“有没有识别出表格”,不能证明表格数值一定正确。生产环境还要抽样比对原 PDF:合并单元格、跨页表头和扫描表格往往需要 OCR 或更强的布局模型。若使用 NVIDIA 的摄取服务,可从其配置项启用表格抽取、图片抽取或更强的 PDF 解析;是否开启应结合 GPU、延迟和文档复杂度决定。
为表格和图片选择不同的表示通道
正文通常适合文本 embedding;表格可以同时保留“可读文本”和 HTML/结构化版本;图片则需要原图、图片描述或视觉 embedding。不要为了追求“多模态”把每个正文段落都渲染成图片,这会增加摄取成本,也让精确的关键词匹配更难。
NVIDIA 的多模态检索文档说明,VLM embedding 可以让文本段落、PDF 页面、表格、图表和图片元素由多模态模型表示;结构化元素或整页作为图像的模式则应根据 PDF 工作流选择,并注意实验性能力和资源要求。对表格问答来说,一个稳妥的组合是:表格结构化文本负责列名、单位和精确值,视觉表示负责复杂版式或图片化表格,二者都带 page 与 element_type。
| 元素 | 建议保存 | 召回核对 |
|---|---|---|
| 正文 | 纯文本、页码、标题层级 | 文本相似度与来源页 |
| 表格 | 行列结构、HTML/规范化文本、页码 | 列名、单位、表格类型 |
| 图片或图表 | 原图或描述、页码、区域类型 | 图片是否真的来自目标页 |

检索时要验证召回的不是“看似相关的正文”
查询“第二季度毛利率是多少”时,召回结果应至少能指出表格所在页、元素类型和对应片段。如果前五条结果全是“本季度经营情况如下”之类正文,说明切块或表示选择仍在丢表格。可以把召回记录先转成证据卡片,再交给生成模型:
def evidence_card(hit):
# 让生成阶段知道证据来自哪一页、哪一种元素
return {
"page": hit.metadata.get("page"),
"element_type": hit.metadata.get("element_type"),
"content": hit.text,
}
cards = [evidence_card(hit) for hit in retrieved_hits]
table_cards = [card for card in cards if card["element_type"] == "Table"]
if not table_cards:
# 没有表格证据时不要假装已经回答了精确数值
raise LookupError("没有召回表格元素,需要调整摄取或检索策略")
如果查询本身带图片,NVIDIA 的多模态查询路径还要求明确选择 collection,并且图像查询有单页检索等限制。落地时应记录“文本命中、表格命中、图片命中”的数量,抽样检查页码和元素类型,再观察答案是否引用了真正的表格证据。这样排查的是数据链路,而不只是盯着最终回答像不像。
常见误区与落地清单
- 只调大 chunk:大块正文仍然不会凭空恢复表格结构;先确认元素是否被识别。
- 只保存表格纯文本:列名和单位容易与数值脱节,至少保存结构化版本和页码。
- 全量开启视觉处理:先用少量复杂 PDF 评估准确率、显存和延迟,再扩大范围。
- 没有回溯字段:没有 page、element_type 或原文片段时,召回错误很难定位。
判断是否修好,可以用三类问题做小样本回归:正文事实、表格精确值、图片/图表含义。每类都检查召回证据是否来自正确页码和元素类型。只要表格问题仍然返回正文,优先回到摄取和表示层排查,而不是继续堆生成提示词。
相关问题
表格一定要转成图片才能进入多模态 RAG 吗?
不一定。结构化文本更适合列名、单位和数值匹配;复杂版式或图片化表格再补充视觉表示,按查询和文档特点组合即可。
PDF 能复制文字,为什么还要做布局识别?
可复制只说明有字符层,不代表表格行列、页面区域和图片语义被保留。需要回答表格问题时,布局和元素边界同样重要。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习