RAG 检索调优:chunk_size、overlap 与向量模型选择的实验方法
如果你照着网上的 RAG 教程搭过一次 demo很容易陷入类似情况示例语料检索正常换成本领域文档后检索结果变得不稳定。于是反复修改 chunk_size再换向量模型试了很多组仍然说不清问题到底出在哪里。这里的真正问题通常不是某个“最佳参数”不存在而是调参动作没有回答一个更前置的问题让检索失败的是切分还是向量匹配切分与向量化的职责并不相同RAG 的召回流程可以简化成文档被切成多个 chunk每个 chunk 被向量化查询向量与所有 chunk 向量做相似度计算返回分数最高的前 k 个候选。切分决定的是检索单元的语义边界。如果一个问题的答案被拆进两个 chunk每个 chunk 都只覆盖部分证据单独拿任何一个去和查询比较语义都不完整。向量化再强也无法补齐被切掉的上下文。向量化处理的是“已经形成的候选 chunk 与查询的语义接近程度”它决定的是命中之后的排序质量。因此调参前应先把失败分成两类支持答案的文本从来没有出现在前 k 个候选中支持答案的文本出现了但排序明显靠后。前者更可能由切分粒度和切分边界引起后者主要和向量模型、检索返回量或排序策略有关。两类问题混在一起调结果会很难解释。先花少量时间建一个小评估集只靠两三条手工问题和肉眼观察很难判断一次改动是真实改进还是偶然波动。一个低成本、可复现的评估集可以这样构建从真实使用场景收集 2050 条查询不要为了测试方便而把问题改写成过度规范的表达。在原始文档中标记出能回答每条查询的文本范围。固定检索返回数 k例如 10。记录 hit10前 10 个候选中是否出现能支持答案的文本。如果还想评估排序能力可以同时看 MRR。MRR 对每条查询取“第一个相关候选所在位置的倒数”排第 1 记 1排第 5 记 0.2前 k 个没有相关结果记 0最后对所有查询取平均。一个小评估集未必能反映所有长尾场景但已经足够暴露切分和向量化带来的明显差距。重点是每次调参都用同一组查询、同一个 k不要边调边改评估口径。chunk_size 与 overlap 应该按切分粒度对照更稳定的做法是先固定向量模型把切分方案按粒度分成三档做基线对比而不是只把 chunk_size 从一个整数改成另一个整数。细粒度以自然段为基本单元。如果自然段过长超过向量模型可处理长度就在句末、空行或列表边界继续切分。中粒度把一个标题下的相邻自然段合并成一个小节作为一个 chunk。粗粒度直接按章节作为 chunk若超长再在节内自然边界二次分割。这三档的本质不是“数字变大变小”而是让检索单元尽量贴近文档自身的逻辑结构。对同一份文档固定 512 token 按句号硬切和从标题边界处开始切得到的结果可能完全不同。拿到三档基线的 hit10 后再看失败查询属于哪一种如果正确证据被切到两个 chunk 的接缝处细粒度往往会漏掉后半部分信息这时让 chunk 携带更多相邻上下文可能有效如果某个 chunk 里混入了多个主题粗粒度会把与查询不相关的主题也卷进向量里导致正确内容被稀释。overlap 可以先设为 0 做基线。只有当失败查询明确表现为“答案的关键句落在两个 chunk 的交界处”时再逐步增加 overlap例如把前一个 chunk 末尾的一句话带入下一个 chunk或者让下一级 chunk 保留上一级的小节标题。这样做的目的是保持上下文连续而不是让 overlap 本身越大越好。overlap 过大会让同一段文本被多次向量化不仅增加索引体积也会给候选集引入大量近似重复内容。向量模型必须放在切分实验之后再评估如果切分已经把正确证据分成两段换更强或更大的向量模型并不能制造出本来就不存在的完整 chunk。因此应先选出明显更好的切分方案和 overlap 方向再替换向量模型。替换模型时仍需使用同一份评估集、同一个 k。只看两条样例感受不够应分别记录 hit10 和 MRR如果 hit10 没有变化说明模型替换并没有改变“能否找回正确内容”这一层结果如果 MRR 提升说明正确内容确实排得更靠前这对后续只取少量 top 结果的链路是有价值的。实际选择向量模型时要特别关注目标文档的语言和领域。不同模型训练语料的侧重点不同对中文文档、领域缩写、代码和通用英文文档的表现也会有差异。要验证这种差异不能靠模型总排行榜只能靠已经建立的本地真实查询评估集。一套可执行的实验顺序把上面的逻辑收敛为实际操作可以按这个顺序执行建立 2050 条真实查询的评估集计算当前基准的 hit10。固定向量模型按细粒度、中粒度、粗粒度三档切分做对照记录每档的 hit10。选择命中较好的粒度再对失败查询分类如果失败集中在 chunk 边界从 overlap 为 0 开始按句逐步增加直到 hit10 不再提升。固定切分与 overlap再替换向量模型进行第二轮对照。除非 hit10 或 MRR 明显改善否则不必为了换模型而换模型。每轮只改变一个变量并保留完整的查询集和配置记录否则后续无法判断是哪一步带来了提升。这套方法不依赖具体产品也不预设某个固定 chunk_size。它解决的问题是当 RAG 检索效果差时如何用低成本实验找出真正的瓶颈而不是在参数空间里盲目试错。