RAG切分没做好,后面全白搭:分块策略实战指南
分块是RAG最被低估的环节。固定长度、语义分块、层次分块、父子文档、按结构切——五种策略的取舍与代码思路。
检索不准,先怪分块
RAG 效果差,大家习惯去调 embedding 模型、换向量库、加 reranker。但十次里有六次,根因是分块(chunking)没做好。
一个被切成两半的段落,前半段没了主语,后半段没了结论。向量化之后,两半都检索不准。再好的检索器,也救不回被切碎的知识。
为什么要分块
因为上下文窗口有限,且长文本的信息密度不均。分块的目的是:让每个块成为一个语义完整、可独立理解、又足够聚焦的单元。
切得太大:召回的块里混入无关内容,噪音干扰模型。切得太小:语义断裂,检索到也读不懂。
五种主流策略
策略一:固定长度分块
最简单,按 token 或字符数切,块之间留重叠(overlap)。
for i in range(0, len(text), size - overlap):
chunk = text[i:i + size]
- 优点:实现简单、速度快、块大小均匀
- 缺点:无视语义,可能切在句子中间
- 适用:结构松散、均匀的文本,作为基线
关键参数:块大小 300–800 token,重叠 10%–20%。重叠是为了防止答案恰好落在边界被切断。
策略二:语义分块
按句子或段落的语义相似度切分——语义发生明显转折处,就是切点。
- 做法:逐句计算相邻句子相似度,相似度骤降处切分
- 优点:块内语义连贯
- 缺点:计算成本高,块大小不均
适合长文章、报告这类连续散文。
策略三:结构感知分块
利用文档本身的结构:Markdown 标题、HTML 标签、代码块、表格。
# 一级标题 → 大块边界
## 二级标题 → 中块边界
### 三级标题 → 小块边界
- 优点:尊重文档逻辑,块天然完整
- 缺点:依赖文档格式质量
- 适用:技术文档、产品手册、维基
这是结构化文档的首选。
策略四:父子文档(Parent-Child)
用小块做检索,用大块做上下文。
- 检索单元:小句子(精确匹配)
- 返回单元:其所属的父段落(完整上下文)
好处:既保证检索的精度,又保证喂给模型的上下文完整。这是目前企业 RAG 里效果最好的模式之一。
# 检索命中 child,返回对应的 parent
results = search(child_chunks, query)
context = [c.parent for c in results]
策略五:层次/多粒度分块
同一份文档建多个粒度的索引:段落级、小节级、章节级。检索时按问题类型选择粒度。
- 精确事实 → 用小粒度
- 需要综述 → 用大粒度
怎么选:决策表
| 文档类型 | 推荐策略 |
|---|---|
| 技术文档/Markdown | 结构感知 + 父子 |
| 长报告/散文 | 语义分块 |
| 聊天记录/邮件 | 按消息/会话边界 |
| 表格/数据 | 结构保留,别拆行 |
| 混合内容 | 按类型分别处理 |
三个高频陷阱
- 无脑固定长度:对结构化文档是灾难,标题和正文被拆散
- 忽略表格:表格被按字符切开就彻底失去意义,要整体保留
- 元数据丢失:每块都要带来源、标题、页码等元数据,否则检索到也说不清出处
元数据示例:
source: "产品手册.pdf"
section: "3.2 退款政策"
page: 14
chunk_id: "doc12-3.2-01"
验证分块质量
别拍脑袋,用数据验证:
- 抽样看切出来的块,能否独立读懂
- 拿已知答案的问题,看答案所在的块能否被检索到
- 对比不同策略的召回率与答案准确率
分块是一个需要实测调优的环节,没有普适最优解。
落地清单
- 文档类型是否已分类,分别选用策略?
- 结构化文档是否按标题切分?
- 表格、代码块是否整体保留?
- 是否保留重叠以防边界切断?
- 每块是否附带完整元数据?
- 是否用父子文档提升上下文质量?
- 是否用真实问答集实测过召回率?
结语
分块是 RAG 的地基。地基没打好,上面堆再多 reranker、再换更贵的模型,都是在歪楼上加层。 先把分块做对,再谈优化——你会发现问题少了一大半。