实战 SOP
实战 SOP

RAG 分块策略 SOP:chunk 切多大、怎么切、怎么评

RAG 分块策略 SOP:固定/递归/语义/结构感知四种策略,chunk_size 与 overlap 调参经验,父子分块与 late chunking,召回评测迭代。附 LangChain 分块器代码示例。

发布于 2026年8月2日7 分钟阅读
<!-- rag-chunking-strategy-sop | sop | RAG 分块策略 SOP:chunk 切多大、怎么切、怎么评 -->

RAG 系统搭好上线,最让人头疼的不是"答不出来",而是"答得不准":明明知识库里有相关文档,检索就是召不回来,或者召回来的片段和问题八竿子打不着。团队第一反应往往是换 embedding 模型、加 rerank、调 top-k——这些都对,但很多人忽略了管道最上游的那个变量:分块(chunking)。文档怎么切,直接决定了 embedding 看到的是什么语义单元。chunk 太大,一个片段塞进多个主题,向量被稀释,相似度被拉低;chunk 太小,上下文断裂,回答东拼西凑。分块没调好,下游任何调优都是在漏水的管子上打补丁。

这篇 SOP 不讲概念,直接走一遍分块策略选型和调参的全流程:四种主流策略怎么选、chunk_size 和 overlap 怎么定、代码怎么写、怎么评测、怎么迭代。和本站《RAG 系统评估 SOP》不同,那篇讲怎么"评"整条 RAG 管道,这篇聚焦管道最上游的"切"——分块是检索质量的地基,切对了,后面的 embedding、rerank 才有发挥空间。


一、为什么分块是 RAG 检索质量的命门

RAG 的检索靠 embedding 相似度:把用户问题和文档片段都变成向量,算余弦相似度,取最相关的 top-k。这意味着 embedding 的输入不是整篇文档,而是切好的 chunk。chunk 是检索的最小单元,它的大小和边界直接决定了向量"看到"的语义范围。

两个极端都会出问题:

  • chunk 太大:一个 chunk 里混了多个主题(比如一份合同里的三条条款),embedding 把它们压缩成一个向量,语义被平均稀释。用户问"违约金怎么算",这个 chunk 和问题的相似度被其他无关条款拉低,排名靠后甚至召不回来。而且大 chunk 占 LLM 上下文窗口,top-k 能塞进的片段数变少,能提供的有效信息反而更少。
  • chunk 太小:一个 chunk 只有一句话甚至半句话,上下文断裂。用户问"年假怎么休",召回到一个只写了"工龄满 1 年 10 天"的片段,缺少"满 10 年 15 天"的上下文(被切到另一个 chunk),回答就不完整。

结论很硬:分块不是预处理环节的随手一刀,而是决定检索质量上限的关键决策。 切对了,embedding 才能把语义表达准;切错了,换再贵的模型也救不回来。


二、四种分块策略:原理与适用场景

主流分块策略有四种,各有适用场景,没有银弹。

策略原理优点缺点适用场景
固定长度按 token/字符数硬切实现最简单,速度最快可能切断句子和语义边界纯文本、格式均匀、快速验证
递归分块按层级分隔符优先切,长度兜底尽量保留段落/句子边界仍依赖分隔符,复杂结构可能失效通用文本、Markdown、混合内容
语义分块按相邻句子 embedding 相似度断句切分点贴合语义变化需调用 embedding,成本高长文档、主题跨度大
文档结构感知按标题/段落/列表等结构切保留文档层级和逻辑完整性依赖文档结构质量Markdown、HTML、技术文档

逐个展开。

1. 固定长度(Fixed-size)。 按 token 数或字符数硬切,比如每 500 token 一块。最简单直接,几乎所有框架都内置。但硬切的代价是:一个完整的句子或条款可能被从中间劈开,chunk 前半截和后半截各自语义不完整。适合格式均匀的纯文本快速验证,但生产环境几乎不该作为首选。

2. 递归分块(Recursive)。 按一组层级分隔符优先切:先试段落分隔符 \n\n,切完还超长就用换行 \n,再不行用句号 ,最后用空格、空字符串兜底。核心思路是"尽量在自然边界切,只在必要时硬切"。LangChain 的 RecursiveCharacterTextSplitter 就是这个策略的标配实现。它是通用文本和 Markdown 的稳妥默认选择——既保证 chunk 不超长,又尽量不在句子中间断开。

3. 语义分块(Semantic)。 不按固定长度切,而是把文档拆成句子,算相邻句子的 embedding 相似度,在相似度骤降的"断点"切分。原理是:语义连贯的句子聚成一块,语义跳变处就是分块边界。优势是切分点天然贴合内容主题变化,劣势是要对每篇文档跑一遍 embedding,成本和延迟都高。适合主题跨度大的长文档(比如一篇混合了产品介绍、定价、案例的技术白皮书)。

4. 文档结构感知(Structure-aware)。 不按长度切,按文档本身的层级结构切:Markdown 按标题(###)切,HTML 按 DOM 节点切,PDF 按段落和章节切。优势是每个 chunk 自带完整层级上下文("这个片段属于哪一节的哪个标题下"),检索时语义最完整。LlamaIndex 的 MarkdownNodeParser、Unstructured 的分区解析都属此类。适合结构化技术文档、产品手册、法规条文。

选型一句话:有结构优先用结构感知,没结构用递归分块兜底,长文档主题跨度大再考虑语义分块,固定长度只用于快速验证。


三、关键参数:chunk_size 与 overlap 怎么定

策略选完,两个参数决定最终效果。

chunk_size(分块长度)。 经验值范围 256-1024 token,没有万能值,按语料类型调:

  • FAQ、SOP 条目、短问答:300-500 token,因为每个条目本身就是自包含的语义单元。
  • 通用文档、产品说明、博客:500-800 token,兼顾语义完整和检索精度。
  • 合同条款、法规条文、长篇手册:800-1200 token,保证一个条款不被切断。

记住两个陷阱:chunk 不是越大越好(向量稀释),也不是越小越好(上下文断裂)。256-1024 是稳妥区间,但最终值必须拿你自己的语料和评测集来定,没有拍脑袋的银弹。

overlap(重叠长度)。 相邻 chunk 之间的重叠区域,作用是防止切分边界的内容丢失上下文。经验值是 chunk_size 的 10%-20%:

  • chunk_size 500 → overlap 50-100
  • chunk_size 1000 → overlap 100-200

overlap 为 0 是最常见的踩坑:一个句子被切成两半,前半截在 chunk A,后半截在 chunk B,检索到 A 时回答不完整。但 overlap 也不是越大越好——重叠太多会导致同一个内容在多个 chunk 重复出现,浪费存储、稀释检索精度,还可能让 top-k 召回重复内容。10%-20% 是平衡点。


四、代码示例:递归分块实操

以 LangChain 的 RecursiveCharacterTextSplitter 为例(API 以官方文档为准):

python
# pip install langchain-text-splitters
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 中文文档推荐把句末标点也放进分隔符层级
splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""],
    length_function=len,
)

chunks = splitter.split_text(document_text)

print(f"切出 {len(chunks)} 块")
for i, chunk in enumerate(chunks[:3]):
    print(f"--- chunk {i} ({len(chunk)} 字符) ---\n{chunk[:80]}...")

几个要点:

  • separators 是层级列表,splitter 从前往后试:先按 \n\n 切,某块还超 chunk_size 就退到 \n,再不行退到 ,依此类推。
  • 中文文档务必把中文句末标点(。!?;)放进分隔符,否则 splitter 只认英文标点,会在中文句子中间硬切。
  • length_function=len 按字符数计长度。如果想按 token 计,换成 length_function=tiktoken_len(需安装 tiktoken),这样 chunk_size 单位就是 token。
  • LlamaIndex 对应的是 SentenceSplitterfrom llama_index.core.node_parser import SentenceSplitter),参数名一样,方法为 get_nodes_from_documents(documents),API 以官方文档为准。

五、进阶:父子分块与 late chunking

基础策略解决"怎么切",进阶策略解决"检索精度和上下文完整不可兼得"的矛盾。

父子分块(Parent-Child Chunking)。 核心思路:把文档切成大块(父 chunk),再把每个父 chunk 切成小块(子 chunk)。检索时用子 chunk 的 embedding 精准命中,但把命中的子 chunk 对应的父 chunk 喂给 LLM。这样检索精度由小块保证(小块语义聚焦,向量不被稀释),回答上下文由大块保证(父 chunk 包含完整段落)。LangChain 的 ParentDocumentRetriever 就是这个模式的实现。适合长文档既要召回精准又要回答完整的场景。

Late Chunking。 传统分块是"先切再 embedding",late chunking 反过来:先把整篇文档过一遍 embedding 模型拿到 token 级表示,再按边界切分、把 token 向量聚合成 chunk 向量。好处是每个 chunk 的向量都包含了整篇文档的上下文信息(不是孤立编码),对长文档检索更准。Jina 在 2024 年提出了这个方案并开源了实现。适合长文档、跨段落语义关联强的场景。

一句话:父子分块用"大小块分工"解精度-上下文矛盾,late chunking 用"先编码再切"解孤立编码问题。 两者都增加复杂度,基础策略调到瓶颈再上。


六、评测:分块好不好用数据说话

分块调完不能靠"看起来召回还行"上线,必须量化评测。和本站《RAG 系统评估 SOP》一脉相承,分块直接影响的是检索质量维度:

  • context_recall(召回率):标准答案里的信息是否都被检索到了。分块太大会漏召回(语义被稀释排名靠后),太小也会漏(上下文断裂不完整)。这是分块调优最该盯的指标。
  • context_precision(精准率):相关 chunk 是否排在前面。分块太大会让不相关内容混进同一个 chunk 拉低 precision。
  • 命中率(hit rate):top-k 里是否包含正确 chunk。简单直观,适合快速 A/B 对比不同 chunk_size。

评测流程:准备 50-100 条标注样本(含 question、ground_truth),用 Ragas 或 DeepEval 跑一遍,对比不同分块参数下的 context_recall 和 context_precision。具体代码和指标读法见本站《RAG 系统评估 SOP》,这里不重复。关键原则:每次只改一个变量(只改 chunk_size 或只改 overlap),否则没法归因。


七、五步走:分块调优流程

把前面串成可复制的流程:

  1. 分析文档类型。 看语料是结构化技术文档、Markdown、还是纯文本?主题跨度大不大?条目自包含还是长篇连贯?文档类型决定策略选型方向。
  2. 选策略。 有结构优先文档结构感知,没结构用递归分块兜底,长文档主题跨度大考虑语义分块。先从递归分块起步,它是稳妥默认。
  3. 定 chunk_size 和 overlap。 按语料类型从经验值起步(通用文档 500/50,FAQ 300/30,长文档 1000/100),overlap 设 chunk_size 的 10%。
  4. 评测。 用标注样本跑 context_recall / context_precision / hit rate,对比不同参数。每次只改一个变量。
  5. 迭代。 评测分数不够就回去调参数或换策略,循环直到达标。上线后文档更新要重跑评测,防止分块策略对新文档失效。

八、四个踩坑实录

1. 一刀切固定长度。 图省事用固定长度硬切所有文档,句子和条款被从中间劈开,召回质量塌方。固定长度只用于快速验证,生产环境至少上递归分块。

2. 忽视文档结构。 Markdown 文档明明有标题层级,却用纯文本方式切,把一个标题和它的正文切到两个 chunk,检索到正文片段时缺少标题上下文。有结构的文档一定用结构感知策略。

3. overlap 设为 0。 节省存储把 overlap 设为 0,切分边界的内容丢失上下文,跨 chunk 的信息(比如一句话被切成两半)检索到一半回答就不完整。overlap 至少设 chunk_size 的 10%。

4. 不评测就上线。 凭感觉调完参数,"看起来召回还行"就发布,上线后用户一问就发现召回漏了关键文档。分块参数必须用标注评测集量化验证,没有例外。评测方法见本站《RAG 系统评估 SOP》。


FAQ

Q1:chunk 切多大合适? 没有万能值,经验区间 256-1024 token。FAQ/短条目 300-500,通用文档 500-800,长篇条款 800-1200。最终值必须拿自己的语料和评测集测出来。原则:chunk 要大到包含完整语义单元,小到不被多主题稀释。

Q2:overlap 多少合适? 经验值是 chunk_size 的 10%-20%(如 chunk_size 500 → overlap 50-100)。作用是防切分边界丢上下文。设 0 会丢边界信息,设太大(超过 30%)会让内容重复出现在多个 chunk,浪费存储、稀释检索精度。

Q3:四种分块策略哪个好? 没有银弹。有文档结构(Markdown/HTML)优先用结构感知,通用文本用递归分块兜底(最稳妥默认),长文档主题跨度大用语义分块,固定长度只用于快速验证。先从递归分块起步,调到瓶颈再换进阶策略。

Q4:怎么评测分块好不好? 用标注样本跑检索指标:context_recall(是否漏召回)、context_precision(相关 chunk 排前没排前)、hit rate(top-k 命中没命中)。对比不同 chunk_size/overlap 下的分数,每次只改一个变量。具体工具和代码见本站《RAG 系统评估 SOP》。

Q5:中文文档分块有什么要注意的? 两件事。一是分隔符:递归分块的分隔符列表务必加入中文句末标点(。!?;),否则 splitter 只认英文标点会在中文句子中间硬切。二是长度计量:length_function=len 按字符数计,一个中文字算 1;如果想按 token 计需换用 tiktoken,因为中文一个字通常对应 1-2 个 token,按字符切出的 chunk 实际 token 数可能偏大。


参考来源

本文由 AI 辅助生成,经人工审核编辑。最后更新:2026-08-02

常见问题

chunk 切多大合适?
没有万能值,经验区间 256-1024 token。FAQ/短条目 300-500,通用文档 500-800,长篇条款 800-1200。最终值必须拿自己的语料和评测集测出来。原则:chunk 要大到包含完整语义单元,小到不被多主题稀释。
overlap 多少合适?
经验值是 chunk_size 的 10%-20%(如 chunk_size 500 → overlap 50-100)。作用是防切分边界丢上下文。设 0 会丢边界信息,设太大(超过 30%)会让内容重复出现在多个 chunk,浪费存储、稀释检索精度。
四种分块策略哪个好?
没有银弹。有文档结构(Markdown/HTML)优先用结构感知,通用文本用递归分块兜底(最稳妥默认),长文档主题跨度大用语义分块,固定长度只用于快速验证。先从递归分块起步,调到瓶颈再换进阶策略。
怎么评测分块好不好?
用标注样本跑检索指标:context_recall(是否漏召回)、context_precision(相关 chunk 排前没排前)、hit rate(top-k 命中没命中)。对比不同 chunk_size/overlap 下的分数,每次只改一个变量。具体工具和代码见本站《RAG 系统评估 SOP》。
中文文档分块有什么要注意的?
两件事。一是分隔符:递归分块的分隔符列表务必加入中文句末标点(`。!?;`),否则 splitter 只认英文标点会在中文句子中间硬切。二是长度计量:`length_function=len` 按字符数计,一个中文字算 1;如果想按 token 计需换用 `tiktoken`,因为中文一个字通常对应 1-2 个 token,按字符切出的 chunk 实际 token 数可能偏大。

相关文章