Chunk 分块策略决定检索质量
作者:程序员马丁
Ragent AI —— 从 0 到 1 纯手工打造企业级 Agentic RAG,拒绝 Demo 玩具!AI 时代,助你拿个offer。
为什么不能把整篇文档直接丢给大模型?
假设你在一家电商公司做开发,老板让你搞一个智能客服系统。公司有一份 200 页的《客服知识库》,涵盖退货政策、物流规则、会员权益、售后流程等内容。用户问“买了 7 天的商品还能退吗?”,系统要能从知识库里找到答案并回复。
最直觉的做法——把整份知识库的文本一股脑塞给大模型,然后让它回答。
听起来很合理,但实际跑起来你会撞上两堵墙。
1. 大模型的上下文窗口限制
大模型在处理文本时,有一个上下文窗口的概念。你可以把它理解成大模型的工作台 ——它一次能摊开看的纸张数量是有限的。
拿目前主流的模型来说,上下文窗口大概在 128k 到 1M 个 token 之间(token 是什么后面会解释,这里你先理解成大约等于一个汉字或单个英文)。128K token 听起来很多,但一份 200 页的知识库文档,纯文本量轻松超过 30 万字,远远超出窗口上限。
直接后果:文本塞不进去,或者会触发输入长度限制/截断/费用显著增加。
从 128K token 到 1M token,跨度还不到一年,进步确实非常快。但接下来是否还需要继续把上下文做得更大,仍有待观察:从成本、延迟到实际效果来看,token 并不是越多越好。
就算未来模型的窗口越来越大,能装下整份文档了,还有第二个更本质的问题。
2. 检索精度的问题——大海捞针
假设你有一个上下文窗口无限大的模型,把整份知识库都塞进去了。用户问“生鲜商品支持七天无理由退货吗?”,模型需要从 30 万字里找到相关的那几段话。
这就像你去图书馆找一句话,但图书管理员把整个图书馆的书全摊在你面前说自己找。信息太多,噪音太大,模型很容易走神——要么找不到重点,要么把不相关的内容混进回答里。
即使上下文做到 1M,很多在线客服场景仍会偏向 RAG,因为全量长提示会显著拉高成本与响应延迟,且吞吐更差。
在 RAG 的架构中,做法不是把所有文本都丢给模型,而是先检索出最相关的几段文本,只把这几段喂给模型。这样模型拿到的上下文精准、干净,回答质量自然就上去了。
但问题来了:要做检索,你得先有可以被检索的单元。一整份知识库是没法作为检索单元的——粒度太粗了。你需要把它切成一段一段的小块,每一块聚焦一个相对完整的知识点。
这就是分块(Chunking)要干的事。
分块到底在干什么
1. 分块在 RAG 流程中的位置
上一篇我们用 Apache Tika 从 PDF、Word 等文件中提取出了纯文本。但纯文本只是原材料,还不能直接用于检索。分块是紧接着文本提取之后的一步,它把长文本切成适合检索的小段。
整个数据准备阶段的流程是这样的:

分块之后的下一步是向量化——把每个文本块转成一组数字(向量),方便计算机做相似度检索。向量化的原理和实现下一篇单独讲,这里你只需要知道:分块的质量直接决定了后续检索的质量。块切得好,检索就准;块切得烂,后面怎么优化都救不回来。
2. 几个关键参数:chunkSize、overlap
在动手切之前,有两个参数你必须搞清楚:chunkSize(块大小)和 overlap(重叠量)。
2.1 chunkSize 怎么理解
chunkSize 就是每个块的长度上限。比如你设 chunkSize = 200,意思是每个块最多包含 200 个字符(或 200 个 token,取决于你用什么单位,后面会说)。
chunkSize 设多大合适?这没有标准答案,但有一个基本的权衡:
- 块太大(比如 2000 字):每个块包含的信息多,但检索时容易混入不相关的内容,精度下降。就像用户问退货政策,结果返回了一整章包含退货、换货、维修的内容,模型还得自己从里面挑。
- 块太小(比如 50 字):每个块很精准,但可能把一个完整的意思切断了,上下文丢失。就像把一条退货规则从中间劈开,前半句和后半句单独看都不知道在说什么。
一般来说,200 到 1000 个字符是比较常见的范围,具体取决于你的文档类型和检索需求。
2.2 overlap 是什么,为什么需要它
overlap(重叠)是指相邻两个块之间共享的文本长度。
打个比方:你在看一本小说,每次只能记住一页的内容。如果你严格按页翻,第 1 页看完翻到第 2 页,那第 1 页最后一句话和第 2 页第一句话之间的联系就断了。但如果你每次翻页时,把上一页最后几行重新看一遍,这几行 就是重叠的部分,它帮你保持了上下文的连贯性。
用一个具体的例子来看。假设知识库里有这样一段退货政策:
自签收之日起 7 天内,商品未经使用且不影响二次销售的,消费者可申请七天无理由退货。生鲜食品、定制商品、贴身衣物等特殊品类不适用此规则,具体以商品详情页标注为准。
如果 chunkSize = 40,不加 overlap,切出来可能是:
- 块 1:
自签收之日起 7 天内,商品未经使用且不影响二次销售的,消费者可申请七天 - 块 2:
无理由退货。生鲜食品、定制商品、贴身衣物等特殊品类不适用此规则,具体 - 块 3:
以商品详情页标注为准。
注意看,“七天无理由退货”这个关键词被切成了两半,分别落在块 1 和块 2 里。用户搜“七天无理由退货”,两个块都匹配不完整。
2.2.1 不加 overlap 会丢失什么
上面的例子已经很直观了——不加 overlap,相邻块的边界处一定会丢失上下文。如果用户恰好问的问题涉及到边界处的内容,检索就可能找不到完整的答案。
加上 overlap = 15 之后,切出来变成:
- 块 1:
自签收之日起 7 天内,商品未经使用且不影响二次销售的,消费者可申请七天 - 块 2:
消费者可申请七天无理由退货。生鲜食品、定制商品、贴身衣物等特殊品类不适 - 块 3:
特殊品类不适用此规则,具体以商品详情页标注为准。
块 2 的开头和块 1 的结尾有重叠,“ 七天无理由退货”在块 2 里是完整的了。
当然,overlap 也不是越大越好。overlap 太大意味着大量重复文本,存储和计算成本都会上升。一般经验是 overlap 设为 chunkSize 的 10%~25%。
2.3 用什么单位:字符 vs token
你可能注意到了,前面说 chunkSize 的时候,有时说字符,有时说 token。这两个东西不一样,有必要区分一下。
字符(Character)就是你肉眼看到的每一个符号。“你好”是 2 个字符,"Hello"是 5 个字符,空格和标点也各算 1 个字符。
Token 是大模型实际处理文本的最小单位。大模型不是一个字一个字地读文本的,它会先把文本切成一个个 token。对于英文,一个常见单词通常是 1 个 token,长一点的单词可能被拆成 2-3 个 token。对于中文,一个汉字通常是 1-2 个 token。
举个例子:
| 文本 | 字符数 | 大约 token 数 |
|---|---|---|
| 七天无理由退货 | 7 | 7-10 |
| Hello World | 11 | 2 |
| 退货政策 | 4 | 4-6 |
为什么要关心这个?因为大模型的上下文窗口是按 token 算的,不是按字符算的。如果你用字符数来设 chunkSize,实际消耗的 token 数可能比你预期的多(尤其是中文场景)。
不过在入门阶段,用字符数来设 chunkSize 完全够用。等你对 token 有了更深的理解,再考虑切换到基于 token 的分块也不迟。
主流分块策略详解
下面我们用同一段示例文本,来演示几种主流的分块策略。先把示例文本贴出来,后面反复会用到:
一、退货政策
自签收之日起 7 天内,商品未经使用且不影响二次销售的,消费者可申请七天无理由退货。生鲜食品、定制商品、贴身衣物等特殊品类不适用此规则,具体以商品详情页标注为准。退货运费由消费者承担,如因商品质量问题退货,运费由商家承担。
二、换货政策
自签收之日起 15 天内,商品存在质量问题的,消费者可申请免费换货。换货时需提供订单编号、商品照片及问题描述。换货商品将在审核通过后 3 个工作日内寄出,届时会通过短信通知物流单号。
三、会员权益
普通会员享受 9.5 折优惠,每月可 领取 2 张满 200 减 20 的优惠券。黄金会员享受 9 折优惠,每月可领取 4 张满 200 减 30 的优惠券,且退换货享受免运费服务。钻石会员享受 8.5 折优惠,每月可领取 6 张满 200 减 50 的优惠券,退换货免运费,并享有专属客服通道。
四、物流配送
默认使用顺丰快递,偏远地区使用邮政 EMS。订单金额满 99 元包邮,未满 99 元收取 8 元运费。大件商品(家具、家电等)使用德邦物流,配送费根据商品重量和收货地址单独计算。预计配送时间:一线城市 1-2 天,二三线城市 2-4 天,偏远地区 5-7 天。
五、售后服务
所有商品享受 1 年质保服务。质保期内出现非人为损坏的质量问题,可免费维修或更换。超出质保期的维修服务按成本价收取配件费和人工费。如需售后服务,请拨打客服热线 400-XXX-XXXX 或在 APP 内提交售后工单。
这段文本大约 600 个字符,包含 5 个章节,每个章节讲一个独立的业务规则。接下来看看不同的分块策略会把它切成什么样。