一、面试题目
请详细介绍 RAG 中文本切块(Chunking)四大核心策略:固定长度切块、语义切块、递归字符切块、切块重叠设计,分别原理、优缺点、适用场景、工程选型建议。
二、知识储备
1. 基础概念
Chunking 文本切块 把长文档切分成小块,用于向量化入库、检索召回,是 RAG 影响召回精度最重要的前置环节 。切块核心矛盾:块太小丢上下文、块太大语义混杂。
2. 四种切块策略详解
(一)固定长度切块(Fixed-size Chunking)
原理
按固定字符 / Token 长度一刀切,比如每 512 Token 切一块,顺序截取,不考虑句子、段落、语义边界。
优点
- 实现最简单、速度最快、成本最低
- 适合海量文档批量处理
- 可控性强、容易做容量预估
缺点
- 容易截断句子、割裂语义
- 一块内可能包含多个无关主题
- 边界破碎严重,检索精度低
适用场景
- 结构化不强、口语化、网文、杂乱文档
- 低成本快速搭建 RAG、原型验证
- 对召回精度要求不高的场景
工程要点
常用:512 / 1024 Token 固定长度。
(二)递归字符切块(Recursive Character Text Splitter)
原理
分层递归切割 ,按优先级从大到小分隔符依次切:段落换行 \n\n → 单行换行 \n → 句号。 → 逗号, → 空格 → 单个字符 `先按大分隔符切,若仍超长度,再用下一级更细分隔符递归切。
优点
- 尽量保留段落、句子完整性
- 不强行截断语义边界
- 效果远好于固定长度,实现简单
- 工业级默认首选切块方案
缺点
- 仍不理解深层语义,只靠符号规则
- 特殊无标点文档效果一般
适用场景
- 技术文档、PDF、知识库、手册、书籍
- 绝大多数企业 RAG 落地首选
- 有标准标点、段落结构的正式文本
(三)语义切块(Semantic Chunking)
原理
- 先按短句 / 小片段粗切
- 对每个片段做 Embedding 向量化
- 计算相邻片段语义相似度
- 相似度低于阈值 → 判定语义边界,从此处切分
优点
- 按语义主题自然切分,不割裂上下文
- 每块内部主题单一、纯度高
- RAG 召回准确率最高
缺点
- 要多次调用 Embedding,成本高、速度慢
- 阈值调优依赖经验
- 长文档处理耗时明显增加
适用场景
- 高精度知识库、法律合同、医疗文档、专业论文
- 对问答精准度要求极高、允许一定成本开销
- 主题边界清晰的正式文稿
(四)切块重叠设计(Chunk Overlap / 滑动重叠)
原理
相邻两个 Chunk 之间保留一段重复文本,例如块长 1024,重叠 128。后一块开头复用前一块末尾一段内容,形成上下文平滑过渡。
核心作用
- 解决关键信息落在两块边界被拆分、检索漏召
- 保持跨块上下文连续性
- 提升问答连贯性,避免断章取义
优点
- 极低成本大幅提升召回效果
- 兼容所有切块策略(固定 / 递归 / 语义都可加重叠)
缺点
- 增加少量 Token、向量数量变多、存储略增
工程经验值
- 块长 512 → 重叠 64~128
- 块长 1024 → 重叠 128~256
- 重叠不宜过大:超过块长 20% 收益边际递减
适用场景
所有生产级 RAG 都必须开启重叠,是标配设计。
3. 四种策略横向对比总结
|----------|---------------|------------|----------|-----------------|
| 切块方式 | 核心原理 | 精度 | 速度成本 | 工程推荐 |
| 固定长度 | 按固定字符硬切 | 低 | 最快、最低 | 原型、杂乱文本 |
| 递归切块 | 按换行 / 句号分层递归切 | 中高 | 快、低成本 | 企业 RAG 默认首选 |
| 语义切块 | 向量相似度识别语义边界 | 最高 | 慢、高成本 | 高精度专业场景 |
| 重叠设计 | 块间保留重复上下文 | 提升 5%~15% | 微增成本 | 全部场景必开 |
4. 工程落地最佳选型(面试直接背)
- 通用企业 RAG:递归字符切块 + 固定重叠(10%~20%)
- 高精度专业场景:语义切块 + 适度重叠
- 快速原型 / 杂乱网文:固定长度切块 + 小重叠
- 任何生产环境 :不允许无重叠切块,必须加 Overlap
5. 常见踩坑
- 只固定长度不做递归:语义割裂严重、问答乱答
- 不开重叠:边界关键信息丢失、召回漏缺
- 语义切块阈值乱设:块过碎或块过大
- 切块统一尺寸不做自适应:长句被硬截断
三、破局之道
面试高阶总结:文本切块不是简单切字符串,而是在语义完整性、块大小、速度成本、检索召回率之间做平衡。固定长度最简单但精度最差;递归切块靠分隔符分层切割,是工业级性价比首选;语义切块通过向量相似度识别主题边界,精度最高但成本高;重叠设计是所有生产级 RAG 的标配,用极小成本解决边界信息丢失问题。
落地最优组合:递归切块 + 合理重叠做通用基线,高精度业务再叠加语义切块。
四、极简代码实现
Python
python
# 1. 固定长度切块 + 重叠
def fixedChunk(text, chunkSize=512, overlap=128):
chunks = []
start = 0
textLen = len(text)
while start < textLen:
end = start + chunkSize
chunks.append(text[start:end])
# 滑动步进 = 块长 - 重叠
start += chunkSize - overlap
return chunks
# 2. 递归字符切块 + 重叠
def recursiveChunk(text, chunkSize=1024, overlap=128):
# 切割分隔符优先级
separators = ["\n\n", "\n", "。", ",", " "]
def splitRecurse(content, sepIdx):
# 不能再分 或 已经小于块长,直接返回
if sepIdx >= len(separators) or len(content) <= chunkSize:
return [content]
# 按当前分隔符切割
parts = content.split(separators[sepIdx])
res = []
for p in parts:
res.extend(splitRecurse(p, sepIdx + 1))
return res
# 先递归切分
rawChunks = splitRecurse(text, 0)
# 加相邻重叠
final = []
for i in range(len(rawChunks)):
if i > 0:
# 前一块末尾 + 当前块
merge = rawChunks[i-1][-overlap:] + rawChunks[i]
final.append(merge)
else:
final.append(rawChunks[i])
return final
JavaScript
javascript
// 1. 固定长度切块 + 重叠
function fixedChunk(text, chunkSize = 512, overlap = 128) {
const chunks = [];
let start = 0;
const textLen = text.length;
while (start < textLen) {
const end = start + chunkSize;
chunks.push(text.slice(start, end));
start += chunkSize - overlap;
}
return chunks;
}
// 2. 递归字符切块 + 重叠
function recursiveChunk(text, chunkSize = 1024, overlap = 128) {
const separators = ["\n\n", "\n", "。", ",", " "];
function splitRecurse(content, sepIdx) {
if (sepIdx >= separators.length || content.length <= chunkSize) {
return [content];
}
const parts = content.split(separators[sepIdx]);
let res = [];
for (let p of parts) {
res = res.concat(splitRecurse(p, sepIdx + 1));
}
return res;
}
// 递归原始切块
const rawChunks = splitRecurse(text, 0);
// 叠加重叠
const final = [];
for (let i = 0; i < rawChunks.length; i++) {
if (i > 0) {
const merge = rawChunks[i-1].slice(-overlap) + rawChunks[i];
final.push(merge);
} else {
final.push(rawChunks[i]);
}
}
return final;
}