RAG分块策略2026:固定大小、递归、语义切分对比
RAG分块策略2026:固定大小、递归、语义切分对比。检索质量的上限,往往在切文档那一刻就定下了
📜 目录
RAG分块策略2026:固定大小、递归、语义切分对比
检索质量的上限,往往在切文档那一刻就定下了。检索只能返回你切出来的块,块切得太大,相关性被稀释;切得太小,上下文丢失。这篇把主流切分策略拆开讲清楚,给出参数表,最后给一套能落到数据上的选法和验证方法。
一、为什么分块决定成败
一个块同时承担两个任务:作为 embedding 的输入,也作为喂给模型的上下文。
- 块太大:一段话里混了好几个主题,embedding 把语义平均掉,检索时哪个问题都沾一点,哪个都不精准;喂给模型时还白烧 token
- 块太小:主语、指代、前提被切掉,模型看到"它的价格是 99"却不知道"它"是谁
- 边界切错:一句话被拦腰截断,答案的一半在上一块
同一个知识库,换一种切法,检索命中率能差出十几个百分点。这个差距比换 embedding 模型小,但比调 top_k 大。
二、五种策略一一拆解
1. 固定大小切分
按字符数或 token 数切,加重叠窗口。最朴素,也最通用。
from langchain_text_splitters import CharacterTextSplitter
splitter = CharacterTextSplitter(
chunk_size=500,
chunk_overlap=80,
separator="",
)
chunks = splitter.split_text(document)
特点:不认文档结构,表格和代码容易被切断。适合格式混乱、结构不明的纯文本。重叠的作用是防止句子被切开,常见取块大小的 10% 到 20%。
2. 递归切分
优先按大结构切(段落),切不动再按句子,再不行按字符。LangChain 的 RecursiveCharacterTextSplitter 就是这套逻辑,也是多数项目的默认选择。
from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=150,
separators=["\n\n", "\n", "。", "!", "?", " ", ""],
)
中文文档里把句号、问号、叹号加进分隔符,效果比只用换行好。注意 chunk_size 的单位是字符,中文一个字算一个字符,和英文 token 不是一个量级,照抄英文教程的 1000 会切出很长的块。
3. 结构感知切分
Markdown 按标题切,HTML 按标签切,代码按函数切。块天然带上层级信息。
from langchain_text_splitters import MarkdownHeaderTextSplitter
splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=[("#", "h1"), ("##", "h2"), ("###", "h3")]
)
这类切分把标题写进元数据,检索时可以按标题过滤,回答时可以把标题拼回上下文。技术文档、手册、法规这类层级清晰的资料,优先用这种。
4. 语义切分
用 embedding 判断相邻句子的语义相似度,跌到阈值以下就切一刀。LlamaIndex 的 SemanticSplitterNodeParser、LangChain 的 SemanticChunker 都实现了。
优点:能切在真正的主题变化处,跨段落的长论述不会被打断。 缺点:要调用 embedding 模型,成本高、速度慢;阈值敏感,调不好会切出大量碎块。
5. 父子块与小块召回
把"用来检索的块"和"喂给模型的块"分开:用小块做向量检索保证精准,命中后取它所属的大块(父块)送给模型保证上下文完整。LangChain 的 ParentDocumentRetriever 就是这个思路。
这类设计通常比单纯调块大小更有效,代价是存储和索引要维护两份。
三、参数对照表
| 策略 | 块大小参考 | 重叠 | 成本 | 适用文档 |
|---|---|---|---|---|
| 固定大小 | 300-500 字符 | 10%-20% | 最低 | 格式混乱的纯文本 |
| 递归 | 500-1000 字符 | 10%-15% | 低 | 通用文档,中文偏小 |
| 结构感知 | 按章节 | 少量 | 低 | Markdown、HTML、手册 |
| 语义 | 按主题边界 | 不需要 | 高 | 长论述、访谈稿 |
| 父子块 | 小子块 + 大父块 | 视情况 | 中 | 问答对精度要求高 |
块大小没有普适最优值。公开基准里,几百 token 的块在多数问答负载上表现较好,但这是统计意义上的结论,你的文档类型和问题类型会改变结果,所以必须自己测。
四、按查询类型设计块
同一个知识库,问题类型不同,最优块形态不同:
- 事实查找("退款期限是几天"):小块、高精度,块里最好只有一个事实
- 流程说明("怎么申请报销"):块要包含完整步骤,宁可长一点
- 对比类("A 和 B 有什么区别"):每个块里放一个完整论点,别把对比的两方切散
- 摘要类("这份报告讲了什么"):按章节切,保留层级
如果业务里混着多种问题,做两套索引比强行折中更实际。
五、怎么用数据验证,而不是靠感觉
- 从真实用户提问里挑 50 到 100 条,确保覆盖主要意图
- 人工标注每条问题对应的原文片段,作为标准答案
- 同一批文档,用两三种切分策略各建一套索引
- 跑同一批问题,统计标准答案所在块是否进入 top 3、top 5
- 比较命中率和平均块长度,再决定
如果语义切分相比递归切分只提升几个百分点,多花的 embedding 成本和延迟不值得,选递归。提升明显再上。
另外两个容易漏的检查:
- 看坏例子,别看平均值:一条检索失败的样本,能暴露切分逻辑的系统性问题
- 块长度分布:如果出现大量几十字符的碎块,说明分隔符配错了,这些块基本检索不到东西
六、几条实战经验
- 中文文档的字符数和英文 token 数差距大,参数不要照抄英文教程
- 表格单独处理,按行切并保留表头,否则表格检索几乎无效
- 代码块整块保留,切开就失去意义
- 给每个块加上来源文件名、章节标题、页码这些元数据,检索后能给出处,用户信任度完全不同
- 文档更新要做增量重建,全量重切在文档量大时耗时不可接受
常见问题
Q:块大小到底设多少?
A:先按递归切分、500 到 800 字符、10% 重叠起步,用 50 条真实问题测召回,再上下调。文档短、问题细就切小,文档是长论述就切大。
Q:重叠必须加吗?
A:句级切分且分隔符配得好的话,重叠可以很小甚至为 0。用字符硬切时建议加,代价是索引体积变大、同一段内容被重复召回。
Q:语义切分值得上吗?
A:文档长、主题跳跃多、检索质量要求高的时候值得。日常问答,递归切分加好的分隔符已经能拿到大部分收益。
Q:分块和重排哪个先优化?
A:先修分块。重排是在候选集里挑,候选集本身错了,重排救不回来。
相关文章
本站文章由编辑人工撰写,收录的工具均经过实测或公开资料核验。文中链接指向工具官网或 GitHub 仓库,仅作信息参考,不构成付费推广。