资讯详情

RAG分块策略实战:从固定长度到父子分块的选型与调参指南

📅 2026/10/19 9:09:11 | 华诺云谱 👁 阅读
RAG分块策略实战:从固定长度到父子分块的选型与调参指南
做RAG项目快两年如果只让我选一个最影响效果的环节我大概率会选分块chunking而不是向量模型也不是调prompt。原因很简单分块决定了检索系统是在“大海捞针”还是在“池塘里捞针”。很多人把RAG优化一股脑压在模型和向量库上结果召回率上不去、生成答案张冠李戴追根到底往往是分块策略出了问题。这篇我把自己在多个知识库项目里反复试过的分块思路、参数配置、踩坑记录整理出来。不吹什么灵丹妙药只讲实际操作里怎么判断、怎么选、怎么调。适合正在搭RAG、感觉检索结果不稳定的同学也适合刚入门不知道 chunk_size 和 overlap 怎么定的新人。读完后你能对分块策略有清晰的选型依据并且知道怎么评估自己手里的策略到底行不行。1. 为什么分块策略是RAG检索的第一道闸门做RAG的人容易陷入一个误区模型选好了、向量库也搭好了效果为什么还是不行先把分块拿出来重新审视一下往往能发现问题。1.1 分块到底影响了什么召回、上下文和答案质量先说一个反直觉的事实在真实项目里分块导致的效果差异有时候比换模型还大。原因很简单分块直接决定了你喂给检索系统的“最小单元”是什么后面的生成阶段只能在这个单元之上做拼图。第一层是嵌入表达。文本向量不是把每个字编码完就结束而是把整个块的语义压缩成一个向量。如果一块里塞了三四个不同主题向量就成了“平均脸”跟哪个主题都不太像。如果一块只有半句话、连主语都丢了向量表达也会残缺和查询算相似度时天然吃亏。第二层是召回的准确度。RAG 检索阶段通常用余弦相似度或者点积召回 top-k 个块。这个阶段没有“阅读理解”它不关心块里有没有真正回答问题的内容只看向量相似度。如果一个块里混杂太多噪音真正相关的句子被稀释相似度就排不到前面如果一块只截了引言的残句可能跟很多查询都弱相关召回的都是一堆“疑似相关”的片段。第三层是生成阶段的上下文预算。大模型有窗口限制分块大小直接决定能塞进多少内容。块太大两三条就把窗口挤爆模型只能看到开头看不到关键结论块太小为了覆盖问题可能需要拼接七八块混进去的不相关内容又会干扰生成。所以在你折腾 prompt 之前先问一句我的块把上下文组织好了吗这一层叠下来分块就成了RAG 里牵一发动全身的变量。1.2 一个让我重新重视分块的虚拟项目事故说一个我自己踩过的坑虽然细节做了脱敏但过程很有代表性。某次做一个内部流程问答知识库文档是几十篇流程指南结构很规整标题、小节、步骤、注意事项。当时为了图省事我直接把整篇文档按 1000 字符固定长度硬切没有考虑结构也没有加重叠。上线后检索命中率看起来有 70%但人工抽检却发现一堆离谱回答。最典型的一个问题是“备用金申请的上限是多少”。文档里完整内容分两节第一节讲申请步骤第二节讲额度限制。按 1000 字符切分时刚好把“额度限制”从中间拦腰截断前半段在 A 块后半段在 B 块。检索召回的时候 A 块和 B 块都能命中但模型只能看见相邻几块拼不出完整结论于是开始自由发挥答了一个错得离谱的数字。后来我把切分策略改成“按标题层级优先切分”遇到二级标题就强制开新块再在块与块之间加 60 个字符的重叠同样的问题立刻消失。从那以后我不管做什么项目都会把分块策略当成第一优先级来看而不是直接在向量库上面调参数。这个案例说明了一个基本道理分块不是简单的字符串截断而是要尽量让每个块成为能独立回答一类问题的语义单元。一个块拆开就没头没尾再好的检索和模型也救不回来。2. 主流分块策略大全从固定长度到父子分块怎么选分块策略没有绝对优劣只有适不适合。把主流的几类策略拆开看其实都是在实现成本、语义完整性、处理速度之间做权衡。2.1 固定长度分块实现最简单但容易切碎语义固定长度分块就是按字符数或 token 数硬切比如每 500 个 token 切成一块开头 100 个 token 与前一块重叠。优点是处理快、逻辑简单、跨语言都能用处理日志、短消息这类没有明确结构的文本时很方便。缺点也很直接边界不可控。你可能正好把一句话、一个表格行、一段代码表达式从中间剪断。检索时一个“看似相关”的残缺句子被召回大模型拿到以后也没办法补全。中文尤其明显一个词可能三五个字按字符固定切很容易切进词中间。固定长度还有一个隐性坑不同文档的信息密度不一样。同样是 500 字符诗歌可能已经表达完整意象合同条款可能连半个条款都没写完。所有文档都套同一个固定长度要么浪费窗口要么语义不完整。所以现在我用它只做两件事快速搭 baseline或者处理无结构文本。真要上线我更喜欢递归或者结构感知。2.2 递归字符分块日常项目最稳的默认方案递归分块是目前我默认推荐的起点。它不做一刀切而是先准备一组分隔符比如段落换行、句号、逗号、空格。切分时从最大分隔符开始如果当前块长度超过目标值就递归地在下一级分隔符上继续切开。这样切出来的块会比固定长度自然很多块内优先是一段完整段落或完整句子实在超长才继续往下拆。实现也简单只需要维护一个分隔符优先级列表绝大多数开源框架里都自带这个逻辑不需要从头造轮子。用递归分块时有两个参数需要重点理解chunk_size决定目标块大小overlap控制相邻块之间额外保留重叠内容。overlap 的作用是避免因为切分边界把连续上下文一分为二。比如一个流程包含“步骤 1 完成”后马上进入“步骤 2”如果在步骤 1 结尾切断步骤 2 的上下文就丢了加 overlap 后前一块末尾能带上一点后续内容模型拼接时不容易断片。经验上我会把 overlap 设在 chunk_size 的 10% 到 20% 之间。比如 800 的块overlap 给 80 到 160。这个值不是拍脑袋而是通过小样本实验试出来的overlap 太小边界丢失太大则会引入过多重复内容检索结果里很可能出现两三个内容几乎一样的块白白占用上下文窗口。2.3 结构感知分块代码、表格和Markdown要用结构说话遇到结构清晰的文档再用“句子字符”的通用切法就有点浪费了。例如一份技术手册里每个函数都有独立的说明、入参、返回值一张表格可能每行是一个完整记录一篇 Markdown 文档天然有标题层级这些结构本身就是最好的分块边界。结构感知分块的思路是先把文档解析成结构化对象比如按标题组成树然后在树节点边界上切块。对代码按模块、类、函数、方法切对表格按行列或“表头行组”切对 Markdown按标题层级和列表块切对 PDF先按版面分析还原段落和章节。这种策略能最大程度保证块内语义完整但代价是解析成本。文档格式一多需要分别写解析器或者用统一的文档解析方案处理各种格式。真实项目里不需要一次全支持先覆盖占比最高的两三种格式再逐步补。2.4 语义分块用模型判断话题边界效果最好也最贵语义分块是最近很多团队在尝试的方向。它不依赖字符数或标点而是利用语言模型判断“这句话和上一句是不是同一个话题”。当句子间相似度开始明显下降时就认为话题发生了切换在那里切一道缝。优点很明显边界非常自然跨语言、跨格式都能用而且能很好处理“一段话涵盖多个主题”的情况。缺点也很现实费时费钱。每句话都要过一遍模型做相似度计算对于动辄上万篇文档的库入库时间会明显拉长成本也随之上升。所以我的建议是如果文档数量不大几千篇以内而且单篇内容较长、主题切换频繁语义分块值得上。如果文档海量、更新频繁成本就非常敏感最好先用递归分块顶住只在最关键的高频文档上单独做语义分块。2.5 父子分块检索用小块生成用大块父子分块是我认为当前性价比最高的进阶方案之一。核心是同时保存两种粒度的块子块负责检索父块负责提供上下文给大模型。查询时先用子块去和问题算相似度命中后马上找到子块所属的父块再把父块内容交给模型生成答案。举个例子一份技术方案文档里子块可能是“某个功能模块的实现细节”很小很精确父块可能是整个章节包含背景和约束。检索阶段小块的向量更聚焦容易精准命中生成阶段用父块能帮模型理解来龙去脉避免只盯着局部。实现上分块时给每个子块记录父块 ID向量库里可以同时存两套索引或者只存子块索引但把父块内容映射表放在内存。缺点是存储和索引量增加检索阶段要多一次关联查询。但换来的是生成质量的明显提升特别是答案需要引用上下文时。目前大多数知识库项目我都会优先考虑“感知结构的子块 章节级父块”的组合。3. 实操配置chunk_size和overlap到底怎么定策略确定之后参数定多少就成了下一个问题。说实话没有标准答案但有几个维度可以帮助你做决定。3.1 chunk_size用token还是字符先搞清这个再说很多新手上来就问“chunk_size 设多少”但没搞清楚它背后的计算单位。有的框架按 token 计有的按字符计混用会导致完全不同的效果。模型内部是按 token 理解文本的所以用 token 作为单位更贴近模型能力但字符统计简单快速适合做粗糙的初版。一个粗略换算中文里 1 个 token 大约相当于 1 到 1.5 个汉字英文里大约相当于 3 到 4 个字符。如果你用的嵌入模型上下文足够长块大小并不是越大越好因为块太大向量容易被稀释。一般 300 到 800 token 是一个比较稳妥的区间。更准确的做法是在库里统计实际文本分布。比如取 20 篇代表性文档分别按 200、400、800、1200 token 切分用后面要用的评估集跑一遍看命中率的变化。参数选型不能靠感觉要靠小样本试验。3.2 不同文档场景的参考参数表我整理了一些项目里用过且效果不错的参考值。注意这只是起点一定要在你的数据上重新验证。文档类型推荐策略chunk_size建议overlap建议备注FAQ短问答按条目切200~400字符0~20字符一条问答尽量完整放一块技术手册/Markdown结构感知递归500~800 token10%~15%按标题层级优先切分合同/法律条款按条款切800~1200 token100~200 token条款之间不能拆代码仓库说明按函数/类切300~600 token50~80 token函数注释和签名一起保留对话/聊天记录按轮次切1~3轮对话上一轮尾部不要跨会话拼接论文/书籍按章节段落600~1200 token100~200 token图表说明尽量同块这些数值看着差别很大背后逻辑都一样让块尽量匹配你未来查询的“答案粒度”。FAQ 的答案往往一句话所以小块够用合同条款有前提、例外、补充必须整块保留。3.3 一个可以理解的分块实现示例Python伪代码理解原理之后你可以直接用框架自带的分块器也可以自己实现一个简化版本。下面是一个“优先照顾 Markdown 标题、再按段落切分、最后按长度补切”的伪代码。注意只是示意逻辑生产环境建议用成熟解析器。def recursive_split_with_headings(text, max_len, min_overlap): lines text.splitlines() blocks [] current_lines [] current_len 0 for line in lines: # 把标题行当作强切分点保证章节开头不被埋在上一块末尾 is_heading line.startswith(#) if is_heading and current_len max_len * 0.6: block_text \n.join(current_lines) blocks.append(block_text) # 保留上一块末尾少量内容作为重叠 overlap_text block_text[-min_overlap:] current_lines [overlap_text, line] current_len len(overlap_text) len(line) 1 else: current_lines.append(line) current_len len(line) 1 # 达到目标长度时先提交 if current_len max_len: block_text \n.join(current_lines) blocks.append(block_text) overlap_text block_text[-min_overlap:] current_lines [overlap_text] current_len len(overlap_text) if current_lines: blocks.append(\n.join(current_lines)) return blocks这段代码核心是两点一是把标题行当作强切分点二是用上一块的尾部内容作为下一块的前缀实现 overlap。真实生产里还需要考虑 token 计算、特殊分隔符、格式解析但思路可以直接照搬。3.4 元数据与定位信息别扔检索之后的体验全靠它分块之后很多团队只存了文本向量丢了来源信息这非常可惜。每个块都应该保存至少四样元数据文档 ID、章节路径、页码如果有、块编号。有了这些检索结果展示才能给出“来源XX手册第三部分第2.1节”用户和大模型都能快速定位。我现在的习惯是把“来源上下文”直接拼进块内容里再做嵌入。比如“【文档流程手册-2.1节】本节主要描述备用金申请标准……”。这样做的收益是查询“备用金申请标准”时即使正文里没有完全相同的字眼块前面的来源上下文也能帮助模型和向量算法理解内容归属。实测下来对检索质量的提升比单纯调相似度阈值还明显。不过元数据不要堆太多。块的内容长度本来就有限开口堆一大段元数据会稀释正文语义。保留精炼的标题层级路径就够了。4. 效果评估与调优用数据代替感觉分块策略定完必须用效果说话。这也是很多项目缺少的一步没有评估就没有优化方向。4.1 离线评估三件套命中率、MRR和上下文相关性我建议至少构造 100 条真实查询的离线评估集。查询要来自用户真实问题而不是自己编出来的“标准问题”。每一条查询预先标注好应该命中哪些文档片段。常用指标有这么几个命中率Recallk表示正确答案出现在前 k 个检索结果中的比例MRR平均倒数排名关注正确答案排得有多靠前上下文相关性可以由人工或大模型打分判断召回的块是否真的与问题相关。分块策略的差异主要在命中率和相关性上体现MRR 会同时反映排序也很重要。评估集不是一次性工作。每换一次分块策略、每调整一次参数都要重新跑一遍。最好把这套流程固化成脚本或工作流每次改动后自动出报告而不是靠人工翻看几个例子。4.2 同一份文档跑五种策略看实验结果再决定我经常给团队做一次类似这样的对比实验拿同一批文档、同一个向量模型、同一条评估查询分别跑固定长度、递归、结构感知、语义分块、父子分块用表格记录指标再人工看 20 条典型案例。下面是一个虚构项目里的实验结果数值仅作示意重点看对比关系分块策略命中率5MRR10上下文相关性入库耗时(相对)固定长度58%0.523.1/51x递归字符72%0.683.8/51.2x结构感知81%0.764.2/51.4x语义分块78%0.734.4/58.5x父子分块86%0.814.3/52.1x从这个对比能看出结构感知和父子分块综合表现最好语义分块的相关性最高但入库耗时太猛要权衡成本。实际项目里我不会无脑选分数最高的还要考虑文档格式变化频率、维护成本、上线节奏。如果文档格式经常变结构感知的解析器维护成本会高这时递归分块反而更抗造。4.3 上线之后怎么继续观察和迭代离线评估完了不代表结束。RAG 系统上线后要持续记录两类信号一是检索无结果或低置信度的查询二是用户手动点击了哪条来源、模型回答是否被采纳。这些都是免费的金矿。我习惯把没有召回结果的查询单独存一张表每周看一次。如果一类问题总是检索不到很可能就是那些文档的分块策略没覆盖好。比如“跨章节总结”类型的问题单块检索往往都会失败这时自然就会想到引入更大粒度的大块或者用父子分块中的父块直接检索。分块参数最好做成配置项不要写死在代码里。这样每次调整只需要改配置重新灌库而不是发版。入库任务加一个版本号方便回滚和对比。5. 常见问题与排查技巧实录最后分享一些实际项目里经常遇到的问题和排查思路基本都是通用场景你可以直接对照。5.1 检索结果老是丢关键信息先不要急着换模型。第一步看被召回的块内容是否完整尤其是边界处有没有把关键名词、数值、结论切断。如果是优先加 overlap或者换结构感知分块。第二步看是不是目标内容跨越了多个块。比如一个结论的“原因”在上一块、“结果”在下一块模型拼接时漏掉了中间一环。这种情况可以试试父子分块或者把跨块相邻内容合并成大块。还有一个更隐蔽的问题目标文本在文档里被表格或列表拆开普通按段落切分会把列表项拆散。排查时可以打开原始文档对照检索命中的块看列表项的上下文是否被切掉。如果被切掉说明分块器没有正确解析表格和列表需要先做结构化解析。5.2 块与块重复太多导致结果冗余overlap 设得过大或者文档本身有很多重复段落会导致一次检索返回的 top-k 块内容高度雷同。模型看到三块一样的文本不仅浪费上下文还可能把重复内容强调成重点。解决办法有三个一是把 overlap 降到 10% 以下二是检索时引入多样性重排比如最大边际相关MMR的思路三是在入库阶段对重复度太高的块做去重。你可以先统计一下块之间的余弦相似度如果同一文档内有两块相似度超过 0.95说明切得太碎了考虑合并。5.3 文档类型不干净怎么分真实知识库很少是单一格式。PDF、Word、扫描图片混在一起甚至还有一部分是表格截图。这时候分块策略必须前移到“文档解析”环节。先做 OCR 或版面识别把内容还原成可编辑文本再根据区块类型分流普通段落进入递归分块表格按单元格结构切图片先做说明文字提取再和上下文拼在一起。如果文档里既有长文又有问答列表最不稳的方案是全库统一参数。建议在入库流程里给每个文件打一个“文档类型”标签不同标签用不同的分块配置。这个标签可以由文件名规则、目录路径或解析结果自动判断。5.4 成本与延迟怎么平衡分块阶段是个离线过程所以付出更多计算成本是可以接受的。语义分块虽然贵但只在入库时跑一次不拖在线延迟如果你的文档量不大其实可以放心用。在线检索阶段要关注的是向量检索本身和命中块的数量。块数越多、每块越大排序和拼 prompt 的时间就越长。如果对延迟敏感可以把每个块的向量维度降低或者对存储做压缩也可以在检索后只把 top-3 块交给模型而不是无脑塞 top-5。另一个常用优化是给高频块做缓存相同的查询直接返回缓存结果避免每次都走全链路。做分块这几年我个人体会最深的是分块策略不是“切完就完”的一次性工作它和你的文档、检索、生成是绑定在一起的。没有银弹只能小步实验、持续观察。别怕麻烦一开始就建好评估集、把分块参数做成可配置后面调起来会省很多事。如果你的 RAG 系统最近总答不对题我建议先从分块策略下手而不是急着换模型或堆 prompt这个方向值得你先花一天时间验证一下。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑