文档切片策略选择

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

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

但怎么切有讲究:

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

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

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

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

切大了切小了,都是问题

切太大会怎样

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

问题一:检索不精准

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

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

问题二:超出上下文限制

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

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

切太小会怎样

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

问题一:语义不完整

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

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

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

问题二:上下文丢失

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

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

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

所以到底切多大

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

但有一

  • \n —— 单换行
  • —— 句子结束标点

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

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

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

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

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

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

Markdown文档

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

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

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

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

切割结果:

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

Word文档

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

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

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

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

方式四:语义分块

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

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

原理

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

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

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

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

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

方式五:大模型智能切块

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

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

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

示例Prompt

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

文档内容:
{document_content}

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

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

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

各平台怎么做的

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

阿里云百炼

7-Blog/AI技术/RAG详细解析/assets/FrFqzLkwCtMW5yg5QIRFMXQg9eKB-37db6087

百炼支持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%的分块调优场景。

小结

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

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

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