
👨💻程序员三明治 :个人主页
🔥 个人专栏 : 《设计模式精解》 《重学数据结构》
《AI探索日志》 《从0带你学深度强化学习》
🤞先做到 再看见!
目录
-
- 为什么不能把整份知识库直接交给大模型?
-
- [1. 上下文窗口限制](#1. 上下文窗口限制)
- [2. 检索精度问题:信息越多,噪声也越多](#2. 检索精度问题:信息越多,噪声也越多)
- 分块到底在做什么?
-
- [1. 分块在 RAG 流程中的位置](#1. 分块在 RAG 流程中的位置)
- [2. 两个关键参数:chunk_size 与 overlap](#2. 两个关键参数:chunk_size 与 overlap)
-
- [2.1 如何理解 chunk_size?](#2.1 如何理解 chunk_size?)
- [2.2 overlap 是什么,为什么需要它?](#2.2 overlap 是什么,为什么需要它?)
- [2.3 用字符还是 token 作为单位?](#2.3 用字符还是 token 作为单位?)
- 主流分块策略详解
- [1. 固定大小分块(Fixed Size Chunking)](#1. 固定大小分块(Fixed Size Chunking))
-
- [1.1 原理](#1.1 原理)
- [1.2 Java 代码实现](#1.2 Java 代码实现)
- [1.3 优缺点](#1.3 优缺点)
- [2. 重叠分块(Overlapping Chunking)](#2. 重叠分块(Overlapping Chunking))
-
- [2.1 原理](#2.1 原理)
- [2.2 Java 代码实现](#2.2 Java 代码实现)
- [2.3 优缺点](#2.3 优缺点)
- [3. 递归分块(Recursive Chunking)](#3. 递归分块(Recursive Chunking))
-
- [3.1 原理](#3.1 原理)
- [3.2 优缺点](#3.2 优缺点)
- [4. 语义分块(Semantic Chunking)](#4. 语义分块(Semantic Chunking))
-
- [4.1 原理](#4.1 原理)
- [4.2 Embedding 语义分块与 LLM 辅助分块对比](#4.2 Embedding 语义分块与 LLM 辅助分块对比)
- [4.3 优缺点](#4.3 优缺点)
- [5. 混合分块(Hybrid Chunking)](#5. 混合分块(Hybrid Chunking))
-
- [5.1 原理](#5.1 原理)
- [方式一:递归分块 + 语义分块](#方式一:递归分块 + 语义分块)
- 方式二:按文档类型路由
- 方式三:分块后处理
- [5.2 优缺点](#5.2 优缺点)
- 使用可视化工具对比分块效果
-
- [CharacterTextSplitter 示例观察](#CharacterTextSplitter 示例观察)
- [RecursiveCharacterTextSplitter 示例观察](#RecursiveCharacterTextSplitter 示例观察)
- 分块策略怎么选?
-
- [1. 不同文档类型的推荐策略](#1. 不同文档类型的推荐策略)
- [2. chunk_size 与 overlap 的经验参考](#2. chunk_size 与 overlap 的经验参考)
- 企业级实践中的注意事项
- 文末总结
本文面向正在建设 RAG 知识库问答系统的开发者,围绕"为什么需要分块、如何设置 chunk_size 与 overlap、常见分块策略如何选择"展开说明。示例场景统一替换为在线教育平台的课程预约与教务服务知识库;技术链路、参数权衡和性能优化思路保持不变。
为什么不能把整份知识库直接交给大模型?
假设一个在线教育平台正在建设智能教务助手。平台内部有一份 200 页左右的《课程服务知识库》,内容覆盖课程预约规则、调课与取消政策、课时权益、班主任服务、直播课说明、发票与售后流程等。学员提出"预约的课程开课前多久可以取消?"这类问题时,系统需要从知识库中定位相关条款,并生成准确回答。
最直接的做法似乎是:把整份知识库文本一次性放进大模型上下文,然后让模型回答。
这个思路在小规模示例中看起来可行,但在真实系统中通常会遇到两个核心问题。
1. 上下文窗口限制
大模型处理文本时存在上下文窗口限制。可以把它理解为模型一次能够"看到"的工作区大小:输入文本、检索内容、系统提示词、用户问题和模型输出都会占用这个窗口。
以当前主流模型为例,上下文窗口通常从 128k token 到 1M token 不等。token 可以粗略理解为模型处理文本时的基本单位,中文场景下常常接近一个汉字或一个词片段。128k token 听起来很多,但一份 200 页的课程服务知识库,纯文本量很容易超过几十万字。如果还包含表格、FAQ、政策说明和历史版本内容,直接塞入模型不仅可能超出长度限制,也会带来显著的成本和延迟。
因此,直接输入整篇文档的后果通常包括:
- 文本无法完整输入,触发长度限制或被截断;
- 单次请求成本明显增加;
- 响应延迟变长;
- 并发吞吐能力下降。
即使未来模型上下文窗口继续扩大,这个问题也不会完全消失。上下文越长,模型需要处理的信息越多,实际业务系统仍然要在成本、延迟、稳定性和回答质量之间做取舍。
2. 检索精度问题:信息越多,噪声也越多
即便假设模型拥有足够大的上下文窗口,直接提供整份知识库仍然会带来检索精度问题。
例如,学员问:"体验课结束后还能改约正式课吗?"如果系统把几十万字的课程规则、合同条款、教师排班、售后流程都交给模型,模型需要在大量信息中找出最相关的几段。上下文越长,噪声越多,模型越容易把不相关条款混入回答,或者忽略真正关键的限制条件。
这也是 RAG 架构仍然重要的原因。RAG 的核心做法不是把所有文本直接交给模型,而是先检索出与问题最相关的几个文本片段,再把这些片段作为上下文提供给模型。这样模型拿到的是更干净、更聚焦的证据,回答质量和稳定性都会更好。
但要做检索,首先需要把文档拆成可以被检索的单元。整份知识库作为一个检索单元粒度过粗,既不利于召回,也不利于排序。系统需要把长文本切成若干相对完整的小段,每个小段围绕一个知识点或业务规则展开。
这就是分块(Chunking)的作用。
分块到底在做什么?
1. 分块在 RAG 流程中的位置
在数据准备阶段,通常会先使用 Apache Tika 等工具从 PDF、Word、HTML 等文件中提取纯文本。但纯文本还不能直接进入向量数据库,原因是文本太长、结构复杂,而且不同段落之间的语义边界不一定清晰。
一个典型的数据准备流程如下:
latex
原始文档
↓
文本抽取(如 Apache Tika)
↓
文本清洗与结构修复
↓
分块(Chunking)
↓
向量化(Embedding)
↓
写入向量数据库
↓
检索增强生成(RAG)
分块之后,下一步通常是向量化。系统会把每个文本块转换为向量,后续根据用户问题与文本块向量之间的相似度进行检索。
因此,分块质量会直接影响检索质量。块切得合理,检索结果通常更聚焦;块切得过大,会引入噪声;块切得过小,又可能丢失上下文。分块一旦质量较差,后续即使调整向量模型、召回数量或重排策略,也很难完全弥补。
2. 两个关键参数:chunk_size 与 overlap
在设计分块策略之前,需要先理解两个核心参数:
chunk_size:每个文本块的长度上限;overlap:相邻两个文本块之间保留的重叠长度。
为了完成命名风格脱敏,下文代码示例将原本常见的 camelCase 写法改为 snake_case,例如 chunkSize 改为 chunk_size。虽然 Java 社区通常使用 camelCase,但这里的命名调整不影响示例逻辑。
2.1 如何理解 chunk_size?
chunk_size 表示每个块的最大长度。比如设置 chunk_size = 200,意味着每个块最多包含 200 个字符,或者最多包含 200 个 token,具体取决于系统采用的计量单位。
chunk_size 没有固定标准,但需要理解它背后的权衡:
| 设置情况 | 影响 |
|---|---|
| 块太大,例如 2000 字 | 单个块包含更多信息,但检索结果容易混入不相关内容,精度下降。例如学员只问"开课前多久能取消预约",结果召回整章"预约、调课、退款、发票"说明,模型还要再次从中筛选。 |
| 块太小,例如 50 字 | 单个块更精准,但容易把完整规则切断。例如"开课前 24 小时可免费取消"被拆成两段,单独看任何一段都不完整。 |
在许多中文知识库问答场景中,chunk_size 可以先从 200 到 1000 个字符之间试起。课程预约、退课规则、FAQ 这类问答型知识,通常适合偏小的块;课程体系介绍、长篇说明、教学方案摘要等场景,则可以适当增大块大小。
2.2 overlap 是什么,为什么需要它?
overlap 指相邻两个块共享的文本长度。它的作用是缓解边界切割带来的语义断裂。
例如,课程服务知识库中有如下规则:
latex
直播课程开课前 24 小时以上,学员可以在学习中心自助取消预约,系统会自动返还对应课时。开课前 24 小时以内取消,需联系班主任人工处理;如教师已完成课前准备,该课时可能不予返还,具体以课程协议为准。
如果 chunk_size = 40 且不设置 overlap,可能切成:
latex
块 1:直播课程开课前 24 小时以上,学员可以在学习中心自助取消
块 2:预约,系统会自动返还对应课时。开课前 24 小时以内取消,需联系
块 3:班主任人工处理;如教师已完成课前准备,该课时可能不予返还
块 4:,具体以课程协议为准。
此时,"取消预约""返还课时"等关键含义被切散。用户搜索"开课前多久取消预约可以返还课时"时,任何一个块都可能不够完整。
如果设置 overlap = 15,相邻块之间保留一部分重复内容,切分效果会更好:
latex
块 1:直播课程开课前 24 小时以上,学员可以在学习中心自助取消
块 2:心自助取消预约,系统会自动返还对应课时。开课前 24 小时以内
块 3:前 24 小时以内取消,需联系班主任人工处理;如教师已完成
块 4:师已完成课前准备,该课时可能不予返还,具体以课程协议为准。
通过重叠,边界处的关键信息更容易在某个块中完整出现。
但 overlap 并不是越大越好。重叠越大,重复文本越多,向量化成本、存储成本和检索计算成本都会增加。常见经验是将 overlap 设置为 chunk_size 的 10% 到 25%。
2.3 用字符还是 token 作为单位?
chunk_size 可以按字符计算,也可以按 token 计算。两者并不等价。
字符是人眼看到的符号数量。例如,"预约课程"是 4 个字符,Hello World 是 11 个字符,包括空格。
token 是模型处理文本时的基本单位。英文中,一个常见单词通常接近 1 个 token,较长单词可能拆成多个 token;中文中,一个汉字可能对应 1 个或多个 token,具体取决于模型的分词器。
| 文本 | 字符数 | 大约 token 数 |
|---|---|---|
| 取消课程预约 | 6 | 6 ~ 10 |
| Hello World | 11 | 2 |
| 课时返还规则 | 6 | 6 ~ 10 |
大模型的上下文窗口按 token 计算,因此基于字符的 chunk_size 只是近似控制。对于入门阶段或简单系统,按字符分块通常足够;当系统对成本、上下文长度和多语言兼容性要求更高时,更推荐使用基于 token 的分块方式。
主流分块策略详解
下面使用同一段在线教育课程服务知识库示例,说明几类常见分块策略。
latex
一、课程预约规则
学员可在学习中心预约直播课程。普通课程最早可提前 14 天预约,最晚需在开课前 2 小时完成预约。热门班课名额有限,系统会按照预约时间顺序锁定席位。预约成功后,学员会收到短信、站内信和学习中心提醒。
二、取消与改约规则
直播课程开课前 24 小时以上,学员可以自助取消预约,系统会自动返还对应课时。开课前 24 小时以内取消,需联系班主任人工处理;如教师已完成课前准备,该课时可能不予返还。因平台故障或教师原因导致课程无法正常进行的,课时将原路返还。
三、学员权益
基础学员每月可预约 4 次答疑课。进阶学员每月可预约 8 次答疑课,并享受作业优先批改服务。尊享学员每月可预约 12 次答疑课,享受专属学习顾问、阶段测评报告和学习路径调整建议。
四、上课通知与直播安排
课程默认使用平台直播教室。开课前 30 分钟,系统会自动生成直播入口,并通过站内信和短信提醒学员。若课程需要使用第三方会议工具,班主任会在开课前至少 2 小时发送会议链接和注意事项。
五、教务支持与发票服务
学员可在学习中心提交教务工单,咨询课程安排、课时记录、发票开具和学习资料下载等问题。工作日 9:00 至 21:00 提交的工单通常会在 4 小时内处理;非工作时间提交的工单会在下一个工作日优先处理。
这段文本包含 5 个相对独立的章节,每个章节对应一个业务规则。下面对不同分块策略进行说明。
1. 固定大小分块(Fixed Size Chunking)

1.1 原理
固定大小分块是最直接的方式:不理解文本结构,也不识别段落或句子边界,只按固定字符数切割。
假设 chunk_size = 100、overlap = 0,系统会这样切:
latex
块 1:从第 1 个字符开始,取 100 个字符
块 2:从第 101 个字符开始,再取 100 个字符
块 3:从第 201 个字符开始,再取 100 个字符
......
这种方式实现简单、性能稳定,但容易把一句话、一个条款甚至一个关键词从中间切断。对于课程预约知识库这类有明确章节和规则边界的文本,固定大小分块通常只能作为兜底方案。
1.2 Java 代码实现
java
import java.util.ArrayList;
import java.util.List;
public class fixed_size_chunker {
/**
* 固定大小分块:按字符数量进行硬切分。
*/
public static List<String> split_text(String source_text, int chunk_size) {
List<String> chunk_list = new ArrayList<>();
int start_index = 0;
while (start_index < source_text.length()) {
int end_index = Math.min(start_index + chunk_size, source_text.length());
chunk_list.add(source_text.substring(start_index, end_index));
start_index = end_index;
}
return chunk_list;
}
public static void main(String[] arguments) {
String source_text = "直播课程开课前 24 小时以上,学员可以在学习中心自助取消预约,"
+ "系统会自动返还对应课时。开课前 24 小时以内取消,需联系班主任人工处理;"
+ "如教师已完成课前准备,该课时可能不予返还,具体以课程协议为准。";
List<String> chunk_list = split_text(source_text, 40);
for (int index = 0; index < chunk_list.size(); index++) {
System.out.println("=== 块 " + (index + 1) + " ===");
System.out.println(chunk_list.get(index));
System.out.println();
}
}
}
这段代码会严格按照 40 个字符切分。切割位置不考虑句子边界,因此部分块的开头或结尾可能读起来不完整。
1.3 优缺点
| 维度 | 说明 |
|---|---|
| 优点 | 实现简单,性能好,不依赖 NLP 处理或额外模型。 |
| 缺点 | 完全忽略文本结构,容易切断句子、段落和规则条件,导致语义不完整。 |
| 适合 | 日志、纯数据文本、格式混乱但无需精细语义边界的内容;也可作为其他策略失败时的兜底方案。 |
| 不适合 | 课程规则、协议条款、操作手册、FAQ 等结构清晰且语义边界重要的知识库。 |
2. 重叠分块(Overlapping Chunking)

2.1 原理
重叠分块是在固定大小分块基础上的改进。核心思想是:相邻块之间保留一段重复文本,降低边界切割造成的信息丢失。
假设 chunk_size = 100、overlap = 25:
latex
块 1:从第 1 个字符开始,取 100 个字符
块 2:从第 76 个字符开始,取 100 个字符
块 3:从第 151 个字符开始,取 100 个字符
......
每次向前移动的步长不是 100,而是 chunk_size - overlap,也就是 75。这样相邻块之间会共享 25 个字符。
与固定大小分块相比,重叠分块仍然不理解语义,但可以显著缓解边界断裂问题。
2.2 Java 代码实现
java
import java.util.ArrayList;
import java.util.List;
public class overlapping_chunker {
/**
* 重叠分块:在固定大小分块基础上,为相邻块保留重叠区域。
*/
public static List<String> split_text(String source_text, int chunk_size, int overlap) {
if (overlap >= chunk_size) {
throw new IllegalArgumentException("overlap 必须小于 chunk_size");
}
List<String> chunk_list = new ArrayList<>();
int step_size = chunk_size - overlap;
int start_index = 0;
while (start_index < source_text.length()) {
int end_index = Math.min(start_index + chunk_size, source_text.length());
chunk_list.add(source_text.substring(start_index, end_index));
start_index += step_size;
}
return chunk_list;
}
public static void main(String[] arguments) {
String source_text = "直播课程开课前 24 小时以上,学员可以在学习中心自助取消预约,"
+ "系统会自动返还对应课时。开课前 24 小时以内取消,需联系班主任人工处理;"
+ "如教师已完成课前准备,该课时可能不予返还,具体以课程协议为准。";
List<String> chunk_list = split_text(source_text, 40, 10);
for (int index = 0; index < chunk_list.size(); index++) {
System.out.println("=== 块 " + (index + 1) + " ===");
System.out.println(chunk_list.get(index));
System.out.println();
}
}
}
这段代码的关键是 start_index += step_size。当 step_size = chunk_size - overlap 时,下一块会从上一块结束位置之前开始,从而形成重叠。
2.3 优缺点
| 维度 | 说明 |
|---|---|
| 优点 | 实现简单,能够有效缓解边界处的语义断裂。 |
| 缺点 | 仍然不识别文本结构;重叠区域会带来重复存储和额外向量化成本。 |
| 适合 | 通用知识库的入门方案,尤其适合结构不稳定、段落边界不可靠的文本。 |
| 不适合 | 对条款完整性要求极高的内容,例如课程合同、合规声明或收费协议。 |
3. 递归分块(Recursive Chunking)

3.1 原理
递归分块是实际 RAG 项目中非常常用的策略。它的核心思想是:先尝试使用更大的语义边界切分,如果切出来的块仍然超过 chunk_size,再使用更细的边界继续切分。
常见的分隔符优先级如下:
latex
["\n\n", "\n", "。", ",", " ", ""]
切分过程可以概括为:
latex
先按空行切分章节
↓
章节仍然过长,则按换行切
↓
片段仍然过长,则按句号切
↓
句子仍然过长,则按逗号或空格切
↓
最后才按字符兜底切分
这种方式的优势在于,它尽量尊重文档结构。能按章节切,就不按句子切;能按句子切,就不按字符硬切。
以课程预约知识库为例,如果 chunk_size = 200,递归分块通常会先按章节之间的空行切分。"取消与改约规则"这一节如果没有超过 200 字,就会作为一个完整块保留;如果超过上限,再继续按句号拆分。
3.2 优缺点
| 维度 | 说明 |
|---|---|
| 优点 | 兼顾语义完整性和块大小控制,是多数文本型 RAG 系统的稳妥默认选择。 |
| 缺点 | 依赖文本中存在合理分隔符;分隔符列表需要根据语言和文档格式调整。 |
| 适合 | 课程知识库、操作手册、帮助中心、教学说明、政策类文档等结构清晰的文本。 |
| 不适合 | 代码文件、复杂表格、扫描 OCR 结果、条款跨页严重的 PDF 等需要专门解析的内容。 |
4. 语义分块(Semantic Chunking)

4.1 原理
固定大小分块、重叠分块和递归分块都属于规则驱动方法。它们主要依赖长度、标点和段落结构,并不真正理解文本内容。
语义分块则使用 Embedding 模型判断文本含义,在语义发生明显变化的位置切分。典型流程如下:
latex
1. 将长文本切成句子或短段
2. 为每个句子生成 Embedding 向量
3. 计算相邻句子之间的向量相似度
4. 当相似度低于阈值时,判断为主题切换点
5. 在主题切换点进行分块
例如,在课程服务知识库中,"取消与改约规则"内部的几句话都围绕课程取消、课时返还和人工处理展开,相邻句子的向量相似度通常较高。当文本从"取消与改约规则"切换到"学员权益"时,话题发生明显变化,相似度会下降,适合作为分块边界。
语义分块的好处是文本块内部主题更加内聚,不容易把多个不相关主题混在一个块里。但它需要额外调用 Embedding 模型,或者使用大模型辅助判断切分位置,因此成本和延迟都更高。
4.2 Embedding 语义分块与 LLM 辅助分块对比
| 维度 | Embedding 语义分块 | LLM 辅助分块 |
|---|---|---|
| 原理 | 计算相邻句子或段落的向量相似度。 | 让大模型直接理解文本并判断切分位置。 |
| 分块质量 | 依赖 Embedding 模型质量和阈值设置。 | 通常更能处理复杂语境、隐含主题和跨段关系。 |
| 速度 | 较快,适合批量处理。 | 较慢,通常以秒级计。 |
| 成本 | 较低。 | 较高。 |
| 适用场景 | 大批量文档处理、通用知识库优化。 | 高价值文档、复杂条款、需要人工级别边界判断的内容。 |
4.3 优缺点
| 维度 | 说明 |
|---|---|
| 优点 | 切分依据更接近真实语义,文本块主题内聚性更强,检索精度通常更高。 |
| 缺点 | 需要额外模型调用;阈值需要调参;对模型质量和文本预处理质量有依赖。 |
| 适合 | 合同条款、收费协议、课程服务协议、合规文档、高价值知识库。 |
| 不适合 | 文档量特别大且对处理延迟敏感的场景;或者文本结构已经非常清晰、递归分块足够有效的场景。 |
5. 混合分块(Hybrid Chunking)

5.1 原理
真实项目中,单一策略往往无法覆盖所有文档。在线教育平台的知识库可能同时包含课程说明、FAQ、直播操作指南、合同条款、发票规则、教师排班说明和客服工单模板。不同内容适合不同切分方式。
混合分块的思路是根据文档类型、文本结构和业务用途选择不同策略,必要时进行后处理。
常见组合方式包括:
方式一:递归分块 + 语义分块
先用递归分块按章节和段落粗切,再对过长或主题复杂的块使用语义分块细切。这样可以兼顾速度和分块质量。
latex
长文档
↓
按章节/段落递归粗切
↓
识别过长或主题复杂的片段
↓
使用 Embedding 或 LLM 进行语义细切
↓
输出最终 chunk
方式二:按文档类型路由
根据文档类型选择分块器:
| 文档类型 | 推荐策略 |
|---|---|
| 课程帮助中心 | 递归分块 |
| FAQ 问答对 | 按问答对切分 |
| 课程服务协议 | 语义分块 |
| 直播故障日志 | 按行切分或固定大小分块 |
| HTML 帮助页面 | 先清洗标签,再递归分块 |
| OCR 扫描文本 | 清洗修复后使用重叠分块或语义分块 |
方式三:分块后处理
先用基础策略生成初始块,再做一轮质量修正:
- 合并过短块;
- 拆分过长块;
- 为每个块补充元数据,例如课程类型、章节标题、文档来源、版本号、生效日期;
- 对相邻块做语义检查,避免一个规则被拆散;
- 对 FAQ 保持问答成对,不让问题和答案分离。
以在线教育平台为例,一个可落地的混合方案可以是:
| 内容类型 | 策略 |
|---|---|
| 课程预约、取消、改约等规则正文 | 递归分块,优先按章节和条款切分。 |
| FAQ 问答 | 每个 Q&A 作为一个块,必要时补充所属课程和适用范围。 |
| 课程详情页 | 提取结构化字段,例如价格、课时、适用年级;描述文本再用重叠分块。 |
| 课程协议和退款条款 | 语义分块或人工复核后的混合分块。 |
| 教务工单模板 | 按模板类型或业务流程节点切分。 |
5.2 优缺点
| 维度 | 说明 |
|---|---|
| 优点 | 灵活度高,可针对不同内容选择最合适的策略,整体检索效果通常最好。 |
| 缺点 | 实现复杂度较高,需要维护多套分块逻辑、路由规则和质量评估机制。 |
| 适合 | 企业级 RAG 系统、多类型知识库、对回答准确率和可解释性要求较高的场景。 |
| 不适合 | 简单 demo、POC 或文档量很小的试验项目。 |
使用可视化工具对比分块效果
仅靠文字描述不够直观。实践中可以使用 ChunkViz 等可视化工具,观察不同分块策略对同一段文本的切割效果。
推荐做几组对比实验:
| 实验 | 策略 | chunk_size | overlap | 观察重点 |
|---|---|---|---|---|
| 实验 1 | CharacterTextSplitter | 100 | 0 | 观察边界是否频繁切在句子中间。 |
| 实验 2 | CharacterTextSplitter | 100 | 20 | 观察重叠区域是否缓解边界断裂。 |
| 实验 3 | RecursiveCharacterTextSplitter | 100 | 0 | 对比固定大小分块,观察递归策略是否更倾向于在段落或句子边界切分。 |
| 实验 4 | RecursiveCharacterTextSplitter | 200 | 0 | 增大块大小,观察块数量和语义完整性的变化。 |
在课程规则类文本中,通常可以观察到:
- 固定大小分块容易切断规则条件;
- 加入 overlap 后,边界信息更容易被保留;
- 递归分块更倾向于保留章节或句子完整性;
- 当
chunk_size过大时,召回内容可能包含多个主题; - 当
chunk_size过小时,规则上下文可能不完整。
CharacterTextSplitter 示例观察
配置如下:
latex
Chunk Size: 100
Chunk Overlap: 20
这种配置可以缓解部分边界问题,但仍然不理解课程规则本身。如果一个取消政策包含多个条件,例如"开课前 24 小时以上""开课前 24 小时以内""因平台原因取消",固定字符分割仍可能把条件和处理结果拆开。
RecursiveCharacterTextSplitter 示例观察
配置如下:
latex
Chunk Size: 200
Chunk Overlap: 0
对于标题清晰、段落稳定的课程知识库,递归字符分割通常能得到较好的结果。它会尽量按章节、段落或句子边界切分,减少语义断裂。
但当一个章节内部包含多个互相依赖的业务条件时,递归分块仍可能不够精细。例如"取消与改约规则"中同时包含自助取消、人工处理、平台责任和课时返还,简单按句子切分可能会把条件和例外说明分开。此时可以考虑增加 overlap,或者对关键章节使用语义分块与人工复核。
分块策略怎么选?
1. 不同文档类型的推荐策略
| 文档类型 | 推荐策略 | 理由 |
|---|---|---|
| 课程帮助中心 / 教务知识库 | 递归分块 | 通常具有清晰标题、段落和条款结构,递归策略能利用这些边界。 |
| FAQ / 问答对 | 按问答对切分,必要时结合递归分块 | 每个 Q&A 是天然知识单元,不应把问题和答案拆开。 |
| 课程协议 / 退款条款 | 语义分块 | 条款边界和例外条件需要精确识别,规则分块容易切错。 |
| 直播故障日志 | 固定大小分块或按行切分 | 日志通常按记录组织,结构简单。 |
| 代码文件 | 专用代码分块器,按类、函数或方法切分 | 通用文本分块不理解代码结构。 |
| HTML 帮助页面 | 先清洗 HTML 标签,再递归分块 | 标签、导航栏和脚注会干扰分块,需要先处理。 |
| OCR 扫描文本 | 清洗修复后使用重叠分块或语义分块 | OCR 文本分隔符不可靠,先做去噪和结构修复更稳妥。 |
| 多类型企业知识库 | 混合分块 | 不同内容采用不同策略,整体效果更稳定。 |
2. chunk_size 与 overlap 的经验参考
以下参数不是标准答案,而是常见起点:
| 参数 | 推荐范围 | 说明 |
|---|---|---|
chunk_size |
200 ~ 1000 字符 | 问答型知识偏小,例如 200 ~ 500;摘要或长说明偏大,例如 500 ~ 1000。 |
overlap |
chunk_size 的 10% ~ 25% |
例如 chunk_size = 500 时,overlap 可从 50 ~ 125 之间试起。 |
一个实用调参路径:
latex
初始配置:chunk_size = 500,overlap = 50
↓
准备 20 ~ 50 个真实用户问题
↓
观察 Top-K 检索结果
↓
如果召回内容噪声太多:减小 chunk_size
↓
如果答案上下文经常断裂:增大 overlap 或改用递归/语义分块
↓
如果不同文档表现差异大:引入混合分块和文档类型路由

企业级实践中的注意事项
真实项目里,分块效果不好往往不只是 chunk_size 没调对,也可能是上游文本抽取已经产生了噪声。尤其是 PDF、扫描件和复杂网页,常见问题包括:
- 页眉、页脚、目录、页码混入正文;
- 表格被拆成错位字段;
- 换行错误导致一句话被切成多段;
- 课程名称、价格、适用人群等结构化字段丢失;
- 历史版本规则与当前规则混在一起;
- 免责声明、版权信息、导航菜单干扰正文。
因此,稳定的流程不应是"抽取完成后立刻分块",而应是:
latex
文本抽取
↓
去噪与结构修复
↓
版本识别与元数据补充
↓
分块
↓
向量化
↓
质量评估
↓
必要时人工二次编排
对于中小规模但高价值的课程知识库,还可以在基础分块之后加入人工二次编排。做法是先用递归分块或语义分块生成初稿,再由运营、教务或知识库维护人员检查关键块,对不完整、不准确或过长的块进行合并、拆分和补充。
这种方式能够解决单纯调参难以解决的问题。例如:
- 某条退款规则需要和例外说明合并;
- 某个 FAQ 的答案依赖前置适用范围,需要补充元数据;
- 某段课程协议跨页,需要人工恢复完整条款;
- 某个知识块需要标记生效日期,避免召回过期规则。
对于 Dify、RAGFlow 等标准 RAG 平台,基础分块能力通常可以覆盖大多数入门场景。但在企业级系统中,单一分块策略容易出现"顾此失彼":
chunk_size变大,完整上下文更容易召回,但噪声可能增加;chunk_size变小,检索更精确,但规则更容易被切断;overlap增大,边界信息保留更好,但存储与向量化成本增加;- 只依赖递归分块,结构清晰的文档效果好,但复杂条款仍可能切错;
- 只依赖语义分块,质量可能更高,但批量处理成本和延迟更高。
因此,更稳妥的工程方案通常是:文本清洗打底,递归分块作为默认策略,关键文档引入语义分块,重要知识块允许人工校正,并通过真实查询集持续评估效果。

文末总结
分块是 RAG 数据准备阶段的关键步骤。文本抽取之后,系统不能直接把长文档整体用于检索,而需要将其拆成大小合适、语义相对完整的文本块,再进行向量化和相似度检索。
常见分块策略各有定位:
| 策略 | 核心特点 |
|---|---|
| 固定大小分块 | 最简单,性能好,但容易切断语义。 |
| 重叠分块 | 在固定分块基础上保留重叠区域,缓解边界断裂。 |
| 递归分块 | 逐层使用段落、句子、标点等边界,是多数文本知识库的默认选择。 |
| 语义分块 | 基于 Embedding 或 LLM 判断主题变化,质量高但成本更高。 |
| 混合分块 | 针对不同文档类型组合多种策略,适合复杂企业知识库。 |
参数上,可以从 chunk_size = 500、overlap = 50 开始,用真实用户问题评估检索效果。如果结果噪声多,适当减小 chunk_size;如果上下文断裂,适当增大 overlap 或切换到更能保留结构的策略。
分块之后,每个文本块仍然只是人类可读的文本。要让计算机进行相似度检索,还需要将文本块转换为向量表示,这一步就是 Embedding。分块质量越高,后续向量检索、重排和生成回答的上限也越高。
如果我的内容对你有帮助,请辛苦动动您的手指为我点赞,评论,收藏。感谢大家!!
