RAG 中文档切割的 chunk_size 和 overlap 应该如何设置?
RAG 中文档切割的 chunk_size 和 overlap 应该如何设置?
这道题考的是 RAG 系统中文档预处理的核心参数理解,说白了就是你怎么把一篇长文档切成适合检索的小块。chunk_size 和 overlap 选得不对,后面检索效果再好也是白搭。
我从四个方面来讲:先讲清这两个参数是什么,然后说不同场景怎么选,再介绍高级切割策略,最后提醒你工程里容易踩的坑。
切西瓜理论:理解 chunk_size 和 overlap 的本质
先说大白话。chunk_size 就是每块文本有多大,overlap 就是相邻两块之间重叠多少。
想象你切西瓜。最理想的情况是一刀下去,西瓜籽完整保留。但现实是你可能一刀切在籽上,那颗籽就被切烂了。overlap 的作用就是让你下一刀稍微偏移一点,保证重要信息不被拦腰切断。
128 Token 切出来像词典里的词条,太小了,问个完整问题都装不下。512 Token 切出来像一段连贯的话,语义基本完整。2048 Token 切出来像一整章,内容是够了,但检索时容易引入太多无关信息。
举个例子你就懂了。
原始文本是:"该方法于 2021 年由 OpenAI 提出,主要用于解决大语言模型的幻觉问题。"
按 128 Token 切:可能切成 ["该方法于 2021 年", "年由 OpenAI 提出,", "主要用...", "问题。"] —— 每块都支离破碎,根本不知道在讲什么。
按 512 Token 切:一整句话能完整保留,语义清晰。
按 2048 Token 切:这句话可能跟前后几段合成一块,检索时把不相关的上下文也带进来了。
overlap 的设置也是同样的道理。设为 10-20% 是个经验值,太小了等于没设置,太大了存储和计算成本直接翻倍。
场景决定参数:不同文档类型的 chunk_size 选择
记住了,没有万能的 chunk_size,只有适合你场景的 chunk_size。
| 文档类型 | 推荐 chunk_size | 推荐 overlap | 原因 |
|---|---|---|---|
| FAQ 问答 | 256-384 Token | 10-15% | 问题短,答案也短,语义完整最重要 |
| 技术文档 | 512-768 Token | 15-20% | 要兼顾问题和答案的完整 |
| 论文/长文 | 1024+ Token | 10-15% | 上下文长,需要更大的窗口 |
| 法律合同 | 512-1024 Token | 20% | 条款语义不能断,精度要求高 |
再打个比方。
问你"今天天气怎么样",我给你一整本书你翻都翻不过来。问你"《红楼梦》讲了什么",我给你一句话你肯定不满意。
FAQ 类场景,答案就那么几句话,chunk_size 设太大反而引入噪音。技术文档稍微复杂点,需要点上下文但也不能太多。长文档本身就有连贯性,设大一点问题不大。
overlap 怎么调?
答案被切断了 → 增大 overlap 或者增大 chunk_size
检索出来的内容不相关 → 减小 chunk_size 或者改用语义切割
上下文丢失 → 增大 overlap
这里有个小技巧:overlap 不要超过 chunk_size 的 30%,超过之后收益递减明显,成本倒是蹭蹭往上涨。
超越固定切割:高级切割策略的选择
固定大小切割是最简单的,用了就省事,但问题是你可能会把一个完整的句子从中间劈开,或者把问题和它的答案分到两个块里。
语义边界切割就是顺着语义走,按照段落、句子、标题这些自然边界来切。好处是每块语义完整,坏处是实现起来复杂,而且每块大小不一。
父子切割是个很实用的策略,现在工业界用得比较多。
结构是这样的:有一级父块,大小设成 1024-2048 Token,里面包含多个二级子块,子块设成 256-512 Token。检索的时候用子块去匹配,因为子块小所以匹配精度高。召回之后把整个父块拿出来喂给 LLM,这样上下文就完整了。
Late Chunking 是 2024 年冒出来的新思路。传统方法是先切再 Embed,Late Chunking 反过来,先对整段话做 Embedding,然后按照语义边界去 chunk。这样能保留更长的上下文依赖,缺点是计算成本高。
实际怎么选?
简单场景用固定切割,省事够用。复杂文档用语义切割或者父子切割,效果好但实现成本高。Late Chunking 先观望,等开源工具成熟了再上。
工程避坑:Embedding 模型选错会毁掉一切
这块是面试官最喜欢追问的地方,也是很多人实际工作时踩过的坑。
第一,中文文档必须用中文 Embedding 模型。
BGE、M3E 这些都是专门针对中文微调过的。你用 OpenAI 的 text-embedding-ada-002 或者 text-embedding-3-large 处理中文专业文档,召回效果能差出 20-30%。
打个比方,Embedding 模型就像翻译员。你让一个美国人翻译中文医学论文,翻得再好也会漏掉专业术语。这不是能力问题,是母语背景的局限。
第二,Top-K 不是固定值。
简单问题用 3-5 条就够了,问个"今天周几"给我返回 10 条结果那叫过度检索。
复杂问题用 8-12 条,因为复杂问题涉及的面广,需要多角度验证。
更高级的做法是让 LLM 先判断问题复杂度,动态调整 K 值。这个实现起来不难,但很多人想不到。
第三,检索结果要加相似度阈值。
低于 0.6 的直接告诉用户"文档里没有相关信息",别硬把不相关的内容塞给 LLM。有些 RAG 系统之所以答得离谱,不是大模型的问题,是检索回来的东西根本不对。
有个土办法可以快速验证:随便问一个文档里肯定没有的问题,看看系统返回什么。如果返回了莫名其妙的内容,说明你的相似度阈值设得太低了。
面试怎么答
基础版:
chunk_size 决定每个文本块的长度,我一般根据文档类型来选。FAQ 用 256-384 Token,技术文档用 512 Token,长文档用 1024+ Token。overlap 设成 chunk_size 的 10-20%,防止关键信息被切断。
中文文档一定要用 BGE 这类中文 Embedding 模型,OpenAI 的模型处理中文专业术语效果差很多。
调优方法很简单:跑一遍看效果,答案被切断了就增大 chunk_size 或者 overlap,召回内容不相关就减小 chunk_size。
加分版:
除了固定切割,我还会用父子切割策略。子块用于检索保证精度,父块用于提供上下文保证完整性。
Top-K 我不是固定值,简单问题用 3-5,复杂问题用 8-12。更进一步会让 LLM 先判断问题复杂度,动态调整 K 值。
检索结果我会加相似度阈值过滤,低于 0.6 的直接告诉用户文档里没有这个信息,而不是硬塞给大模型。
Late Chunking 这个思路我也有关注,它从另一个角度解决了上下文丢失的问题,但现在开源工具还不够成熟,我还在观察。
一句话总结
chunk_size 和 overlap 没有标准答案,核心是根据你的文档类型和业务场景来选,中文场景记得换中文 Embedding 模型。
