分块优化指南:5个高效技巧提升工作流
摘要
RAG系统中分块策略决定检索效果,常见五种:固定分块按长度硬切,递归分块按层级降维,
分块(Chunking)策略失误,RAG 系统注定崩溃
面试官抛出一个问题,有人脱口而出:“肯定是 LLM 生成能力太弱。”
面试官笑了笑,没说话。接着展示了一段代码——一个纯粹按固定长度切分的逻辑,把一个完整的句子从中间拦腰截断。
“这块语义都不完整,你让 LLM 怎么恢复?”
全场哑口无言。
后来花了半个月调研源码与实战案例,才发现:RAG 项目失败,70% 的根因都在分块(Chunking)。
今天把这 5 种分块策略拆解清楚,避免重蹈覆辙。
一、先看透 RAG 的完整数据流
别一上来就调模型参数,先搞懂数据在管线里怎么流转。
看清了吗?生成器只看到你喂给它的 chunk。切分没做好,后面全是噪声。
二、5 种分块策略,别再只会无脑固定长度
1. 固定分块 —— 初级玩家的默认选项
最直接的办法:按固定 token 数量切分,加一点重叠防止边界信息丢失。
def fixed_chunk(text, max_tokens=512, overlap=50):
tokens = tokenize(text)
chunks = []
i = 0
while i < len(tokens):
chunk = tokens[i:i+max_tokens]
chunks.append(detokenize(chunk))
i += (max_tokens - overlap)
return chunks
适用场景:
当作 baseline 对比,或者处理日志、纯文本这类无结构内容。别指望它能搞定复杂文档。
2. 递归分块 —— 从段落到句子逐层切割
先按\n\n(段落)切,仍然过长则按\n,再不行按句子边界切。一层一层降维。
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=200,
chunk_overlap=50,
separators=["\n\n", "\n", "。", " ", ""]
)
chunks = text_splitter.split_text(text)
适用场景:
文档有明显段落、章节结构。比固定长度聪明一点,至少不会在句子中间下刀。
下面的流程图把递归分块的决策逻辑画清楚了:
3. 语义分块 —— 让模型自行判断分界点
把句子转成 embedding,相邻句子的相似度突然下降的地方就是边界。语义变了,立即切一刀。
# 语义分块精简实现
sentences = split_sentences(text)
embeddings = embed(sentences)
chunks = []
current_chunk = [sentences[0]]
for i in range(1, len(sentences)):
sim = cosine_similarity(embeddings[i-1], embeddings[i])
if sim < threshold:
chunks.append(join(current_chunk))
current_chunk = [sentences[i]]
else:
current_chunk.append(sentences[i])
适用场景:
法律文书、科研论文、技术支持文档——上下文断裂会直接误导推理的场景。
代价:计算 embedding 开销大,阈值需要反复调试。
4. 基于结构的分块 —— 直接读取文档大纲
HTML 的、,Markdown 的#、##,PDF 的目录树——这些天然标注了内容边界。
每个章节独立成块,单个章节过长再降级用递归分块。
实现要点:
- 用
BeautifulSoup(HTML)、markdown、pypdf等库抽取结构化标识 - 标题层级作为根节点,保持父子关系
- 表格、图片单独处理(要么独立成块,要么抽象摘要嵌入)
说实话,这是生产环境里最稳定的方案。配合递归分块兜底,效果往往比纯语义切分更可靠。
下面这张图对比了结构化分块和普通分块的区别:
5. 延迟分块(动态分块) —— 最精密的方案
反转传统流程:先不切分,保留整篇文档或大段落。等用户查询到来,检索出最相关的 1-2 个大段,然后在这个局部范围内动态切出细粒度块。
类似编程里的惰性求值——拿到上下文信息后再做精细切割。
适用场景:
- 长篇技术报告、学术论文(跨段落的代词指代、引用关系至关重要)
- 文档频繁更新(不用每次重新计算所有分块)
- 法律/医疗等高精度场景(代词、引文不能错位)
代价:
计算开销高。需要支持长 token 的 embedding 模型。查询时多一步动态切分,响应延迟会上升。
三、一张表帮你选策略
| 策略 | 核心逻辑 | 适合场景 | 隐患 |
|---|---|---|---|
| 固定分块 | 按长度硬切 | 日志、baseline | 语义边界任意切割 |
| 递归分块 | 层级降维切割 | 有段落结构的文档 | 依赖分隔符质量 |
| 语义分块 | embedding 相似度 | 法律、论文、高精度 | 贵、阈值难调 |
| 结构化分块 | 读取 HTML/Markdown 标签 | 技术文档、wiki | 需要解析库 |
| 延迟分块 | 查询时动态切割 | 长文、高召回场景 | 慢、贵 |
写在最后
面试那天如果能把这些讲透彻,也不至于被怼到哑口无言。
分块这个环节看着不起眼,却决定了 RAG 系统 70% 的效果上限。别再上来就chunk_size=512草草了事。
最稳妥的组合拳:
- 技术文档 → 结构化分块 + 递归降级
- 长篇报告 → 延迟分块
- 快速验证 → 固定分块打底
- 法律/医疗 → 语义分块硬扛
没有银弹。根据文档类型和你的算力资源量力而行。
来源:互联网
本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。