超长文档怎么进 RAG:分块之外还要做什么

2026-07-28

数据截至 2026-07,各项目能力以官方文档当前版本为准。

超长文档进 RAG,真正的难点不是”怎么切”,而是”切完之后每一块还剩下多少上下文”。一份三百页的设备手册切成两千个块之后,每个块都变成了一段没有出处、不知道属于哪一章、也不知道前后在讲什么的孤立文字。分块策略只解决了刀怎么下,剩下的活——补回位置、补回结构、补回引用关系——得靠另外几件事。

一个很常见的误解是:块切得够聪明,长文档的问题就解决了。语义分块、递归分块、按标题切,这些方法确实比按固定字数切强,相关做法可以看分块策略那篇。但它们本质上都只是在决定”这一刀落在哪”。对一份短文档来说,切好就基本够用了;对一份三百页的文档来说,切好只是第一步,因为长文档的信息很大一部分不在文字里,而在结构里——第 7 章第 3 节这个位置本身就是信息,“本条所称上述情形”指向的是上一条,附录 B 的表格要配着第 4 章的说明才看得懂。这些东西一切块就全丢了。

一、超长文档特有的四类失效

先把症状对上号,再决定修哪里。长文档在 RAG 里的翻车方式,跟短文档不太一样,比较集中的是这几类:

块的”身份”丢了。 检索回来一段”该参数默认值为 30 秒,超时后自动重连”,读起来完全通顺,但你不知道它说的是哪个模块的哪个参数。同一份手册里可能有七八处都在讲超时重连,模型拿到其中一段就开始答,答得很自信,也很可能张冠李戴。

指代断链。 法律文书、标准规范、企业制度里全是”前款""上述情形""本章第二节所述方法”。这类指代跨块之后就成了悬空的,模型只能靠猜。

答案本身就跨块。 一个完整的操作流程有十二步,跨了三页;一张表格连表头带数据占两页半。无论你怎么切,答案都不可能落在单个块里。这时候提高召回数量有一点用,但很容易把不相关的块也一起捞进来。

同一个词在不同章节含义不同。 大型文档里”节点""通道""等级”这类词往往在不同章节指代不同的东西。纯向量检索按语义相似度捞,很容易跨章节混着捞回来。

这四类问题的共同点是:它们都不是嵌入模型能修的。换一个更强的嵌入模型,只会让”捞得更准的错块”这件事发生得更快一点。

二、给每个块补上”它在哪”

最省力、见效也最直接的一步,是在入库时给每个块挂上它的位置信息,作为元数据存进去。具体存什么,按你的文档类型定,常见的有这几项:

  • 层级路径第4章 网络配置 > 4.3 心跳与重连 > 4.3.2 超时参数。这一串直接拼在块内容前面参与嵌入,同时也单独存一份做过滤字段。
  • 文档标识与版本:哪一份文件、哪个版本号、生效日期。多版本共存的合同和制度类语料,这一项几乎是必需的。
  • 块序号与前后块 ID:为后面的窗口扩展做准备。
  • 内容类型:正文、表格、代码、公式、附录。后面会讲为什么要分开。

把层级路径拼进嵌入文本这个动作,成本极低,但对前面说的”身份丢了”和”跨章节同名词”两类问题效果很明显——因为路径本身就带着领域词,能把向量往正确的章节方向拉。

存了元数据之后,检索侧要跟上,否则等于白存。向量库要能按 payload 做过滤,才能实现”只在第 4 章里找""只查 2026 版”这类限定。常配的向量库里 Qdrant 就支持过滤、payload 索引与量化,第三方评测称其在 100 万以上向量规模下可以做到 50ms 以内的检索,这个数字是第三方基准口径,不是官方指标,实际表现跟你的硬件、维度、量化配置都有关系,只能当量级参考。

三、检索的单位和喂给模型的单位,可以不一样

这是长文档 RAG 里性价比最高的一个技巧,值得单独说。

块切小,检索精度高——因为小块语义集中,向量不被稀释;块切大,生成质量高——因为模型能看到完整上下文。这两个诉求天生打架,很多团队就在”512 还是 1024”之间反复调,其实是把问题设错了:检索用的块和送进模型的块,本来就不必是同一个东西。

具体做法有两种,都不难实现:

父子块。 入库时同一段内容存两个粒度:子块小(比如两三句话),用来建向量索引;父块大(比如整个小节),用来实际返回。检索命中子块,返回它对应的父块。这样召回的判断依据是精准的小片段,喂给模型的却是完整小节。

窗口扩展。 只存一套小块,但每块记住自己的前后块 ID。检索命中之后,按需把前 N 块和后 N 块一起取出来拼接。这个做法对”答案跨块”和”指代断链”两类失效特别对症——“前款”指的内容,大概率就在前一块里。

两种做法可以混用:正文用窗口扩展,条款类文档用父子块(父块的边界就是”条”)。在实现层面,LlamaIndex 这类以数据为中心的框架把索引与查询这一层的原语做得比较贴身,做多粒度索引时改动量小一些;如果你已经在用 LangChain 做整体编排,也完全可以只把 ingestion 与索引这一段交给 LlamaIndex,编排仍留在原处——这种组合在生产里挺常见,不必二选一。入库流程的细节可以单开一篇看。

四、给长文档建一层”目录索引”

当单份文档达到几百页、或者知识库里有几十份这样的长文档时,直接在几万个块里做一次向量检索,噪声会很大。更稳的做法是加一层路由,先定位到文档或章节,再在范围内检索。

实现上通常是这样:入库时给每份文档、每个章节各生成一段摘要,单独建一个”摘要索引”。查询进来先在摘要索引里检索,确定候选文档或候选章节,再带着这个范围条件去正文索引里做二次检索(这时候第二节存的层级路径元数据就派上用场了,直接当过滤条件)。

这个做法的代价是多了一跳,延迟会增加。有第三方评测指出,用 LangChain 的 LCEL 做复杂查询重写这类多跳编排,相比直接检索会多出约 15% 到 20% 的延迟开销——这是第三方基准口径,不同实现差异很大,但方向是对的:每加一层,就要付一次延迟。所以要不要上两段式检索,取决于你的语料规模和用户对响应速度的容忍度。语料只有几十份普通文档,直接一次检索就够了,没必要提前上复杂度。

五、表格、附录、图纸另开一条通道

长文档里最容易被整体流程”平均掉”的就是表格。一张跨页的参数表,按正文的切法处理,结果往往是表头和数据分家、合并单元格被拍平成一行乱码。

值得单独做的处理有几项:

  • 表格整块保留,不参与正文的切分。哪怕它比设定的块大小大得多。
  • 给每张表补一段自然语言描述(表名、字段含义、这张表回答什么问题),用这段描述去建向量索引,命中后返回原表。因为用户提问用的是自然语言,跟表格里的数字在向量空间里离得很远,直接拿表格原文做嵌入,召回率通常很难看。
  • 保留表格的原始结构,返回时以 Markdown 表格或结构化格式给模型,别给拍平的纯文本。

如果你的长文档本身就是扫描版 PDF、财报或者版式复杂的法律文书,那问题其实出在更前面——文档根本没被读明白。RAGFlow 这类开源 RAG 引擎的定位就是深度文档理解,分块会尊重文档结构,带版面感知解析,处理这类传统文本解析器搞不定的语料时更对口;它走 Docker 部署,镜像分 slim 和 full 两种,slim 约 2GB、full 约 9GB,区别在于是否内置嵌入模型,具体以项目官方文档当前版本为准。判断自己是不是卡在解析这一步,可以对照解析瓶颈排查那篇先做一遍确认,别在检索参数上白花时间。

六、跨章节引用:什么时候值得上图检索

前面说的窗口扩展能解决”前款”这种近距离指代,但解决不了远距离引用——“按第 12 章附录 C 的方法执行”,这两处可能隔着两百页。

处理这类关系,有两条路:

轻量的一条是在入库时做一次引用抽取,把”本文档内的交叉引用”识别出来存成块之间的关联字段,检索命中某块时顺带把它引用的目标块也取回来。这条路实现成本可控,对格式规整、引用写法统一的规范类文档效果不错。

重的一条是上图检索。当你的语料本身就是有大量链接关系的结构化内容——比如一整套相互引用的标准规范、一个企业的全部规章制度、一份带大量交叉引用的技术手册族——把实体和关系抽出来建图,检索时沿着关系走,比纯向量检索更能回答”这条规定跟哪些条款相关”这种问题。RAGFlow 内置了知识图谱构建能力,可以少搭一套。图检索的代价是构建成本和维护成本都明显更高,语料一变就要重新抽取,所以建议先确认纯向量加交叉引用字段确实不够用,再考虑往这个方向走。GraphRAG 的适用边界另有专篇。

七、长文档改一版,不该整库重灌

超长文档还有一个很实际的运维问题:手册出了 V3.2,改了三节,你不能每次都把整份三百页重新解析、重新嵌入一遍——既慢又费钱,还会让线上索引出现空窗。

可行的做法是给每个块算一个内容指纹(对块的规范化文本做哈希),入库时连指纹一起存。文档更新时重新解析并分块,逐块比对指纹:一样的跳过,新增的入库,消失的删除。这样一次更新真正需要重新嵌入的通常只有几十个块。

要注意两个坑。一是块边界会漂移:改了一句话可能导致后面所有块的切分位置全变,指纹全部对不上,退化成全量重灌。缓解办法是让分块尽量锚定在稳定的结构边界上(按标题、按条款切,而不是按字数),这样改动的影响就被限制在局部。二是版本共存:合同、制度类语料经常需要”按当时生效的版本”回答,这时候旧版本不能删,得靠第二节存的版本元数据在检索时做过滤。这块的完整做法见增量更新那篇

八、怎么确认这些动作真的有效

上面每一项都会增加系统复杂度,所以每上一项都该有对应的验证,否则很容易做了一堆工程却说不清好在哪。

先建一份小而真的评测集。 从你的长文档里挑三十到五十个真实问题,标注每个问题的答案应该出自哪一节。这份东西一天之内能做完,但它是后面所有判断的基准。

分开看检索和生成。 长文档场景下最该先盯的是召回:正确的那一节有没有进到候选里。如果没进,调生成侧的提示词毫无意义。RAGAS 这类评估工具可以挂在你已有的框架上跑,不用换框架,评估的具体指标可以另看。

一次只改一项。 先加层级元数据跑一轮,再上父子块跑一轮。同时改三处,指标动了你也不知道是谁的功劳。

别按名气选工具。 截至 2026 年 1 月的 GitHub star 数据里,LangChain 约 12.5 万、Dify 约 11.4 万、RAGFlow 约 7 万、LlamaIndex 约 4.65 万、Haystack 约 2.4 万——star 反映的是关注度,跟你这份三百页手册合不合适没有直接关系。按瓶颈选更靠谱:卡在解析就往深度文档理解方向找,卡在检索就选可调旋钮多的,卡在评估就加挂评估工具。选型的完整对照可以看框架选型那篇

诚实说一句局限:以上这些做法能把长文档 RAG 的下限抬起来,但它们改变不了一件事——如果原始文档本身写得就乱,章节层级混用、同一个概念前后叫法不一致、表格没有表头,那么任何工程手段都只是在整理一堆本来就整理不好的东西。遇到这种语料,投入一点人力做文档本身的规范化,回报往往比调三轮参数高。

小结

超长文档进 RAG,分块只是第一步,真正决定效果的是分块之后有没有把结构信息补回去。最先该做的是给每个块挂上层级路径、版本和序号这类元数据,成本最低、收益最直接。接着把”检索用的块”和”喂给模型的块”拆开,用父子块或窗口扩展解决答案跨块和指代断链。表格和扫描件要单独走一条通道,别混在正文流程里被平均掉;跨章节引用先试轻量的交叉引用字段,确认不够用再考虑图检索。最后,每加一项都拿一份小评测集验一次,一次只改一处,别让复杂度涨得比效果快。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。