跳到主要内容

文档切片策略选择

假设你点了一个超大的披萨,18寸的那种。

直接抱着吃?不现实。得切成小块。

但怎么切有讲究:

  • 切太大,嘴巴塞不下
  • 切太小,馅料都掉了,吃起来没味道
  • 切得位置不对,可能把一块完整的培根切成两半

文档分片也是同样的道理。

大模型的上下文窗口是有限的,一篇几万字的文档塞不进去。而且我们检索的时候,想找到的是最相关的那一小段,不是整篇文档。

所以要切块。但切多大、怎么切,直接影响后面的检索效果。

切大了切小了,都是问题

切太大会怎样

假设我把一篇5000字的文档切成5块,每块1000字。

问题一:检索不精准

用户问"打印机怎么换墨盒",检索返回的那一块1000字里,可能只有100字是真正讲换墨盒的,其他900字讲的是打印机怎么联网、怎么设置纸张大小。

这900字就是噪音,会干扰大模型的判断。

问题二:超出上下文限制

检索返回5块,每块1000字,加上用户问题和系统提示词,总共可能有6000+字。

如果大模型的上下文窗口只有4096 tokens,直接就超了。

切太小会怎样

假设我切成50块,每块100字。

问题一:语义不完整

一句话被切成两半,前半句在A块,后半句在B块。

A块:如果打印机出现卡纸现象,请先
B块:关闭电源,然后打开后盖取出纸张。

单独检索到A块或B块,都是不完整的信息。

问题二:上下文丢失

有些内容需要结合上下文才能理解。比如:

上一段:XX-3000型号打印机支持双面打印。
这一段:该功能需要在驱动程序中开启。

如果"这一段"被单独切出来,"该功能"指的是什么就不清楚了。

所以到底切多大

没有标准答案,得看你的具体场景。

但有一些经验值可以参考:

场景建议大小原因
技术文档500-1000字技术内容逻辑性强,需要保持段落完整
新闻资讯300-500字内容相对独立,可以切小一些
法律合同按条款切每个条款是独立的语义单元
代码文档按函数/类切代码有明确的结构边界
分块大小经验值

通用起点:chunk_size = 500~1000字,overlap = chunk_size的10%~20%。宁可先设大一点,发现检索不精准再缩小。不同场景差异较大,最终要通过实际测试集来验证效果。

五种常见的切块方式

不同的切块方式,适合不同的场景。下面一个个讲。

文档切块策略怎么选:从结构、语义到成本的取舍
文档切块策略怎么选:从结构、语义到成本的取舍

方式一:固定大小切块

最简单粗暴的方式——数字符,够数了就切一刀。

原文:ABCDEFGHIJKLMNOPQRSTUVWXYZ(26个字母)
设置:每10个字符切一块
结果:
块1: ABCDEFGHIJ
块2: KLMNOPQRST
块3: UVWXYZ

参数说明

  • chunk_size:每块的字符数
  • chunk_overlap:相邻块之间重叠的字符数

Overlap是什么意思?就是让相邻的两块有一部分内容是重复的:

设置:chunk_size=10, overlap=3
结果:
块1: ABCDEFGHIJ
块2: HIJKLMNOPQ (HIJ和块1重叠)
块3: OPQRSTUVWX (OPQ和块2重叠)

为什么要重叠?因为重要信息可能正好被切断,重叠一部分可以降低信息丢失的风险。

优点:实现简单,可预测

缺点:完全不管语义,可能把一句话切成两半

适用场景:快速验证、对效果要求不高的场景

方式二:递归分块(推荐)

递归分块是目前用得最多的方式。

核心思路:按照一组分隔符的优先级来切割文本。先尝试用最高优先级的分隔符(如双换行符),如果切出来的块还是太大,再用下一级分隔符继续切。

递归分块是主流

递归分块(Recursive Character Text Splitter)是工业界最广泛使用的分块方式,LangChain、Spring AI Alibaba、Dify等主流框架都将其作为默认或推荐方案。它能在尊重文档自然结构的前提下,保证每块不超过指定大小,是大多数场景的首选。

常见的分隔符优先级:

  1. \n\n —— 双换行,通常表示段落分隔
  2. \n —— 单换行
  3. —— 句子结束标点
  4. —— 句内停顿
  5. —— 空格

示例

原文:
第一段内容。第一段继续。

第二段内容。第二段很长很长很长很长很长很长很长...

第三段内容。

设置:chunk_size=50

处理过程:
1. 先按"\n\n"切,得到三段
2. 第二段超过50字,按"。"继续切
3. 切出来的小块不超过50字,完成

为什么叫"递归"

private void splitText(String text, int separatorIndex, List<String> chunks) {
// 如果文本已经足够小,直接加入结果
if (text.length() <= chunkSize) {
chunks.add(text);
return;
}

// 用当前分隔符切分
String separator = separators[separatorIndex];
String[] splits = text.split(separator);

for (String split : splits) {
if (split.length() > chunkSize) {
// 还是太大,递归用下一个分隔符继续切
splitText(split, separatorIndex + 1, chunks);
} else {
chunks.add(split);
}
}
}

就是这个递归调用,让它能够灵活处理各种长度的文本。

优点:尊重文档结构,切出来的块语义相对完整

缺点:对于没有明显分隔符的文本效果一般

适用场景:大部分通用场景

方式三:基于文档结构切块

针对有明确结构的文档(如Markdown、Word),可以根据其内部结构来切。

Markdown文档

按标题层级切割。一级标题下的内容是一块,二级标题下的内容是一块。

# 第一章
这是第一章的内容...

## 1.1 小节
这是小节的内容...

## 1.2 另一小节
这是另一小节的内容...

切割结果:

  • 块1:第一章 + 第一章的内容
  • 块2:1.1 小节 + 小节的内容
  • 块3:1.2 另一小节 + 另一小节的内容

Word文档

按照Word的大纲级别(标题1、标题2...)来切割。

优点:完美保留文档结构,语义最完整

缺点:只适用于有明确结构的文档

适用场景:技术文档、产品手册、规范文档

方式四:语义分块

前面的方式都是基于"规则"的——数字符、看分隔符、看标题。

语义分块不一样,它是基于"意思"的——当话题转换的时候,就切一刀。

原理

  1. 把文本按句子切开
  2. 计算相邻句子之间的语义相似度
  3. 相似度突然下降的地方,说明话题变了,这里切一刀
句子1:打印机支持双面打印。(相似度0.9)
句子2:双面打印可以节省纸张。(相似度0.3)← 话题转换
句子3:打印机的网络设置在控制面板中。
句子4:点击"网络设置"进入配置界面。

在句子2和句子3之间,话题从"双面打印"变成了"网络设置",相似度骤降,这里就是切分点。

优点:切出来的块语义最连贯

缺点:计算成本高(需要算相似度),效果依赖模型质量

适用场景:对效果要求高、能接受一定延迟的场景

方式五:大模型智能切块

最"智能"的方式——直接让大模型来切。

你把文档内容发给大模型,告诉它:"请帮我把这段文本按照主题进行切分,每个切分块应该是一个完整的语义单元。"

大模型会理解内容,然后给出切分结果。

示例Prompt

请将以下文档内容按照主题进行智能切分。
要求:
1. 每个切分块是一个完整的语义单元
2. 相关的内容放在同一块
3. 输出JSON数组格式

文档内容:
{document_content}

优点:效果最好,能理解复杂的语义边界

缺点:成本高(要调用大模型),速度慢,不适合大规模处理

适用场景:少量重要文档、对效果要求极高的场景

各平台怎么做的

看看主流的AI平台是怎么实现分块的,可以给我们一些参考。

阿里云百炼

阿里百炼分块方式

百炼支持6种切分方式:

  • 智能切分(推荐)
  • 按长度切分
  • 按符号切分
  • 按页切分
  • 按标题切分
  • 按正则切分

Dify

Dify主要支持两种:

  • 通用分块(其实就是递归分块)
  • 父子分块(后面会专门讲)

总结

这些平台的共同点是:递归分块是主流

核心参数就三个:

  • 分段标识符(用什么符号切)
  • 分段最大长度(每块最大多少字)
  • 分段重叠度(相邻块重叠多少字)

分块参数调优

最后聊聊怎么找到最佳的分块参数。

没有银弹

实话说,分块参数没有"最优值",只有"适合你场景的值"。

不同的文档类型、不同的问答场景,最佳参数都不一样。

调优方法

方法一:凭经验设初始值

  • chunk_size:500-1000字
  • overlap:chunk_size的10%-20%

方法二:准备测试集

收集一些典型的问答对,作为测试集。

方法三:调参验证

for chunk_size in [300, 500, 800, 1000]:
for overlap in [50, 100, 150]:
- 用这组参数切块
- 跑一遍测试集
- 记录准确率

选准确率最高的参数组合

方法四:观察bad case

上线后持续观察bad case(回答不好的问题),分析是不是切块的问题:

  • 检索到的内容和问题相关度低 → 可能切块太大,噪音多
  • 检索到的内容不完整 → 可能切块太小,语义断裂
  • 检索到的内容重复 → 可能overlap设太大
调优诊断指南

通过bad case的表现反推参数问题:检索内容相关度低通常是切块太大(噪音多),检索内容语义断裂通常是切块太小,检索结果重复通常是overlap过大。这三个方向基本覆盖了80%的分块调优场景。

小结

这篇文章讲了文档分块的核心理论:

  1. 切块大小的权衡:太大不精准,太小不完整,要找平衡点
  2. 五种切块方式:固定大小、递归、基于结构、语义、大模型智能切块
  3. 递归分块是主流:大部分场景用递归分块就够了
  4. 参数需要调优:没有银弹,要根据具体场景调试

下一篇用ChunkViz可视化工具来直观感受不同分块策略的效果差异。

🎁优惠