做 RAG 的人都知道一个残酷的事实:检索效果的天花板,往往在文档切割那一步就已经定死了。Embedding 再强、Rerank 再准,如果切出来的块本身语义破碎、上下文缺失,后面全是白费功夫。
这篇文章把主流的六种文档切割(Chunking)方案捋一遍,从最简单的重叠切割,到 Anthropic 提出的 Contextual Retrieval,讲清楚每种方案的做法、优缺点和适用场景,最后给出选型建议。
一、为什么切割这么重要
RAG 的链路是:文档 → 切块 → 向量化 → 检索 → 喂给 LLM。
切割决定了两件事:
- 检索粒度:块太大,一个块里混了好几个话题,检索时噪声大;块太小,语义不完整,检索到了也没用。
- 上下文完整性:如果把一句话、一个表格、一段逻辑从中间劈开,模型拿到的就是残缺信息。
所以切割的核心矛盾就一句话:块要小到足够精准,又要大到保留完整语义。下面六种方案,本质都是在这个矛盾里找不同的平衡点。
二、六种主流切割方案
方案一:重叠切割(Overlap)
最基础的做法:按固定长度切,但让相邻块之间共享一段内容。
参数:overlap 一般设为 chunk_size 的 10%-20%,比如 500 字的块,重叠 50-100 字。
优点:成本几乎为零,改个参数就行;能防止关键信息刚好卡在切点上被切断。
缺点:只能救单句级别的切断,救不了跨段落的语义断裂。
适用:作为所有切割方案的基础配置,几乎都会叠加使用。
方案二:语义边界切割
不按字数硬切,而是找语义的自然断点。有两种做法:
规则版:按 Markdown 标题、段落、句号等分隔符切。工程上最常用,LangChain 的 RecursiveCharacterTextSplitter 就是按优先级依次尝试分隔符。
模型版:计算相邻句子的 embedding 相似度,相似度骤降的地方说明话题变了,在那里切。
优点:切点符合人类阅读逻辑,不会把完整意思劈开。
缺点:模型版需要额外的 embedding 计算,慢且贵;块大小不可控。
方案二补充:结构感知切割(表格与代码块)
生产环境里最常见的翻车点不是正文,而是表格和代码块被从中间劈开:表格按字数切成两半后,两半都失去了表头和列对应关系,检索到了也没法用;代码块被截断后,语法和逻辑都不完整。
处理原则就三条:
- 表格整体保留:一个表格无论多大都不要从中间切;超大表格可以按行分组切块,但每块都要重复带上表头。
- 代码围栏不切:以 ``` 围栏为硬边界,一个代码块至少作为一个整体;超长代码按函数/类边界二次切分。
- 图片与题注绑定:图片描述文字和图片引用放在同一个块里,避免「图在这儿、解释在上一块」。
这套原则本质上是语义边界切割的加强版:先识别结构元素(表格/代码/图片),把它们当作不可分割的原子,再对剩余正文走常规切分流程。
零成本增强:chunk 元数据(标题路径)
组合拳里提到的「标题路径前缀」值得单独强调,因为它是投入产出比最高的一步:不改变切割逻辑,只给每个 chunk 拼一段元数据前缀再做 embedding。
元数据前缀 = 文档名 > 章节路径 > 小节标题 [+ 页码/来源 URL] 示例: 《RedTao 使用指南》> 第二章 查询语法 > 2.3 图遍历 第三步是调用 executeGremlin 方法……作用有两层:
一是消歧——「配置方法」这种小节标题出现在十篇文档里,拼上文档名后向量立刻可区分;
二是让短 chunk 带上全局语境,效果接近轻量版的 Contextual Retrieval,但完全不需要调 LLM。很多团队只加了这一步,检索质量就有明显提升。
元数据建议至少包含:文档名、完整章节路径、小节标题;有条件再加上页码、来源 URL、更新时间。
方案三:句子窗口检索(Sentence Window)
核心思想是:检索粒度要小,返回粒度要大。
用单句做向量匹配,精准度高;但返回给模型时带上周围几句,保证上下文不丢。
优点:命中率高,上下文完整。
缺点:向量库条目数量暴增,存储成本高。
方案四:父子切割(Parent-Child)
句子窗口的进化版,分成固定的两层结构。
和句子窗口的关键区别:父块的边界是固定的(按章节、段落划分),不是动态取前后 N 句,逻辑更完整。
优点:性价比最高,是工程上最推荐的方案。
方案五:命题化切割(Proposition)
用 LLM 把文档拆成一个个独立完备的原子事实。
每条陈述都还原了指代词,可以脱离原文独立理解。
优点:检索极准,几乎没有歧义。
缺点:贵(每篇文档都要过一遍 LLM);丢失叙述连贯性;可能丢失细节。
方案六:Contextual Retrieval(Anthropic 方案)
保留原始块,但给每个块加一段 LLM 生成的上下文说明。
做法:把整篇文档 + 当前 chunk 一起喂给 LLM,让它生成 50-100 字的上下文描述,拼在 chunk 前面再做 embedding。
效果:Anthropic 实测配合 BM25 混合检索,检索失败率降低49%。
成本:靠 Prompt Caching 把成本压到百万 token 约 1 美元。
代价:索引阶段慢,每个 chunk 都要调一次 LLM。
三、选型建议
| 方案 | 成本 | 语义完整性 | 推荐度 |
|---|---|---|---|
| 重叠切割 | 极低 | ⭐ | 基础配置 |
| 语义边界 | 低-中 | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 句子窗口 | 中 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 父子切割 | 低 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 命题化 | 高 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| Contextual Retrieval | 中-高 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
实战中最有效的其实是组合拳:先按结构切(Markdown 标题)→ 大块内部递归切小块 → 每块加标题路径前缀 → 用父子块策略检索。
最后提醒一句:切割效果不要凭感觉,一定要用 Recall@K 和 MRR 实测。同一批 query,换不同切割策略跑一遍,数据会告诉你答案。
感兴趣的宝子可以关注一波,后续会更新更多有用的知识!!!