RecursiveCharacterTextSplitter 深度详解
一、核心定位
RecursiveCharacterTextSplitter(递归字符文本分割器)是 LangChain 最通用、生产最常用的分块工具,专门解决简单固定切割会把完整句子 / 段落拦腰切断的问题。 核心逻辑:按优先级分层切割,优先用大块分隔符拆分,不够长度再往下一级细分 。 完美适配 all-MiniLM-L6-v2 这类 512 token 上限的 embedding 模型。
二、核心参数
python
运行
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
# 1. 单块最大长度(推荐用token计数,不是字符)
chunk_size=400,
# 2. 块之间重叠长度,解决上下文断裂
chunk_overlap=80,
# 3. 分层分隔符,从粗到细,优先级从左到右
separators=["\n\n", "\n", ". ", "! ", "? ", " "],
# 4. 计算文本长度的函数,默认len(字符),强烈建议替换为token统计
length_function=len,
# 5. 是否允许块小于chunk_size(默认True)
keep_separator=True, # 分割符保留在块末尾,语义更完整
is_separator_regex=False, # 分隔符是否正则
)
关键参数解释
- separators 分层切割逻辑(核心) 默认英文分隔符优先级:
\n\n空行(完整段落,优先切)\n单行换行./!/?完整句子结尾- 空格,最后兜底切单词
执行流程:
-
先用第一个分隔符
\n\n把文本切成小段; -
遍历每一段,若长度 ≤ chunk_size → 直接作为 chunk;
-
若超长,取下一个分隔符继续拆分,直到所有片段都小于 chunk_size; 多层递归,最大程度不破坏完整语义单元。
-
length_function 避坑重点
- 默认
len:统计字符数,中英文 token 密度差异极大,会导致实际 token 超 512,编码截断; - 正确搭配 all-MiniLM-L6-v2:使用模型 tokenizer 统计真实 token 数量
python
运行
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-MiniLM-L6-v2")
# 替换长度函数,按token计数
def count_tokens(text):
return len(model.tokenizer.encode(text))
splitter = RecursiveCharacterTextSplitter(
chunk_size=400,
length_function=count_tokens
)
-
chunk_overlap 重叠窗口 推荐值:
chunk_size * 10% ~ 20%作用:一段横跨两个块的完整逻辑不会丢失,检索时上下文连贯。 例:chunk_size=400 → overlap=70~80 -
keep_separator=True 分割符号保留在块内,比如句号、换行不丢失,语义完整性更好。
三、中英文分隔符配置区分
1)英文文档(all-MiniLM-L6-v2 原生场景)
python
运行
separators = [
"\n\n", # 段落
"\n", # 换行
". ", "! ", "? ", # 完整句子
", ", # 分句
" " # 单词兜底
]
2)中文文档(MiniLM-zh / BGE 嵌入)
中文无英文句号空格,替换中文标点分隔符:
python
运行
separators = [
"\n\n",
"\n",
"。", "!", "?", # 完整句子终止
",", ";", "、", # 分句
" "
]
四、完整可运行示例(all-MiniLM-L6-v2 配套)
python
运行
from langchain.text_splitter import RecursiveCharacterTextSplitter
from sentence_transformers import SentenceTransformer
# 加载嵌入模型
embed_model = SentenceTransformer("all-MiniLM-L6-v2")
# 定义token计数函数
def token_len(text: str) -> int:
return len(embed_model.tokenizer.encode(text))
# 初始化分块器
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=400,
chunk_overlap=80,
length_function=token_len,
keep_separator=True,
separators=["\n\n", "\n", ". ", "! ", "? ", ","]
)
# 测试长文本
long_text = """
all-MiniLM-L6-v2 is a lightweight sentence embedding model based on MiniLM distillation.
It has only 6 layers and 66M parameters, outputting 384-dimensional normalized vectors.
The maximum input token length is 512, so document chunking is necessary for long articles.
RecursiveCharacterTextSplitter splits text by paragraph first, then sentences, to avoid breaking complete semantics.
Overlap between chunks solves the problem that cross-chunk logic cannot be retrieved.
This combination is the standard lightweight RAG stack for English knowledge bases.
"""
# 执行分块
chunks = text_splitter.split_text(long_text)
print(f"分块总数:{len(chunks)}")
for idx, chunk in enumerate(chunks):
print(f"\n===== Chunk {idx+1} =====\n{chunk}")
print(f"Token count: {token_len(chunk)}")
五、适配 all-MiniLM-L6-v2 最佳参数模板
MiniLM 上限 512 token,预留 overlap 安全空间:
通用知识库(英文技术文档、手册)
python
运行
RecursiveCharacterTextSplitter(
chunk_size=400,
chunk_overlap=80,
length_function=token_len,
separators=["\n\n", "\n", ". ", "! ", "? ", ","]
)
FAQ、短问答、产品说明
python
运行
RecursiveCharacterTextSplitter(
chunk_size=200,
chunk_overlap=40,
length_function=token_len
)
六、优缺点
优点
- 开箱即用,无需额外训练 / 额外 embedding 计算(对比语义分块更快);
- 分层切割,相比纯固定字符切割,大幅减少语义断裂;
- 支持自定义分隔符,适配中英文、Markdown、代码;
- 原生兼容 LangChain 全生态(Chroma、FAISS、Loader);
- 轻量,CPU 批量处理速度快,适合线上流水线。
缺点
- 只依赖符号分割,无法理解真实语义断层;长段落内多主题会被塞进同一个 chunk,干扰相似度检索;
- 纯代码块、表格、无标点长文本切割效果差;
- 若不用 token 计数,仅靠字符长度容易超限。
七、常见踩坑与解决
-
Chunk token 超过 512,模型截断向量失效 修复:
length_function使用模型 tokenizer 计数,chunk_size ≤450。 -
完整句子被从中间切断 修复:调整 separators 顺序,优先段落、句子终止符,不要把空格放最前面。
-
跨段落信息检索不到 修复:调高 overlap 至 chunk_size 的 15%~20%。
-
中文文档分块细碎、语义割裂 修复:替换中文标点 separators,不要用英文
.分隔符。
八、进阶替代方案对比
- 仅普通知识库:
RecursiveCharacterTextSplitter(首选) - Markdown 带标题文档:
MarkdownTextSplitter(继承自本类,内置 markdown 分隔符) - 高精度法律 / 论文:
SemanticChunker(语义分块,速度更慢) - 需要完整上下文回答:父子检索 + RecursiveCharacter 双层分块