RAG Chunking 策略的量化评测:别再凭感觉调 chunk_size
中文 RAG 工程实战那篇文章讲过几种常见的 chunk 切分实现,但只停留在”这几种方法怎么写代码”,没回答一个更实际的问题:在你自己的文档集上,到底哪种切分策略更好、chunk_size 该设多大? 大多数团队的做法是抄一个 500 字 + 50 字重叠的经验值就上线了,从来没验证过这个数字是不是适合自己的场景。本文用量化实验的方式把这件事讲清楚。
一、评测怎么做:不重复造轮子
评测指标本身不需要重新发明,我们在LLM 应用 RAG 效果评测框架里已经给过 Context Recall 和 MRR 的实现,本文直接复用这套指标,只是把变量换成”chunking 策略”。核心思路是固定 embedding 模型和检索 top-k,只改变切分方式,观察指标变化——这样才能确认差异是切分策略带来的,而不是其他变量干扰的结果。
二、四种参与对比的切分策略
| 策略 | 做法 | 直觉上的优劣 |
|---|---|---|
| 固定长度 | 按字符数硬切,前后留重叠区 | 实现最简单,但可能把一句话甚至一个表格行切成两半 |
| 按句子/段落 | 沿自然语言边界切分,凑够目标长度 | 语义完整性更好,但长度波动较大 |
| 滑动窗口重叠 | 固定长度基础上加大重叠比例(如 30%) | 缓解边界截断问题,但存储和检索成本上升 |
| 语义/递归切分 | 先按标题/段落层级递归拆分,逼近语义边界后再控制长度 | 效果通常最好,但实现复杂度和处理耗时更高 |
三、关键变量:chunk_size 和 overlap 的扫描实验
单独换切分方法只是第一层变量,chunk_size 本身的取值同样会显著影响结果,所以实验设计上要做二维扫描:固定一种切分策略,分别在 200/500/800/1200 字符四档 chunk_size 下测一遍,同时搭配 0%/10%/30% 三档重叠比例,组合起来跑一轮网格实验。
def sweep_chunking(build_index_fn, chunk_fn, eval_fn, sizes, overlaps, docs, eval_set):
results = []
for size in sizes:
for overlap in overlaps:
chunks = chunk_fn(docs, chunk_size=size, overlap=overlap)
index = build_index_fn(chunks)
score = eval_fn(index, eval_set)
results.append({"size": size, "overlap": overlap, **score})
return results
跑完把结果按 context_recall 排序,通常能看到一个明显的”甜点区间”——chunk_size 太小会导致语义碎片化,检索到的片段缺乏上下文;太大又会把不相关内容和目标答案混在一起,降低 rerank 之后的精确率。这个甜点区间因文档类型而异,没有放之四海而皆准的默认值,这也是为什么”抄一个 500 字的经验值”经常在实际业务上表现平庸。
四、不同文档类型,对切分策略的敏感度不一样
实测中最有价值的发现往往不是”哪个策略总分最高”,而是不同文档类型对切分策略的敏感度差异很大:
- 长篇说明文/文章类文档:语义/递归切分相对固定长度的提升最明显,因为这类文档天然有清晰的标题层级可以利用
- 表格密集型文档:固定长度和滑动窗口都容易把表格从中间切断,导致检索到的片段”有表头没数据”或反过来。这类文档建议在切分逻辑里加表格边界检测,宁可让 chunk 长度不均匀,也不要把表格切碎
- 代码/API 文档:按函数或代码块边界切分(而不是字符数)效果显著优于通用切分策略,因为一段代码被从中间切断基本等于检索结果失效
- FAQ/问答对文档:天然适合按问答对为单位切分,chunk_size 和 overlap 这两个参数在这类文档上的影响反而不大
这个结论的实际意义是:不要用一套 chunking 参数应付所有文档类型,混合文档库应该先按类型分流,再各自应用最适合的切分策略,而不是找一个”平均意义上还不错”的通用参数。
五、一个容易被误解的直觉:重叠区不是越大越好
很多人下意识觉得 overlap 加大总是更安全,实测中这个直觉并不总成立。重叠区过大(比如超过 40%)会导致向量库里出现大量高度相似的 chunk,检索 top-k 时容易被同一段内容的多个重叠版本占满名额,反而挤掉了其他真正相关但没被重复收录的片段,实际拉低了检索多样性。10%-20% 的重叠比例在多数场景下已经能覆盖边界截断问题,继续加大收益递减且有副作用。
六、落地建议:怎么给自己的文档定起点参数
- 从文档类型出发,不要从”经验值”出发——先判断你的文档是长文、表格、代码还是 FAQ,按上一节的规律选切分方法起点
- 用二维扫描实验找 chunk_size 和 overlap 的甜点区间,不要只测一组参数就上线
- 至少构建 20-30 条带标准答案的评测样本,覆盖不同段落位置的答案(开头/中间/结尾),避免评测集本身有偏
- 把这套评测接入 CI,参考把模型评测接进 CI 流水线的思路,未来换 embedding 模型或调整文档格式时能第一时间发现召回率下降
七、常见坑
- 只看 Context Recall,不看 rerank 后的精确率:召回率高但塞进 prompt 的片段质量差,一样会拉低最终生成质量,两个指标要一起看
- 评测集和生产查询分布不一致:用工程师自己编的测试问题跑评测,往往比真实用户提问更规范、更容易命中,评测分数会虚高
- 切分策略调好之后从不复测:文档库内容会持续增长和变化,半年前调好的参数不代表现在依然最优,建议按季度复跑一次评测