编程与 AI12 分钟阅读更新于 2026-07-31

RAG 参数怎么调:chunk、overlap、k 与 chain_type

围绕文档分割、向量检索、RetrievalQA 和私人文档聊天机器人示例,把 chunk_size、chunk_overlap、k、search_type、chain_type 这些参数讲成一套能排查问题的调参方法。

相关工具

RAG 调参不是玄学,先看错在哪里

RAG 系统答不好时,很多人第一反应是换模型或改 Prompt。其实不少问题出在更前面:文档切得太碎,关键句被拆开;chunk 太长,模型读到一堆噪声;k 太小,答案材料没召回;k 太大,重复内容挤满上下文;chain_type 选得不合适,长文档处理反而变差。

相关概念 里这些参数散在几个章节里:文档分割讲 `chunk_size` 和 `chunk_overlap`,向量检索讲 k 和 source_documents,检索式问答链讲 `stuff`、`map_reduce`、`refine`,私人文档聊天机器人里又把 `chain_type` 和 k 放进 `load_db(file, chain_type, k)`。这些不是孤立配置,它们共同决定一次回答能看到什么材料。

调参最怕凭感觉。更稳的办法是先观察错误:是没命中文档,是命中了但重复,是上下文太长,还是答案没用证据。问题定位清楚后,再动对应参数。

RAG 调参面板 UI 草图
RAG 调参面板

把 chunk_size、chunk_overlap、k、chain_type、search_type 和 source_documents 放在一起看,调参才有依据。

chunk_size 决定模型一次看到多大一块

相关的文档分割章节说得很清楚:长文档需要切成较小块,因为模型有上下文限制,长文本处理也会带来计算成本。`chunk_size` 就是每个块包含的字符或 token 数量。它不是越大越好,也不是越小越准。

chunk 太小,语义容易断。比如一句话刚讲到条件,下一块才讲结论,检索只命中其中一块时,模型就会拿到半截信息。文中的短句分割示例也能看到,文本被切成很多小块后,虽然每块都符合长度要求,但上下文被拆散了。

chunk 太大,召回结果会变得笨重。用户只问一个细节,系统却把一大段材料塞进 prompt。模型要从里面自己找重点,token 成本也会上升。私人文档机器人示例里使用 `chunk_size=1000`,这是一个教学场景下比较稳的起点,但不是所有资料都该固定用这个值。

chunk_overlap 是给分割边界留缓冲

`chunk_overlap` 表示相邻两个块之间共享多少内容。文中解释它的作用是保持上下文连贯,避免分割点附近的信息丢失。比如上一块结尾提到“Python 是前提”,下一块开头解释原因,适当重叠能让两边都有一点上下文。

overlap 太小,边界处容易断;overlap 太大,又会制造大量重复。重复 chunk 在后续向量检索里会带来新问题:Top-K 可能被相似片段占满,模型看到的材料变多,信息增量却没有增加。

相关的私人文档机器人用 `chunk_overlap=150`。这个数值适合拿来当起点,之后要看资料类型调整。结构化手册、FAQ、短文档可以小一点;长段落、课程讲义、法律或制度文档可以适当大一点。关键不是记住某个固定数字,而是看 source_documents 是否既完整又不重复。

chunk_size 与 chunk_overlap 示意图
chunk_size 与 chunk_overlap

chunk_size 控制每块长度,chunk_overlap 在相邻块之间保留重叠内容,帮助减少分割边界带来的语义断裂。

RecursiveCharacterTextSplitter 通常比纯字符分割更稳

资料 对比了 `CharacterTextSplitter` 和 `RecursiveCharacterTextSplitter`。纯字符分割器按指定分隔符处理,如果分隔符不合适,可能整段不切,或者切得不自然。递归字符分割器会按双换行、单换行、空格、空字符这样的优先级递归处理,尽量把语义相关概念留在一起。

这也是为什么通用文本里更常用 RecursiveCharacterTextSplitter。它没有理解语义,但它尊重文本结构。段落、换行、空格这些结构信息,往往比硬按固定字符数切开更接近人类写作方式。

如果资料是 Markdown,文中还提到可以按标题分割,并把标题作为 metadata。这个思路很有价值。教程、手册、产品文档通常有标题层级,按标题切分比按字符硬切更容易保留上下文,也方便后面按章节过滤。

k 控制召回数量,也控制噪声数量

文中多次出现 k。向量检索示例用 `similarity_search(question, k=3)`,私人文档聊天机器人把 k 作为 `load_db` 参数传入,并在检索器里写成 `search_kwargs={"k": k}`。k 的含义很简单:每次检索返回多少条候选文档。

k 太小,容易漏。用户问的问题可能需要两三处材料合起来回答,只返回一条 chunk 就不够。k 太大,噪声会上来,尤其在文档重复、切分 overlap 较大、问题又很宽泛的时候,模型会拿到很多不该看的内容。

调 k 时不要只看最终答案。要直接看 source_documents:前几条是否来自正确文件,是否命中关键页,是否重复,是否有明显无关内容。如果 k 从 3 调到 5 后答案变差,原因很可能不是模型变笨,而是多出来的材料干扰了它。

search_type 决定检索策略

私人文档机器人示例里使用 `search_type="similarity"`,也就是普通相似度检索。它适合大多数入门场景,写法简单,速度也直接。但前面的检索章节已经展示过,相似度检索会遇到重复和范围不准的问题。

如果 source_documents 里有大量重复,可以考虑把 search_type 调成 MMR。MMR 会在相关性和多样性之间做平衡,避免 Top-K 都是同一段内容的变体。这个调整通常比盲目降低 k 更稳,因为它保留了候选数量,同时减少重复。

如果问题里经常出现“第二章”“2025 版”“某个来源”这类限定条件,单靠 search_type 不够,还要加 metadata 过滤或 SelfQueryRetriever。检索策略要和资料结构配合,不能只靠一个参数解决所有问题。

chain_type 影响文档怎么交给模型

文中对 `stuff`、`map_reduce`、`refine` 做了实验。stuff 是最简单的方式,把检索到的文档一起塞进上下文,一次调用 LLM。它快、好调,但受上下文窗口限制。资料少、k 不大、chunk 不长时,stuff 往往是第一选择。

map_reduce 会先让每个文档单独生成中间答案,再合并成最终答案。它能处理更多文档,但速度更慢,而且 示例里结果反而更差:因为信息被分开处理,分散在不同文档里的线索不一定能在同一上下文中被理解。

refine 会逐个文档更新答案,适合证据分散、需要逐步修正的场景。它也更贵、更慢,输出稳定性还要单独验证。选择 chain_type 时,不要把复杂当高级。先用 stuff 跑出基线,再用真实问题测试其他策略。

chain_type 选择图
chain_type 怎么选

stuff 快而简单,map_reduce 能处理多文档但可能割裂,refine 适合分散证据但成本更高。

一次只调一个参数

RAG 调参最容易犯的错,是同时改 chunk_size、overlap、k、Prompt 和模型。改完以后答案好了,你不知道是哪一步起作用;答案坏了,也不知道该退回哪里。

更稳的做法是先固定测试集。准备十几个真实问题,每个问题都保存期望来源和判断标准。然后一次只改一个参数,比如先把 k 从 3 调到 5,看 source_documents 是否覆盖更完整;再调 chunk_overlap,看边界信息是否改善;最后再比较 chain_type。

每次测试都要记录三样东西:命中的文档、最终答案、人工判断。只看答案会遗漏很多信息。source_documents 变干净了,答案才有机会稳定;source_documents 一直乱,Prompt 写得再漂亮也只是补救。

常见问题

chunk_size 有没有固定推荐值?

没有。示例里私人文档聊天机器人使用 1000 作为起点,但实际要根据文档结构、问题粒度和上下文窗口调整。

k 越大答案越好吗?

不一定。k 大能召回更多材料,也会带来更多噪声和重复。要看 source_documents 是否更完整,而不是只看数量。

chain_type 应该默认选什么?

多数轻量场景先用 stuff。它快、简单、容易调试;只有遇到长文档或证据分散时,再测试 map_reduce 或 refine。

RAG、知识库与长期记忆

继续阅读

返回专题