RAG 为什么经常答错表格问题?
RAG 开发者可能都遇到过这样的场景:用户上传了一份文档,提问一个表格里的数据,系统给出了一个像模像样的回答——有引用标注、有数值、格式工整。但用户核对原文后告诉你,答错了。
这类错误往往被归因于检索没召回正确的 chunk,或者模型生成了幻觉。顺着这个思路,接下来的动作通常是调 embedding、改 chunk 策略、优化 prompt。这些优化当然有价值,但它们可能掩盖了一个更上游的问题。
来看一个真实的例子。
用户上传了一份财务季报 PDF,提问:“本期收入 Q2 是多少?”系统返回了一个数字,还附上了引用来源。但用户核对后发现,系统引用的是成本 Q2,不是收入 Q2。两个数值都在原文里,OCR 没认错字,但答案的对应关系错了。
回溯问题链条:PDF 解析 → 文本切片 → 向量检索 → LLM 生成。在哪个环节出的错?答案往往被归咎于检索策略或模型幻觉。但实际上,在 PDF 解析这一步,表格的结构关系已经断了。原始表格中,“收入”和“成本”是两个父表头,各自横跨 Q1、Q2 两列。解析器输出时,如果两组 Q2 被拍平,它们就变成了四个孤立的数值,不再分别隶属于“收入”和“成本”。从这一刻起,无论后续检索多么精准、生成多么流畅,RAG 系统已经不可能正确回答“收入 Q2 是多少”了。它能检索到 Q2,但不知道是哪一个 Q2。
RAG 的答案质量上限,不是在生成阶段决定的,而是在入库的表格解析阶段就被限定了。本文将拆解表格解析质量如何系统性地影响 RAG 问答。

OCR识别结果

文档解析输出结果
表格解析对 RAG 的四个破坏路径
要理解表格识别出差错的原因,可以先做一个区分:字符级归属 vs 字段级归属。OCR 解决的是前者——这个字符在图像的哪个位置。表格解析要解决的还有后者——这个数值属于哪个字段。RAG 系统对字段级归属的依赖,远高于字符级归属。一个字识别错了,模型有时还能靠上下文纠正;但一个数值挂错了字段,模型只会自信地给出错误答案。
以下四个破坏路径,根因都在于:字段级归属在解析阶段断裂,导致 RAG 检索和生成出现系统性偏差。
破坏路径一:表格被拍平成文本,模型失去层级导航
解析系统把表格输出为连续文本或扁平 Markdown 时,表头、数据行、注释全部混在一起。进入向量检索后,模型拿到的是一段“去结构化”的文本块,看不到表头到数据的层级关系,也看不到正文与注释的边界。
如上图中 OCR 识别结果所示,对于这样的输入文本,模型无法区分“这是表头定义”“这是数据值”“这是脚注说明”。
当用户问“表格中有哪些科目”,模型把科目行下面的注释说明也一并列了进去。因为在拍平后的文本中,这条脚注紧挨着科目名称,模型无法识别它们之间的层级差异。
破坏路径二:表头继承丢失,数字含义被张冠李戴
多层表头场景中,同一个列名( Q2)在不同父表头下含义不同。因为被解析系统拍平,两个 Q2 在文本中完全无法区分。进入向量检索后,与“Q2”相关的两个数值被同等对待——系统不知道它们一个属于收入,一个属于成本。
这就是开头那个错误答案的根本原因。用户问“收入 Q2”,模型引用了成本 Q2 的数值。从 RAG 系统的视角看,它的行为完全自洽:检索到了包含 Q2 的文本块,忠实地从中提取了数字。问题出在更上游,当检索器看到两个 Q2 时,它已经没有能力区分应该召回哪一个。
破坏路径三:单位、币种等元数据脱钩
很多业务表格的关键信息不在表格内部,而在表格上方或下方。比如表头上方写着“单位:百万元”。解析系统如果只输出表格主体,这行单位说明会被当作独立段落,切片到另一个 chunk 里,甚至在文档处理中被丢弃。
RAG 检索到表格数据所在的 chunk,但这个 chunk 里不包含单位信息,就会出现这样的情况:LLM 读到了数字 1350,但不知道它是“1350 百万元”还是“1350 元”。
用户问“收入是多少”,模型回答 1350,而实际是 1350 百万元——13.5 亿,答案差了三个数量级。从评价指标上看,这个回答的忠实度可能不低,因为它确实引用了原文中的某个数字。但对用户来说,它完全不可用。
破坏路径四:表格切片上下文断裂,跨页长表尤甚
RAG 的 chunk 切分策略通常基于段落边界或固定 token 数,不会识别表格的连续性。一张跨页长表可能被切成多个 chunk:表头在 chunk1,前半段数据在 chunk2,后半段数据在 chunk3。当检索器召回 chunk3 时,模型看到的是一堆没有表头的数据行。
面对用户提问,模型检索到了对应的数据行,但无法判断每个数值属于哪一列,只能猜测或拒答。

为什么当前 RAG 管道普遍忽略表格结构
这个问题之所以普遍存在,不是某一个工具的缺陷,而是技术栈、评测体系和认知三个层面的系统性盲区。
技术栈断层。 LangChain、LlamaIndex 等 RAG 框架的文档加载器,底层通常调用的是基础 PDF 解析能力,表格结构信息在加载环节就丢失了——框架不知道这是一张表,更不知道它有几层表头、有没有合并单元格。后续的 splitter 和 retriever 在一个“无结构文本”的世界里工作,根本感知不到表格的存在。
评测盲区。 RAG 的常用评测指标(忠实度、相关性、上下文召回率等)对表格结构错误不敏感。一个数字被挂错表头,在评测中不会触发“忠实度”扣分,因为模型确实引用了原文中的某个数字。这套评测体系天然偏向“是否引用了原文内容”,而非“引用的是否是正确的那一条”。
认知错位。 部分 RAG 开发者认为表格解析是 OCR 的问题:OCR 准确率够高,表格就能用。但 OCR 解决的是字符级归属,表格解析要解决的是字段级归属。一个字都没识别错,表格依然可能完全不可用。这两件事分属不同层级,不能互相替代。
入库前做好表格解析,RAG 能改变什么
如果能前置解决,局面会截然不同。四个问题,解法也对应四个方向。
解法一:输出保留完整表格结构
解析结果应该保留表头层级、数据行归属、合并单元格关系。这样 RAG 的 splitter 可以基于表格结构做智能切分,而非暴力断句。模型在回答时能区分“表头”和“数据”,不再把脚注和科目名称混淆。
解法二:表头信息随数据行一起存储
每个数据值在入库时,应该携带其完整表头路径。比如不是孤立地存储数字 1350,而是存储“收入 > Q2 > 1350”。这样即使检索到单个数值,模型也能看到它的完整上下文,引用 Q2 时能明确区分是“收入 Q2”还是“成本 Q2”。
解法三:元数据与表格主体保持关联
单位、币种等元数据不应被切片策略从表格主体上剥离,RAG 检索到表格数据时,单位说明随同返回。模型回答时能带上单位,输出“1350 百万元”而非“1350”,不再出现数量级错误。
解法四:跨页表格按文档级对象处理
跨页长表在解析阶段就应该完成拼接,作为一张完整表格输出。RAG 的 splitter 不需要在一张表中间下刀,长表后半段的数据行不再丢失表头,让模型能正确理解每一列的字段含义。

用你的表格,来 Playground 看看不同解析方案的差距
RAG 的表格问答质量,入库前就决定了上限。本文中讨论的 RAG 系统常见问题指向同一个结论:复杂表格解析不是 RAG 的可选优化,而是必需的前置步骤。
RAG 出错,根因往往不在模型,在入库前的表格解析。选对解析方案,比调检索策略和 prompt 更直接。
xParse Playground 可以帮你直观验证:你的表格适合哪种解析方案。


点击 👉xParse Playground,上传一张你手头的复杂表格 PDF 或图片,同时看到不同解析方案的结构化输出。你可以直接对比:哪个方案保留了表头层级?哪个方案丢了单位元数据?哪个方案把跨页表接上了?这些输出上的差异,就是 RAG 答案质量的差异。
带上你最棘手的那张表格,来亲眼看看不同解析方案输出的差距。