固定长度、递归字符、语义分块和结构分块怎么选?RAG Chunk策略对比
文章摘要
Chunk策略决定了RAG系统能够检索到什么、丢失什么,以及大模型最终看到多少完整上下文。固定长度分块实现简单但容易切断条款;递归字符分块通用性强;语义分块边界自然但成本较高;结构分块最适合制度、合同和技术文档,却依赖可靠的文档解析。本文从边界质量、实现成本、检索效果、元数据和适用文档等维度对比四种策略,并给出企业项目的组合方案。
一、Chunk不是越大越好
Chunk过小:
- 条件与结论分离;
- 标题与正文分离;
- 上下文不足;
- 召回结果数量增加;
- 重排成本增加。
Chunk过大:
- 包含大量无关内容;
- 向量语义变得模糊;
- 正确答案在片段中不突出;
- Token成本增加;
- 多个主题混在一起。
理想Chunk应该满足:
语义相对完整
+主题相对单一
+包含必要条件
+适合Embedding模型
+可追溯到原文
二、固定长度分块
按照字符或Token数量切分:
每500 Token切一块
重叠100 Token
伪代码:
def fixed_chunks(
tokens: list[str],
chunk_size: int,
overlap: int
) -> list[list[str]]:
chunks = []
start = 0
while start < len(tokens):
end = start + chunk_size
chunks.append(tokens[start:end])
start = end - overlap
return chunks
优点
- 实现简单;
- 速度快;
- 结果数量可预测;
- 适用于纯文本;
- 便于控制Embedding上限。
缺点
- 容易切断句子;
- 容易切断条款;
- 表格和代码结构被破坏;
- 不理解标题层级;
- 重叠会产生重复内容。
适合
- 日志;
- 聊天记录;
- 结构很弱的长文本;
- 快速原型;
- 已经清洗好的短段落。
三、递归字符分块
按照一组分隔符逐级尝试:
章节
→ 段落
→ 句子
→ 标点
→ 字符
常见分隔符:
separators = [
"\n\n",
"\n",
"。",
";",
",",
""
]
如果一个段落超过上限,再使用更细粒度分隔符继续切。
优点
- 比固定长度更尊重自然边界;
- 不需要Embedding计算边界;
- 适合中文;
- 实现成本较低;
- 可控制最大Chunk。
缺点
- 分隔符依赖语言和文档类型;
- 无法识别真正主题变化;
- 标题层级仍可能丢失;
- 表格和代码仍需特殊处理。
适合
- Markdown;
- 网页正文;
- 普通制度和说明文档;
- 中文知识库;
- 中等复杂度RAG。
四、语义分块
语义分块通常计算句子或段落Embedding,然后判断相邻内容的语义变化。
链路:
句子切分
→ 每句Embedding
→ 计算相邻距离
→ 距离突变处切分
示意:
similarities = cosine_similarity(
sentence_vectors[:-1],
sentence_vectors[1:]
)
for index, score in enumerate(similarities):
if score < threshold:
create_boundary(index)
优点
- 边界更接近主题变化;
- 可减少无关内容混合;
- 对长文章和研究报告有效;
- 不完全依赖排版符号。
缺点
- 需要额外Embedding调用;
- 入库成本和时间上升;
- 阈值难统一;
- 短句容易产生噪声;
- 模型变化后边界可能变化;
- 结果长度不稳定。
适合
- 长篇报告;
- 访谈;
- 研究材料;
- 主题切换明显的内容;
- 高质量离线知识库。
五、结构分块
结构分块利用文档自身结构:
标题
章节
条款
列表
表格
代码块
图注
例如制度文档:
第一章 总则
第一条
第二条
第二章 申请流程
第三条
可以按“条款”作为基础单元,同时附带章节路径:
{
"title": "差旅管理制度",
"section_path": [
"第二章 申请流程",
"第三条 审批要求"
],
"content": "……"
}
优点
- 语义和业务边界最清晰;
- 标题、条款、表格可保留;
- 易于引用;
- 元数据丰富;
- 适合权限和版本管理。
缺点
- 强依赖解析质量;
- 不同格式需要不同策略;
- 扫描PDF处理困难;
- 结构异常时需要降级;
- 工程复杂度最高。
适合
- 制度;
- 合同;
- 招标文件;
- 产品手册;
- API文档;
- 法律法规;
- 技术规范。
六、四种策略对比
| 维度 | 固定长度 | 递归字符 | 语义分块 | 结构分块 |
|---|---|---|---|---|
| 实现难度 | 低 | 低到中 | 中到高 | 高 |
| 计算成本 | 低 | 低 | 高 | 中 |
| 边界自然度 | 低 | 中 | 高 | 高 |
| 长度稳定 | 高 | 较高 | 低 | 中 |
| 依赖文档结构 | 否 | 较低 | 否 | 是 |
| 表格友好 | 差 | 差 | 差 | 好 |
| 引用友好 | 一般 | 一般 | 中 | 好 |
| 企业制度适用 | 一般 | 较好 | 较好 | 最好 |
七、Overlap应该设置多少
Overlap用于减少边界信息丢失,但不是越大越好。
过小:
上下文跨Chunk断裂
过大:
重复召回
向量库膨胀
重排结果高度相似
Token浪费
建议从比例开始测试:
Chunk 500 Token
Overlap 50—100 Token
但结构分块不一定需要固定Overlap。
可以采用:
父标题
+当前条款
+必要前置条款摘要
而不是机械复制100 Token。
八、父子Chunk是一种常用折中
入库两种粒度:
子Chunk:短,负责精准召回
父Chunk:长,负责完整回答
流程:
查询
→ 搜索子Chunk
→ 找到parent_id
→ 获取父Chunk
→ 去重
→ 交给大模型
示例:
{
"chunk_id": "C-101-3",
"parent_id": "P-101",
"section": "4.2住宿标准",
"content": "一线城市标准为500元……"
}
这种模式适合:
- 条款较长;
- 需要精准检索;
- 回答需要完整上下文;
- 文档有清晰层级。
九、表格和代码必须单独分块
表格不应该按普通Token截断。
建议:
表格标题
+表头
+若干完整数据行
代码:
类
方法
函数
配置块
不要把一个函数从中间切断。
十、Chunk Metadata至少包含什么
chunk_id
parent_id
document_id
document_version
section_path
page_start
page_end
content_type
language
tenant_id
status
Metadata不仅用于展示来源,还用于:
- 权限过滤;
- 版本过滤;
- 类型过滤;
- 父子检索;
- 结果去重;
- 质量评测。
十一、不要只按平均回答效果选策略
需要建立分类型测试集:
事实问答
条件问答
跨段落问答
表格问答
版本问答
数字问答
条款引用
指标:
Recall@K
MRR
nDCG
答案忠实度
上下文Token
重复率
入库耗时
某种策略可能对FAQ很好,对表格极差。
十二、企业项目推荐组合
普通Markdown和网页
结构标题
+递归字符
PDF制度和合同
版面解析
+结构分块
+父子Chunk
长篇研究报告
章节结构
+语义分块
日志和聊天
固定Token
+时间窗口
表格
表格结构分块
+结构化字段
总结
没有一种Chunk策略适合所有文档。
选择顺序应是:
先识别文档结构
→ 优先保留业务边界
→ 再控制Token长度
→ 用黄金测试集验证
企业RAG通常不应该只使用固定长度分块,而应采用结构分块、递归分块和父子Chunk的组合。
延伸阅读
如果你正在关注企业级 AI 应用、RAG、Agent、MCP 与大模型工程化落地,欢迎访问 智元界:
https://www.zyentor.com/
智元界将持续分享可运行的技术实战、架构设计、问题排查与企业应用案例。