固定长度、递归字符、语义分块和结构分块怎么选?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/

智元界将持续分享可运行的技术实战、架构设计、问题排查与企业应用案例。