Day 17:Chunking 切分策略
学习目标
昨天我们把各种格式的文档解析成了干净的文本,还提取了结构信息和元数据。今天要做的事情是把这些长文本切成适当大小的片段——这就是 Chunking(切分)。
切分听起来简单,实际上它是 RAG 系统中影响最终效果最显著的环节之一。切得太大,检索不精准,一个 Chunk 里塞了几千字,模型很难定位到具体答案。切得太小,上下文丢失,一个只有两句话的 Chunk 缺少背景信息,模型看不懂它说的是什么。切分的粒度和方式,直接决定了检索的精度和答案的质量。
今天的目标是理解为什么需要切分、不同的切分策略各自的优劣、Overlap 的作用和代价、以及如何评估切分质量。学完之后,你应该能够针对不同类型的文档,选择合适的切分策略,并解释为什么这样选择。
核心概念
一、为什么要切块
要理解切分的必要性,先得搞清楚为什么不能把整篇文档直接塞给模型。
向量检索需要短文本。 向量检索的原理是计算问题向量和文档片段向量之间的相似度。如果文档片段太长,向量是对整段文本的”平均表示”,会模糊掉具体细节。你问”退货的 SLA 是多少小时”,如果文档片段是一整页的内容,里面提到了退货流程、退货条件、退货SLA、退款方式等各种信息,向量表示会偏向整段文本的主题(退货相关),而不是具体的 SLA 数字。检索可能找得到这个片段,但片段太长,模型需要从中提取答案,效果打折。
上下文窗口有限。 虽然模型的上下文窗口越来越大,但把整篇 50 页的文档塞进 Prompt 是不现实的。实际操作中,检索到的片段会拼接到 Prompt 中,如果每个片段太长,能放的片段数量就少了,覆盖面变窄。
语义粒度要对齐。 用户的问题通常指向一个具体的知识点,比如一个数字、一个流程、一个定义。理想的 Chunk 大小应该和”一个完整的知识点”大致对齐。这样检索到的 Chunk 就是答案所在的最小上下文,既不缺少必要背景,又不包含太多无关信息。
存储和检索效率。 短文本的向量计算更快、存储更省、检索更高效。虽然这不是主要考虑因素,但在大规模知识库(百万级 Chunk)场景下,效率差异会很明显。
但切分也有代价。 切分打破了文档的原始结构。原本有前后逻辑关系的段落被切成了独立的片段,片段之间的连贯性丢失了。切分做得不好,可能导致一个完整的论述被腰斩,前半段在 Chunk A,后半段在 Chunk B。检索时可能只检索到 Chunk A,答案就不完整。
所以切分的核心矛盾是:粒度要细(为了检索精准),但上下文要保留(为了理解完整)。所有的切分策略都是在平衡这两个需求。
二、固定长度切分
固定长度切分是最简单的策略:按照固定的字符数或 Token 数切割文本。
怎么做。 设定一个 Chunk Size(比如 500 字符),从文本开头开始,每 500 字符切一段。最后一段如果不足 500 字符,单独作为一段保留。
优点:
- 实现极其简单,几行逻辑就能搞定
- 每个 Chunk 的大小一致,便于后续处理(向量维度一致、Prompt 拼接可预测)
- 不依赖文档结构,适用于任何文本
缺点:
- 完全不考虑语义边界,可能在句子中间、段落中间甚至单词中间切断
- 丢失文档结构信息,标题、段落、章节的含义被忽略
- 对于结构化文档(有明确标题层级的),效果明显不如按结构切分
适用场景: 没有结构信息的纯文本(比如 OCR 输出的无格式文本)、需要快速搭建原型的场景。
改进做法。 纯粹的固定长度切分太粗暴了。通常会做一个改进:按固定长度切,但在最近的句子边界或段落边界处切割。比如目标是 500 字符,找到 500 字符附近最近的句号或换行符,在那里切断。这样至少保证每个 Chunk 是完整的句子或段落集合。
三、按段落切分
按段落切分是以段落为最小单位进行切分。
怎么做。 先按段落分割文本(以换行符或缩进为标志),然后将一个或多个连续段落组合成一个 Chunk,直到达到目标大小。
优点:
- 保留了段落的完整性,不会在段落中间切断
- 段落通常是表达一个完整意思的最小单元,切分结果语义相对完整
- 实现也比较简单
缺点:
- 段落长度差异很大。有的段落只有一句话,有的段落有十几句话。短的段落可能导致 Chunk 过小,长的段落可能导致 Chunk 过大
- 段落之间的逻辑关系可能被忽略。一个论证可能跨越多个段落,切分后逻辑链断裂
- 有些文档的段落划分本身就不合理(用换行代替段落分隔),导致切分结果混乱
适用场景: 段落划分清晰的文档,比如散文式的技术文档、FAQ 类文档。
改进做法。 按段落切分后,检查每个 Chunk 的大小。太小的 Chunk 和相邻段落合并,太大的 Chunk 再按句子拆分。这样在保留段落边界的同时,控制了 Chunk 大小的一致性。
四、按标题切分
按标题切分是利用文档的标题层级结构作为切分边界。
怎么做。 根据提取到的标题信息,以某个层级的标题为边界切割文本。比如以二级标题为边界,每个二级标题下的内容(包括三级标题和正文)作为一个 Chunk。
优点:
- 语义最完整。同一个标题下的内容通常围绕同一个主题,切分后的 Chunk 有明确的主题聚焦
- 保留了文档的原始组织结构
- 每个 Chunk 可以携带标题信息作为上下文(比如”这是’退货政策’章节的内容”),增强检索效果
缺点:
- 完全依赖文档有良好的标题结构。如果文档没有使用标题,或者标题层级混乱,这个策略就无法使用
- 标题下的内容长度差异可能很大。有的章节只有几行,有的章节有几页。短章节的 Chunk 信息量不足,长章节的 Chunk 又太大
- 需要昨天文档解析阶段正确提取了标题信息
适用场景: 结构良好的长文档,比如技术手册、产品文档、规章制度。
改进做法。 按标题切分后,对过大的 Chunk(比如超过目标大小的 2 倍)做二次切分(按段落或句子),对过小的 Chunk(比如不到目标大小的一半)和相邻章节合并。在合并和拆分时,保留标题信息作为上下文。
这是工程实践中效果最好的切分策略之一。 因为它充分利用了文档作者已经做好的内容组织工作。文档作者写标题的时候,就是在做”内容分组”——把相关的内容放在同一个标题下。RAG 系统利用这个分组,天然就能获得语义更完整的 Chunk。
五、语义切分
语义切分是最”智能”的切分策略,通过分析文本的语义变化来决定切分边界。
核心思路。 文本中相邻的句子如果讨论的是同一个话题,语义上是连贯的;如果话题发生了转换,语义上会出现”断点”。语义切分就是找到这些断点,在断点处切分。
怎么做。 常见的做法是:将文本按句子分割,对每个句子生成 Embedding 向量,计算相邻句子向量之间的相似度。如果相似度突然下降(说明话题转换),就在那里切分。
更高级的做法是用大模型来判断:给模型一段文本,让它判断在哪里做分割最合适。这种方式效果最好,但成本也最高。
优点:
- 切分边界最贴近语义变化,Chunk 内部的话题一致性最好
- 不依赖文档格式或结构标记,适用于任何文本
- 在处理非结构化文本(没有明确段落划分、没有标题的文本)时,效果优于其他策略
缺点:
- 计算成本高,需要对每个句子做 Embedding 或调用模型
- 效果依赖 Embedding 模型的质量,模型不好可能导致切分边界不准
- 实现复杂度高,调参难度大(相似度阈值怎么设?多大的下降才算”断点”?)
- 处理速度慢,不适合大规模文档的实时处理
适用场景: 对切分质量要求极高的场景、没有明确结构的文本、有足够计算资源的场景。
六、Overlap
Overlap(重叠)是切分中的一个重要机制。它的含义是:相邻的 Chunk 之间保留一定长度的重复内容。
为什么需要 Overlap。 假设一段文字描述了一个完整的过程:“第一步,提交申请。第二步,经理审批。第三步,财务确认。第四步,完成退款。“如果没有 Overlap,按照固定长度切分可能在”第三步”和”第四步”之间切断。Chunk A 包含前三步,Chunk B 包含第四步。如果用户问”退款完成的最后一步是什么”,检索可能只匹配到 Chunk B,但 Chunk B 缺少前面步骤的上下文。
有了 Overlap,Chunk B 也会包含 Chunk A 的尾部内容(比如”第三步,财务确认”),这样 Chunk B 的上下文更完整。
Overlap 的大小选择。 通常设为 Chunk Size 的 10%-20%。比如 Chunk Size 是 500 字符,Overlap 可以设为 50-100 字符。Overlap 太小起不到保留上下文的作用,太大则浪费存储和检索资源(大量重复内容被重复索引)。
Overlap 的代价。
- 存储空间增加。同样的文档,有 Overlap 的切分会比没有 Overlap 的切分产生更多的 Chunk。
- 检索结果可能重复。同一个内容出现在两个 Chunk 中,检索时两个 Chunk 都被返回,需要去重。
- 总索引体积增大,检索计算量增加。
什么时候需要 Overlap。 几乎总是需要的。特别是当切分策略比较粗糙(比如固定长度切分)时,Overlap 是弥补上下文丢失的关键手段。即使使用按标题切分这种语义友好的策略,章节之间的过渡段也值得用 Overlap 来保留。
七、Chunk Metadata
每个 Chunk 除了文本内容本身,还应该携带元数据。这些元数据不是存在向量数据库中参与检索的向量部分,而是作为附属信息存储,在检索结果返回时提供上下文。
核心元数据字段:
- chunk_id:唯一标识符
- source_document:来源文档的文件名或 ID
- section_title:所属章节的标题
- section_path:完整的章节路径(如”第 3 章 > 3.2 节 > 3.2.1 小节”)
- page_number:页码(如果可获取)
- chunk_index:在文档中的第几个 Chunk(从 0 开始)
- content_type:内容类型(正文/表格/列表/代码块)
- char_count:字符数
- created_at:创建时间
为什么元数据重要。
检索到 Chunk 后,用户需要知道这个信息来自哪里。元数据让回答可以附带”该信息来自《XX 文档》第 12 页’退货政策’章节”。没有元数据的检索结果就像一篇文章中的引用没有出处——信息本身可能是对的,但无法验证。
元数据还支持过滤检索。比如用户只想在”2024 年更新的文档”中搜索,可以通过元数据的时间字段来过滤,而不需要在所有文档中搜索后再筛选。
八、Chunk 质量评估
切分完成后,怎么知道切得好不好?这是很多人忽略的环节。
评估维度:
完整性。 每个 Chunk 是否包含完整的语义?有没有被腰斩的句子或段落?如果一个 Chunk 以”这个流程的第三步是”开头,以”完成整个闭环。“结尾,但缺少了中间的关键步骤,这就是完整性问题。
一致性。 Chunk 的大小是否相对一致?有没有特别大(5000 字符)或特别小(50 字符)的 Chunk?极端大小的 Chunk 通常意味着切分策略需要调整。
独立性。 每个 Chunk 能否独立理解?还是必须结合前后的 Chunk 才能理解?理想的 Chunk 应该像一个独立的”知识卡片”,拿到就能理解它在说什么。
覆盖性。 切分后的所有 Chunk 是否完整覆盖了原文档的内容?有没有内容被遗漏?切分过程中因为边界处理不当而丢失几句话的情况并不少见。
冗余度。 相邻 Chunk 之间的 Overlap 是否合理?有没有过多的内容重复?冗余度过高会浪费存储和检索资源。
评估方法:
- 自动检查。 编写检查脚本,统计 Chunk 的大小分布、检测空 Chunk、检测过小或过大的 Chunk、计算 Overlap 比例。
- 抽样审查。 随机抽取 20-30 个 Chunk,人工阅读,判断语义是否完整、能否独立理解。
- 检索测试。 准备一批测试问题,用当前的 Chunk 进行检索,看检索结果是否包含正确的 Chunk。如果检索不到,可能是切分有问题。
概念关系图
Chunk 切分策略对比
=========================================================
策略 语义完整性 实现复杂度 适用文档
-----------------------------------------------------------------
固定长度切分 低 低 无结构文本
按段落切分 中 低 段落清晰的文档
按标题切分 高 中 有标题结构的文档
语义切分 最高 高 任何文本
Chunk 大小与效果的关系
=========================================================
Chunk 太小 (< 100 字符) Chunk 合适 (200-1000 字符) Chunk 太大 (> 2000 字符)
------------------------- ------------------------- -------------------------
+ 检索精准度高 + 检索精准度与上下文平衡 + 检索精准度低
- 缺少上下文 + 语义相对完整 - 向量表示模糊
- 信息碎片化 + 存储效率合理 - Prompt 占用过多
- 检索结果数量多 - 需要调参找到最佳大小 - 模型处理困难
- 需要更多拼接 - 不同文档需要不同参数
切分策略选择决策树
=========================================================
文档有标题结构吗?
|
+-- 是 --> 按标题切分 + 过大章节二次切分
|
+-- 否 --> 文档有明确的段落划分吗?
|
+-- 是 --> 按段落切分 + 大小控制
|
+-- 否 --> 对切分质量要求高吗?
|
+-- 是 --> 语义切分
|
+-- 否 --> 固定长度切分 + Overlap
Chunk 在 RAG 管线中的位置
=========================================================
[干净文本 + 结构信息] (Day 16 的输出)
|
v
[选择切分策略]
|
v
[执行切分]
|
+-- [Chunk 1] -- text + metadata
+-- [Chunk 2] -- text + metadata
+-- [Chunk 3] -- text + metadata
+-- ...
|
v
[质量评估]
|
+-- 大小分布检查
+-- 完整性抽查
+-- 检索测试
|
v
[合格 Chunks] -----> 送入 Embedding 环节 (Day 18)
实战分析
任务一:实现 3 种切分策略
针对同一份文档(建议用一份有标题结构的技术手册),分别实现三种切分策略,对比效果差异。
固定长度切分。 设定 Chunk Size 为 500 字符,Overlap 为 100 字符。观察切分结果:有多少 Chunk 是在句子中间断开的?有多少 Chunk 缺少上下文?
按段落切分。 以段落为最小单位,将连续段落组合到目标大小。观察切分结果:段落合并是否合理?有没有”硬凑”在一起的不相关段落?
按标题切分。 以二级标题为边界,每个二级标题下的内容作为一个 Chunk。观察切分结果:有没有特别大的章节需要二次切分?有没有特别小的章节需要合并?
任务二:对比切分效果
把三种策略的切分结果放在一起对比。重点关注以下指标:
Chunk 数量。 同样一篇文档,三种策略各产生了多少个 Chunk?数量差异大吗?
Chunk 大小分布。 统计每种策略下 Chunk 的最大值、最小值、平均值、中位数。分布越均匀通常越好(但也有例外,比如按标题切分,如果某个章节天然就很长,强行均匀切分反而不好)。
语义完整性。 随机抽查每种策略的 10 个 Chunk,评估它们能否独立理解。按 1-5 分打分。
检索效果。 准备 10 个测试问题,分别用三种切分结果做检索(这一步需要 Day 18 的 Embedding,今天可以先设计测试问题和预期正确的 Chunk,记录下来明天用)。
任务三:给每个 Chunk 加 Metadata
选择效果最好的一种切分策略,为每个 Chunk 添加完整的元数据。
确保每个 Chunk 都有以下信息:
- 唯一 ID(可以用文档名 + 序号生成)
- 来源文档名
- 所属章节标题(如果有)
- 页码(如果有)
- Chunk 在文档中的序号
- 字符数
- 内容类型
这些元数据在后续检索时会被用到。设计元数据的时候要考虑向量数据库的存储格式——大多数向量数据库支持 JSON 格式的元数据存储。
任务四:设计 Chunk 评估表
设计一个评估表,用于定期评估切分效果。评估表应该包含:
自动指标:
- Chunk 总数
- 大小分布统计(最大、最小、均值、中位数、标准差)
- 过小 Chunk 数量(< 100 字符)和占比
- 过大 Chunk 数量(> 2000 字符)和占比
- Overlap 比例
人工评估:
- 抽样数量和抽样方法
- 每个 Chunk 的语义完整性评分(1-5)
- 每个 Chunk 的独立性评分(1-5)
- 断句问题记录(在哪里断开、是否合理)
- 信息丢失记录(有哪些内容被切分导致丢失)
当日产物说明
产物一:《Chunking 策略对比》
这是一份对比分析文档,记录三种切分策略在相同文档上的效果差异。
应该包含:
- 测试文档的描述(类型、长度、结构特征)
- 三种策略的参数设置
- 对比表格(Chunk 数量、大小分布、语义完整性评分、检索效果)
- 结论:哪种策略最适合这种类型的文档?为什么?
质量标准: 数据驱动,不是凭感觉说”A 策略比 B 策略好”。有具体的数字和评分支撑结论。
产物二:《文档切分脚本》
针对效果最好的策略,设计一个通用的切分方案。
应该包含:
- 输入格式定义(接收什么样的文本和结构信息)
- 切分逻辑说明(核心算法的步骤)
- 参数说明(Chunk Size、Overlap、标题层级等参数的含义和推荐值)
- 输出格式定义(每个 Chunk 的文本和元数据结构)
- 边界情况处理(空文档、超大文档、只有一行的文档)
质量标准: 方案足够具体,另一个人可以据此实现切分逻辑。参数建议有理有据,不是拍脑袋定的。
产物三:《Chunk 质量评估表》
这是一份可复用的评估模板。
应该包含:
- 自动评估指标的完整列表和计算方法
- 人工评估的评分标准(每个维度的 1-5 分分别对应什么水平)
- 评估流程说明(抽多少、怎么抽、谁来评)
- 问题记录模板(发现切分问题时的记录格式)
质量标准: 模板可以直接用于后续项目的切分评估。评分标准清晰,不同人使用同一模板对同一切分结果打分,差异不超过 1 分。
常见误区与避坑
误区一:Chunk Size 越小检索越精准
这个推理看起来成立但忽略了上下文的问题。Chunk 太小,比如只有一个句子,检索确实更精准地匹配到了那个句子,但模型生成答案时缺少上下文,可能误解那个句子的含义。
比如一个只有”需要在 24 小时内完成”的 Chunk,脱离了上下文,你不知道是什么需要在 24 小时内完成——是退货处理?是工单响应?还是数据备份?模型要么猜测(可能猜错),要么回答不了。
Chunk Size 的选择要在检索精准度和上下文完整性之间找平衡点。通常 200-1000 字符是一个不错的起点,具体值需要根据文档类型和问题类型来调。
误区二:一套参数打天下
不同类型的文档需要不同的切分参数。一份产品规格表(每个字段都很短,信息密度高)和一份行业分析报告(段落长,论述深入)显然不能用同一套参数。
实际项目中,应该根据文档类型分组,每组使用不同的切分策略和参数。至少应该区分:技术文档、制度文件、FAQ、数据表格,这四类文档的切分方式应该各不相同。
误区三:切完就不管了
切分不是一次性工作。文档更新了需要重新切分,切分策略优化了需要重新切分,甚至发现检索效果不好的时候也需要回头检查切分是否有问题。
切分是 RAG 系统中持续迭代的环节。建立一个”切分 → 评估 → 优化 → 重新切分”的闭环,定期评估切分效果,根据评估结果优化策略。
误区四:忽略 Chunk 的上下文信息
一个 Chunk 的文本内容如果以”根据上述规定”开头,检索到这个 Chunk 的人(或模型)根本不知道”上述规定”是什么。这就是上下文丢失的问题。
解决方案是在每个 Chunk 中加入上下文信息。比如在每个 Chunk 的开头加上它所属的章节标题,甚至加上文档标题。这样即使 Chunk 本身被单独检索出来,也能知道它的上下文。比如”【退货政策 > 处理时效】根据上述规定,退款将在 3 个工作日内完成”——有了前面的章节标题,“上述规定”的指向就清晰多了。
误区五:Overlap 越大越好
Overlap 的作用是保留上下文,但过大的 Overlap 会带来问题:
- 存储和索引体积膨胀,同样的内容被重复存储和索引多次
- 检索结果中大量重复,检索”退货 SLA”可能返回三个几乎相同的 Chunk,浪费了检索结果的位置
- 每个 Chunk 的独特性降低,向量表示趋于雷同
Overlap 设为 Chunk Size 的 10%-20% 通常就够了。超过 30% 就要考虑是不是切分策略本身有问题,才需要靠 Overlap 来弥补。
延伸思考
Chunking 与检索质量的因果关系
切分质量直接决定检索质量,这一点怎么强调都不过分。很多团队花大量时间优化检索算法、调 Embedding 模型、加 Rerank,却忽略了最基础的切分问题。
一个简单的例子:假设文档中有”退货流程如下:1. 客户提交退货申请;2. 客服审核申请;3. 仓库确认收货;4. 财务处理退款。退款将在 3 个工作日内完成。“如果切分在”3. 仓库确认收货”和”4. 财务处理退款”之间断开,而用户问”退货后多久能收到退款”,检索可能只找到包含后半段的 Chunk,但这个 Chunk 缺少”退货”这个关键词的上下文(因为”退货”在前半段),导致检索不到。
这不是检索算法的问题,而是切分的问题。在花时间优化检索之前,先确保切分是合理的。
面向不同问题类型的切分
用户的问题有不同的类型:事实型(“退款要几天”)、流程型(“退货流程是什么”)、对比型(“产品和 B 产品有什么区别”)、原因型(“为什么退货被拒绝了”)。
不同类型的问题对 Chunk 的要求不同。事实型问题需要精准的 Chunk(小粒度),流程型问题需要完整的上下文(大粒度),对比型问题需要包含对比对象的 Chunk。
理论上,同一个文档可以按多种粒度切分,建立多级索引。检索时根据问题类型选择不同粒度的索引。这在学术研究中已经有探索,但在工程实践中还不太成熟。
Chunking 的未来方向
自适应切分。 不是用固定规则切分,而是让模型根据内容自动决定切分边界。模型理解了文本的语义后,在语义转折处切分。这和语义切分的思路类似,但更强调”自适应”——不需要预设参数,模型自己判断。
层级索引。 同时维护不同粒度的 Chunk(句子级、段落级、章节级),检索时先在粗粒度上定位,再在细粒度上精确匹配。这类似于”先找章节再找段落”的人类阅读习惯。
这些方向在实际项目中的应用还处于早期阶段,但值得了解和关注。
自测问题
-
为什么不能把整篇文档作为一个整体进行检索?列举至少三个原因。
-
固定长度切分的最大缺点是什么?如何改进?
-
为什么按标题切分通常是最好的策略?它在什么情况下不适用?
-
语义切分的原理是什么?它的高成本体现在哪里?
-
Overlap 的作用是什么?为什么说”Overlap 越大越好”是错误的?
-
设计一个 Chunk 的元数据结构,包含至少 7 个字段,说明每个字段在 RAG 系统中的作用。
-
Chunk 质量评估的五个维度是什么?分别怎么衡量?
-
如果一份文档既有标题又有段落,你会选择什么切分策略?说明理由。
-
举一个具体例子,说明切分不当如何导致检索失败。
-
为什么说”切分质量直接决定检索质量”?这个论点的逻辑链条是什么?
关键词
- Chunking:文本切分,将长文档切割成适当大小的片段,是 RAG 管线中承上启下的关键环节
- Chunk Size:切分粒度,每个文本片段的目标大小,通常以字符数或 Token 数衡量
- Overlap:重叠,相邻 Chunk 之间保留的重复内容长度,用于保持上下文连贯性
- 固定长度切分:按照固定字符数切分文本的策略,最简单但语义完整性最差
- 按段落切分:以段落为最小单位进行切分,保留段落完整性
- 按标题切分:利用文档标题层级作为切分边界的策略,语义完整性最好
- 语义切分:通过分析文本语义变化来决定切分边界的策略,最智能但成本最高
- Chunk Metadata:每个文本片段携带的元数据,包括来源、位置、类型等信息
- 语义完整性:评估 Chunk 是否包含完整语义的维度,是切分质量的核心指标
- 切分评估:对切分结果进行质量检查的过程,包括自动指标和人工审查