首页 >  科技周边 >  人工智能

RAG 文档切片如何保留表格行列关系

来源:17golang原创

时间:2026-09-12 09:16:50 311浏览 收藏

RAG 问答里,表格最容易出现一种“检索到了,但回答不对”的问题:向量库命中了一行数据,却没有表头、表名和原文位置。模型只看到“华东、2025、18.4”,很难判断 18.4 到底是销量、金额还是增长率。

处理表格不要直接套固定字符数切片。更稳妥的做法是先识别表格边界,再把表格标题、列名和一行数据合成可独立理解的知识块,同时把 table_id、页码、行号等来源信息写入 metadata。
要点速览
  • 表头是行数据的语义上下文,不能只保存一次。
  • 每个行级 chunk 都应带表格身份、行号和来源定位。
  • 事实型问题优先召回行块,跨行比较再补充同表相关行。

为什么固定长度切片会拆散表格关系

普通段落可以按句子或字符窗口切分,表格却有二维结构。固定窗口可能把表头留在前一个 chunk,把数据行切到后一个 chunk;也可能把一行从“地区、月份、收入、增幅”中间截断。即便 Markdown 表格没有被截断,单独嵌入一行时也会丢掉列名。

所以问题不只是 chunk 太大或太小,而是切片单位错了。表格的最小可检索单位通常应该是“表格身份 + 列名 + 一行值”,而不是一段任意长度的字符串。Azure 的 RAG 文档也把按结构和语义切分、为表格建立专门 chunk 作为可调整的策略;Markdown 的标题层级还可以作为额外上下文。

为每一行补齐表头和表格身份

先把表格规范化成行记录。假设原表名为“区域销售月报”,列名为“地区、月份、销售额、同比”,一行不要只写成“华东|2025-08|128000|12%”,而应写成:

表格:区域销售月报
地区=华东;月份=2025-08;销售额=128000;同比=12%

这样做会增加一些重复文本,却换来了稳定的字段语义。表格较大时,可以将长表拆成多个行块;表格标题和列名重复写入每个块,而不是依赖相邻 chunk 恰好被一起召回。

RAG 表格切片中原始文档、表格标题、列名、行记录和行级知识块的关系
图1:表格行级知识块同时携带表格标题、列名、行内容和来源 metadata,避免单独检索一行时失去字段语义。

如果表格的单元格本身很长,不要强行把一整行塞进一个超大 chunk。可以先保留完整的字段名,再对长文本字段做二次切分,并在子块 metadata 中保留同一个 row_id。

把来源定位写进 metadata,而不是塞进正文

正文负责让嵌入模型理解内容,metadata 负责过滤、排序和回溯。建议至少保留以下字段:

字段用途示例
table_id区分同一文档中的多张表sales_2025_08
row_id稳定定位某一行sales_2025_08_r17
page回到 PDF 或原文页码12
headers支持字段过滤或重建表头地区、月份、销售额、同比

下面的示例只演示切片模型,不绑定某个向量数据库。关键点是每一行使用同一组 headers,并为每个 chunk 生成稳定 row_id:

def table_rows_to_chunks(table_title, headers, rows, source):
    chunks = []
    for index, row in enumerate(rows, start=1):
        # 将列名和值按位置配对,避免只保存没有语义的裸值
        pairs = [f"{name}={value}" for name, value in zip(headers, row)]
        text = f"表格:{table_title}\n" + ";".join(pairs)
        chunks.append({
            "text": text,
            "metadata": {
                "table_id": source["table_id"],
                "row_id": f"{source['table_id']}_r{index}",
                "page": source["page"],
                "headers": headers,
            },
        })
    return chunks

生产代码还要处理合并单元格、空值、跨页表头和列数不一致。若一行缺列,应记录解析异常并进入人工或规则复核,不能让 zip 静默丢掉尾部字段。

按问题类型选择检索组合

“某地区八月销售额是多少”适合直接召回行级 chunk;“哪些地区同比超过 10%”则需要召回同一张表的多行,再按同比字段做过滤或排序。不要为了覆盖第二类问题,把整张表无条件拼进一个超大向量。

一个实用的组合是:向量检索找到候选行,metadata 过滤 table_id 或字段条件,再根据 row_id 拉取同表相邻行,最后把命中的行和来源位置一起交给生成模型。回答模板里应明确表名、字段和值,必要时附上页码或文档标识。

RAG 表格问答中用户问题、行级知识块、表格 ID、页码定位和回答证据的关系
图2:回答表格问题时,行级命中不能替代表格 ID 和页码定位,三类信息共同组成可回溯证据。

上线前检查这份表格切片清单

  • 随机抽取一个 row_id,脱离相邻 chunk 后仍能说清每个值对应的列。
  • 同一张表跨页时,后续页是否重复保留列名或继承明确的表头版本。
  • 空值、合并单元格、单位和百分号是否在正文或 metadata 中保留。
  • 检索结果是否能回到 table_id、page 和 row_id,而不是只返回一段相似文本。
  • 对跨行比较问题,是否有过滤、排序或二次召回,而不是让模型凭印象计算。

相关问题

表格每行都重复表头,会不会浪费 token?

会有少量重复,但通常比丢失列语义更可控。可以只重复短表头,把长说明放进 metadata 或父级文档,再按实际 token 成本调整。

应该把整张表作为一个 chunk 吗?

小表且问题经常需要跨行比较时可以保留父级表块;大表更适合“父表 + 行级子块”的组合,不要二选一。

Markdown 表格能直接交给通用文本切分器吗?

可以作为输入格式,但不能假设通用切分器会自动理解行列关系。先确认解析器如何处理表格,再显式生成行级文本和 metadata。

如何判断切片真的改善了问答?

准备包含单字段查询、跨行比较和来源追溯的测试集,分别检查字段准确率、数值一致性和 page/table_id/row_id 的可回溯率。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>