跳到主要内容

分块策略是 RAG 流水线中隐藏的核心决策

· 阅读需 13 分钟
Tian Pan
Software Engineer

大多数关于 RAG 质量的讨论都聚焦在错误的地方。团队在争论嵌入模型的选择、微调检索的 top-K、以及尝试各种提示词模板——然而在数据摄取阶段做出的一个架构决策,却悄然决定了系统能力的上限。这个决策就是分块策略(chunking strategy):即在索引之前,你如何将文档切分成片段。

一项 2025 年的基准研究发现,分块配置对检索质量的影响,甚至比嵌入模型的选择还要大。然而,团队通常会选择默认配置——通常是 512 个 token 的 RecursiveCharacterTextSplitter——然后花上几个月的时间去思考,为什么他们的检索精度总是差强人意。问题在索引时就已经埋下了。更换模型无法解决这个问题。

为什么分块是一个不可逆的架构决策

当你对语料库进行索引时,你就对检索系统做出了一个承诺:这是它将要处理的最小意义单位。这个承诺是起支撑作用的。每一个嵌入向量、每一次近似最近邻查找、LLM 在下游看到的每一段上下文——所有这一切都源自这些初始分块。

这会产生一种不对称风险。糟糕的提示词可以在几秒钟内改进。而糟糕的分块策略则需要重新摄取整个语料库。在大规模生产部署中,这可能意味着数小时的计算时间、流水线中断以及协同的重新索引操作。团队往往会低估这种成本,直到他们亲自付出代价。

这种失败还有一个典型特征:它是无声的。当分块错误时,检索返回的结果看起来似乎很合理。嵌入相似度分数没问题。关键词信号也存在。LLM 生成了自信的回答。只有当有人将生成的答案与标准答案(ground truth)进行对比时,或者当合规审计发现引用的程序有误时,错误才会浮出水面。而此时,系统可能已经在生产环境中运行了数月。

朴素固定大小分片的实际代价

大多数教程中的默认行为是根据字符或 token 数量,通过一定的重叠将文本切分为固定大小的窗口。这对于运行 Demo 来说已经足够了。但在生产规模下,它会以特定的、可重现的方式失败。

语义边界的破坏。固定大小窗口在字符计数边界处切分,完全感知不到句子结构、段落换行或文档章节。结果就是分块可能从句子中间开始,在思路中途结束。这种分块的嵌入向量会捕获到噪声:它部分代表了两个想法,而不是完整地代表一个想法。由于被稀释的嵌入向量与查询的匹配精确度较低,检索质量会受到损害。

跨边界上下文丢失。关键信息往往会跨越分块边界。例如,适用于某个操作规程的警告标签被与规程本身切分开了;一个结论需要前一段落的背景设定;或者表格列标题与行数据分离。这些切分不会产生明显的错误,而是会产生微妙的错误答案,而这种错误的调试难度要大得多。

对非均匀内容的统一处理。一个混合了专利申请、聊天记录和技术文档的语料库,无法通过单一的分块大小来很好地处理。专利包含完整的、自引用的权利要求,需要 1,000–1,500 个 token 才能解释。聊天记录包含对话轮次,200 个 token 都嫌多。对所有内容统一应用 512 个 token 的固定分块,会导致两者的检索效果都平平。

分块策略图谱

了解实际的可选方案有助于评估权衡。

递归字符分片(Recursive character splitting) 有充分的理由成为当前的生产默认选择。它应用了一套层次化的分隔符——首先是段落换行,然后是行换行,接着是空格——仅在必要时才回退到字符分片。这在通常情况下保留了语义边界。Chroma 2024 年针对六个文档领域和五个嵌入模型的基准测试发现,在 400–512 token 范围内采用 10–20% 重叠的递归分片,在不同文档类型中实现了 85–90% 的 Recall@5,且方差最低。它并非对每个语料库都最优,但在不适用时它能优雅地降级。

语义分块(Semantic chunking) 使用嵌入相似度来检测自然的话题转变并在此处进行切分。在孤立的基准测试中,它实现了 91–92% 的召回率。但在实践中,它的端到端准确率会下降到约 54%——比递归分片落后约 15 个百分点。罪魁祸首是片段大小:语义切分的平均长度为 43 个 token,这通常太短,导致 LLM 无法从中构建有意义的答案。语义分块提高了检索精度,但需要设置一个最小分块底线才能在端到端流程中发挥作用。

父子分块(Parent-child chunking) 直接解决了精度与上下文之间的权衡问题。较小的“子”分块(100–500 token)被索引并用于检索以保证嵌入精度。当一个子分块被检索到时,较大的“父”分块(500–2,000 token)会被返回给 LLM,提供周围的上下文。对于那些答案需要上下文、而上下文又不方便在每个小分块中重复出现的领域,这种架构值得为此增加复杂性。

延迟分块(Late chunking) 是 2024 年推出的,它反转了标准顺序:首先使用全上下文 Transformer 对整个文档进行嵌入,然后将生成的 token 嵌入切分为分块并进行均值池化(mean-pooled)表示。每个分块嵌入都继承了整个文档的长程上下文。缺点是必须先处理整个文档才能对任何分块进行索引,这增加了数据摄取的延迟和成本。对于意义高度依赖远程上下文的语料库——如叙述性文档、复杂的技术手册——这种质量提升足以证明其开销是合理的。

文档结构感知分块(Document-structure-aware chunking) 利用源材料中的显式结构:Markdown 中的章节标题、PDF 中的视觉布局、技术文档中的操作步骤。在 NVIDIA 2024 年的研究中,页面级分块实现了最高的综合准确率,但这仅在文档页面对应于有意义的语义单元时才成立,这是在采用之前值得验证的前提。

如何进行受控的分块实验

这种优化分块(chunking)的方法论描述起来很简单,但很少有人能严格执行。

首先要隔离变量。构建两到四个 RAG 流水线,除了分块策略外,在其他方面完全相同——相同的嵌入模型(embedding model)、相同的向量数据库(vector database)、相同的检索参数、相同的 LLM。你观察到的任何质量差异都归功于分块。跳过这一隔离步骤,你将无法判断改进是源于分块,还是源于并行进行的其它优化。

在开始之前,先建立一个具有代表性的评估集。你需要涵盖真实用户提出的各种问题的查询——既包括事实性查询(“最大剂量是多少?”),也包括分析性查询(“方法 A 与方法 B 相比如何?”)。这些查询类型对不同的分块大小非常敏感:事实性查询在 256–512 个 token 时表现最好,因为精确度(precision)高;分析性查询通常需要 1,024 个或更多 token,以提供足够的上下文进行比较。

关键指标包括上下文召回率(Contextual Recall,检索到的上下文是否包含答案?)、上下文精确度(Contextual Precision,检索到的内容中有多少是真正相关的?)以及 Recall@K(正确的分块是否出现在前 K 个结果中?)。请分别按文档类型和查询类型跟踪这些指标。聚合分数可能会掩盖特定文档类别中的灾难性失败。

系统地改变分块大小和重叠(overlap)比例。对于递归拆分(recursive splitting),合理的扫描范围可能涵盖 256、512 和 1,024 个 token,以及 5%、15% 和 25% 的重叠率。2024 FinanceBench 的评估发现,对于金融文档,1,024 token 的分块配合 15% 的重叠效果最佳。NVIDIA 的研究发现,对于事实性查询的技术文档,512 token 是最优的。不要假设这些数字可以直接套用到你的领域——请根据你的语料库和查询分布进行验证。

导致精确度隐形崩溃的反模式

在生产环境 RAG 失败的复盘中,有几种模式反复出现。

超过 20% 的重叠极少有帮助,而且往往有害。 直觉上,更多的重叠意味着更少的间隙,这在理论上是正确的。但在实践中,当重叠超过 20% 时,精确度会急剧下降,而召回率并没有显著提升。索引大小会膨胀 2–3 倍,检索延迟增加,冗余分块会挤掉相关结果。行业标准的黄金分割点是 10–20% 的重叠。

对异构语料库采用单一策略。 如果你的语料库包含专利、支持工单、API 文档和会议纪要,没有哪种单一的分块大小能适合所有内容。分析你的文档分布。如果有两种或三种以上的文档类型占比较大,请实现按类型分块的逻辑。这在构建时会增加工程时间,但在运行时带来的回报是持续的检索质量提升。

将语义分块(semantic chunking)视为可以直接替换的升级。 语义分块的基准测试结果看起来很棒,直到你观察端到端的准确率。团队从递归分块切换到语义分块,在独立测试中观察到检索分数的提高,然后发布——结果却发现 LLM 的回答质量下降了。原因是 43 个 token 的碎片不足以让 LLM 发挥作用。如果你使用语义分块,请强制设定至少 200 个 token 的最小分块限制。

不验证分块边界。 从新索引的语料库中随机抽取 50 个分块并阅读它们。如果它们在句中开始或结束,或者将表格与其标题分开,或者代码块被截断——这些问题都会蔓延到针对该语料库回答的每一个查询中。这种手动抽查只需 20 分钟,却能发现自动化指标可能会遗漏的配置错误。

在 CI/CD 中对分块进行回归测试

分块回归(regression)尤其具有隐蔽性,因为它们往往是间接引入的。工程师更改了语料库预处理、更新了文档解析器、调整了流水线配置或添加了新的文档类型——这些看起来都不像对分块的修改——但检索质量却在无形中退化了。

解决方法是将检索质量视为 CI 流程中的一等公民准入门槛,通过一组带有标签的预留查询集和预期上下文分块来进行衡量。

至少在每次构建时跟踪 Recall@5 和 Contextual Precision。根据你的领域设置合适的阈值——医疗应用可能要求 Recall@5 ≥ 0.90,而内部知识库可能接受 0.80。当指标降至阈值以下时,判定构建失败。这能在合并时而非生产环境中暴露出分块回归问题。

此外,还要监控聚合指标可能遗漏的两种特定失败模式。第一种是查询类型退化:新的分块配置可能会提高分析型查询的性能,同时摧毁事实型查询的召回率。请分别跟踪这些。第二种是文档类型退化:如果采用统一策略,向语料库添加新的文档类别可能会改变现有语料库的最优分块大小。按文档类别跟踪检索质量。

DeepEval、Braintrust 和 Evidently AI 等工具为此提供了框架。基础设施投资并不大。相比之下,在没有建立基准的情况下调试生产环境的质量退化,成本要昂贵得多。

从何处开始

如果你正在构建一个新的 RAG 系统,一个安全的初始配置是:采用 512 个 token 的递归字符切分(recursive character splitting),并设置 15% 的重叠(overlap)。在发布任何内容之前,请针对一个包含至少 50 个查询的标记留存集(labeled holdout set)进行评估。这一基准方案既合理又经过了充分的基准测试,且在失效时表现平稳。

如果你现有的系统收到了质量投诉,诊断流程如下:

  1. 随机抽取 50 个分块(chunks)并阅读,检查它们的语义连贯性。
  2. 针对标记留存集运行 Recall@5 和上下文精度(Contextual Precision)评估。
  3. 按文档类型和查询类型对结果进行分类。
  4. 确定问题是出在分块过小(低上下文召回率 / Contextual Recall)还是分块噪声过多(低上下文精度 / Contextual Precision),然后朝相应的方向进行微调。

分块是一项并不起眼的基础设施工作。它既不会出现在演示脚本中,也不会出现在功能发布公告里。但那些成功构建了生产级 RAG 的团队一致反馈,系统性的分块微调——只要配合适当的评估进行一次——所带来的质量提升,是长达数月的模型和提示词实验所无法企及的。上限在摄入阶段(ingestion time)就已经设定好了。其他所有的工作都只是在这一上限之下运行。

References:Let's stay in touch and Follow me for more thoughts and updates