深蓝黑背景封面。左侧是同一份长文档的三种切法对照:第一条文档带被等宽切成五块,相邻块之间有阴影重叠区,标注「定长分块:每 512 token 一刀切,重叠 10%~20%,简单快但会切断句子」;第二条文档带按段落边界切成不等宽三块,标注「递归分块:先段落、再句子,超限才硬切,保住语义单元」;第三条文档带按主题颜色分成三块,标注「语义分块:按嵌入相似度找主题断点,内聚但依赖模型」。左下一行灰色小注「块太大噪声多,块太小上下文碎,切法决定召回质量上限」。右侧大标题两行「RAG 的文档分块」「有哪些切法」,副标题「定长、递归、语义:边界划在哪,答案就藏在哪」,小注「索引前的一步,决定了检索时的天花板」。左上角标注「面试经典 · RAG」,右上角圆角胶囊标注「Day 06 · 12-03」。 图 1:本文封面,三种分块切法的边界对照。

先说明属性:这是一篇经典题解析,题目出自本地历史面试资料整理,与任何公司的当前招聘无关。「RAG 的文本分块有哪些方法」是检索增强方向的高频题,表面是让你背方法清单,实际考两件事:能不能说清每种切法切的是什么边界,以及块大小这个旋钮往哪边拧、代价是什么。

一句话结论:主流切法分三类——定长切、递归切、语义切,分别切在长度、结构边界和主题断点上;块大小没有标准答案,常见起点 256~512 token、重叠 10%~20%。

先讲为什么要分块。嵌入模型有输入长度上限,几百页的文档整篇塞不进去;就算塞得进,整篇压成一个向量,具体主题的细节会被平均掉,检索时什么都像、什么都不像。分块的本质是把文档切成「可以独立被检索」的最小单元,切法直接决定召回质量的上限。

第一类,定长分块。 每 N 个 token(或字符)切一刀,相邻块保留 10%~20% 的重叠,防止恰好切在答案中间。优点是实现最简单、速度最快、块长均匀;缺点也明显——句子会被拦腰切断,语义残缺。适合日志这类结构规整、单条信息量小的文本。

第二类,递归分块。 给分隔符排优先级:先按段落(两个换行)切,切出来的块还超上限就降一级按换行切,再超按句号切,最后才落到单字符硬切。LangChain 官方文档把 RecursiveCharacterTextSplitter 列为通用文本的默认推荐,理由就是尽量保住完整语义单元。代价是块长不均、实现略复杂,但绝大多数文档场景应该从这里起步。

第三类,语义分块。 把相邻句子分别算嵌入向量,相似度跌破阈值就判定主题切换、在此断开。块内主题最内聚,但每篇文档要多跑一轮嵌入计算,慢,且断点质量依赖嵌入模型本身。适合主题混杂的长文。

用一段代码把前两种切法的差别摆出来(Node.js 22.15.0,node chunk.js,用字符数模拟 token 上限):

function fixedChunks(s, size, overlap) {
  const out = [];
  for (let i = 0; i < s.length; i += size - overlap) {
    out.push(s.slice(i, i + size));
  }
  return out;
}

function recursiveSplit(s, seps, size) {
  const sep = seps[0];
  const pieces = sep === '' ? [...s] : s.split(sep);
  const out = [];
  for (const p of pieces) {
    if (p.length <= size) { if (p.length) out.push(p); }
    else out.push(...recursiveSplit(p, seps.slice(1), size));
  }
  return out;
}
// 分隔符优先级:段落 → 换行 → 句号 → 单字符

实测输出(输入为三段关于分块的短文,上限 40):

定长切分 块1: 第一段讲分块为什么重要:……整篇文档根本塞不进去。⏎第二段
定长切分 块2: 进去。⏎第二段讲检索精度:块太大,答案被噪声淹没……
递归切分 块1: 第一段讲分块为什么重要:嵌入模型有输入长度上限,整篇文档根本塞不进去。
递归切分 块2: 第二段讲检索精度:块太大,答案被噪声淹没;块太小,上下文又支离破碎。

定长切分把「塞不进去」从中间剁开,还因为重叠把「第二段」重复进两个块;递归切分让每个段落完整成块,语义单元保住了。

深蓝黑背景概念图,顶部小字「概念图 · RAG 文本分块」,主标题「三种切法,切的是三种边界」。主体是三列对照卡:左列「定长分块」画一条被等宽切开、相邻块带重叠区的文档带,规则写「固定 N token + 重叠 10%~20%」,优点「实现最简单、速度快」,缺点「句子被拦腰切断、语义残缺」,适用「日志等规整文本」;中列「递归分块」画分隔符优先级链「段落 → 换行 → 句号 → 字符」,规则写「按优先级逐级降档,块超上限才降一级」,优点「尽量保住完整语义单元」,缺点「块长不均、实现略复杂」,适用「文章与文档,框架默认方案」;右列「语义分块」画一条相似度曲线在两个低谷处断开,规则写「相邻句子嵌入相似度跌破阈值即断」,优点「块内主题最内聚」,缺点「多一次嵌入调用、慢且依赖模型质量」,适用「主题混杂的长文」。底部总结条写「块大小权衡:小块检索准但上下文碎,大块上下文全但噪声多;常见起点 256~512 token、重叠 10%~20%,再按召回效果回调」。 图 2:三种切法的规则、优缺点与适用场景对照。

块大小怎么选。 这是一对矛盾:块小,向量语义集中、检索准,但上下文碎,答案可能缺前因后果;块大,上下文全,但噪声多、向量被稀释。工程上的常见起点是 256~512 token、重叠 10%~20%,然后按召回效果回调:发现答案常被切断就加大重叠,发现召回块答非所问就缩小块或换语义切。另有一类结构感知切法可作补充——按 HTML 标签、Markdown 标题、代码函数边界切,文档结构本身就是现成的语义边界。

面试现场的答题结构。 先给三类切法加一句分界线(长度、结构、语义),再各带一组优缺点与适用场景,然后主动谈块大小的权衡与调参路径,最后补一句「切法选择要跟检索评测联动,不能拍脑袋」。答到「分块决定召回质量上限」这一层,这道题就从背书题答成了工程题。你的知识库用的哪种切法?块大小是拍出来的还是调出来的?欢迎聊聊。