RecursiveCharacterTextSplitter类解读

张开发
2026/4/10 16:33:40 15 分钟阅读

分享文章

RecursiveCharacterTextSplitter类解读
基于 LangChain 当前官方文档与官方源码/参考入口RecursiveCharacterTextSplitter可以这样理解文章目录1) 切分原理2) 关键参数3) 方法接口4) 适用边界5) 中文场景优化6核心类方法的使用1. split_text(text: str) - list[str]2. create_documents(texts: list[str], metadatas: list[dict] | None None) - list[Document]3. from_language(language: Language, **kwargs: Any) - RecursiveCharacterTextSplitter4. get_separators_for_language(language: Language) - list[str]5结论1) 切分原理它是 LangChain 官方推荐的通用文本默认切分器核心思路是给定一组分隔符按顺序递归尝试分割文本如果当前层级切出来的片段仍然超过目标大小就继续用下一层更“细”的分隔符再切。默认分隔符是[\n\n, \n, , ]也就是优先保留段落其次换行再其次空格最后退化到逐字符级别。因此它的目标不是“绝对平均切块”而是尽量在语义完整性和块大小约束之间取平衡。官方文档也明确说了对大多数场景先从它开始。(LangChain 文档)从源码看它会先在传入的separators里找到当前文本中实际存在的第一个分隔符用这个分隔符先切对小于chunk_size的片段先暂存对超长片段再递归调用_split_text(..., new_separators)用后续更细的分隔符继续切。切完后再做 merge得到最终 chunks。这个机制解释了它为什么通常比“固定长度硬切”更适合 RAG。(GitHub)2) 关键参数官方示例里最关键的是这几个chunk_size、chunk_overlap、length_function、is_separator_regex。其中chunk_size是单块上限具体“大小”由length_function决定chunk_overlap是相邻块之间的目标重叠用来降低上下文被切断后的信息损失length_function决定如何计算长度默认示例用lenis_separator_regex则决定你传入的 separators 是按普通字符串解释还是按正则解释。(LangChain 文档)源码还显示它自己的构造参数里额外暴露了separators默认值就是[\n\n, \n, , ]并且keep_separator默认是True。这意味着切分时通常会保留分隔符而不是简单把分隔符丢掉源码中的_split_text_with_regex还支持keep_separatorstart或end这样的控制方式。这个点在处理标点、代码边界时很有用因为保留边界符往往更利于语义还原。(GitHub)一个容易忽略但很重要的点官方文档页写的是“chunk size 按字符数衡量”这是针对默认length_functionlen的讲法如果你换了length_function例如改成 tokenizer 计数本质上它就不再是“字符长度切分器”而是“递归分隔 自定义长度度量”。(LangChain 文档)3) 方法接口直接可用的核心接口有split_text(text) - list[str]输入字符串输出字符串列表。官方文档明确把它作为“直接拿字符串 chunks”的入口。(LangChain 文档)create_documents(texts, metadatasNone) - list[Document]把文本列表切分后生成Document对象适合后续 embedding、向量库入库、检索链路。官方递归切分文档直接这样推荐基类源码也表明这是标准接口。(LangChain 文档)split_documents(documents) - list[Document]与transform_documents(documents)这两个是基类TextSplitter上的文档级接口前者对输入Document序列做拆分后者则是“transform”风格封装内部仍然走文档切分。(GitHub)from_language(language, **kwargs)官方源码和代码切分文档都给出了这个工厂方法它会根据编程语言拿一套预置 separators并且用is_separator_regexTrue初始化。适合代码、Markdown、HTML、LaTeX 这类带明显结构边界的内容。(GitHub)get_separators_for_language(language)返回某种语言的预置分隔符。官方代码切分文档明确展示了它的用法比如 Python 的 separators 包含\n class、\n def、\n\n、\n、、。(LangChain 文档)另外RecursiveCharacterTextSplitter继承自TextSplitter。官方参考入口显示基类还提供from_tiktoken_encoder和from_huggingface_tokenizer这类工厂方法因此你可以把“长度计算”切到 token 维度而保留递归分隔策略。(LangChain 参考文档)4) 适用边界它最适合的是普通自然语言文本、轻度结构化文档、以及希望尽量保留段落/句子完整性的通用 RAG 预处理。官方把它定位为 generic text 的推荐起点这个判断很明确。(LangChain 文档)但它也有边界第一它本质仍是基于分隔符的启发式切分不是语义模型切分器。也就是说它能“尽量沿自然边界切”但不理解真正的语义单元遇到表格、复杂 JSON、长公式、扫描文本、跨段强依赖内容时效果可能一般。官方文本切分总览页也把 splitter 分成 text structure-based、length-based、document structure-based 等不同类别说明它并不是所有类型文档的最优器。(LangChain 文档)第二默认策略对无空格语言不够友好。官方专门拿中文、日文、泰文举例说明默认分隔符[\n\n, \n, , ]可能会把词切断。也就是说中文不建议直接吃默认配置。(LangChain 文档)第三如果你的真正约束是模型 token 窗口而不是字符数那么仅用默认len并不稳妥。更合理的做法是保留RecursiveCharacterTextSplitter的递归分隔思想但把长度函数改成 tokenizer 维度或直接用基类提供的 tokenizer 工厂能力。(LangChain 文档)5) 中文场景优化官方对中文场景的建议非常直接给separators增补中文常见标点尤其是句号和逗号类边界。文档明确列出应考虑加入.、、。、零宽空格\u200b、,、、、以避免无词边界语言在 chunk 之间被生硬截断。(LangChain 文档)一个更实用的中文配置可以写成这样fromlangchain_text_splittersimportRecursiveCharacterTextSplitter text_splitterRecursiveCharacterTextSplitter(chunk_size500,chunk_overlap80,separators[\n\n,\n,。,,,,,、, ,],)这里我在官方建议基础上额外加了 ? 这类中文句读符号这部分属于实践扩展不是官方原样列表但方向与官方“为中文补充标点边界”的建议一致。官方原文明确列出的仍然是.、,、、。、、、和\u200b。(LangChain 文档)中文实践里我建议这样落地纯段落型文章先用[\n\n, \n, 。, , ]问答/客服语料优先加入、法规/制度/合同加入、条款编号分隔符必要时开启 regex混合中英文本同时保留英文.,和中文。代码/Markdown/HTML优先考虑from_language(...)的结构化 separators而不是手写一套中文标点规则 (LangChain 文档)6核心类方法的使用根据 LangChain 官方文档RecursiveCharacterTextSplitter提供了几个关键方法核心方法包括split_text、create_documents和from_language。以下是这些方法的使用示例和核心说明1.split_text(text: str) - list[str]此方法用于将输入的文本按设定的分隔符切割成较小的文本片段。默认的分隔符为[\n\n, \n, , ]可以根据需求自定义。它是获取文本切分后的基础方法。使用示例fromlangchain_text_splittersimportRecursiveCharacterTextSplitter text_splitterRecursiveCharacterTextSplitter(chunk_size100,chunk_overlap20,length_functionlen,is_separator_regexFalse,)textMadam Speaker, Madam Vice President, our First Lady and Second Gentleman...chunkstext_splitter.split_text(text)print(chunks)此方法直接返回切割后的文本列表。2.create_documents(texts: list[str], metadatas: list[dict] | None None) - list[Document]此方法将切分后的文本转换为Document对象。每个Document对象包含文本及其元数据通常用于后续处理如嵌入embedding或存储在向量数据库中。使用示例fromlangchain_text_splittersimportRecursiveCharacterTextSplitter# 假设你已经有了切分后的文本列表 textstexts[Madam Speaker...,Justices of the Supreme Court...,My fellow Americans...]metadatas[{source:speech1},{source:speech2},{source:speech3}]text_splitterRecursiveCharacterTextSplitter(chunk_size100,chunk_overlap20)documentstext_splitter.create_documents(texts,metadatasmetadatas)fordocindocuments:print(doc.page_content)print(doc.metadata)此方法返回的是Document对象列表。3.from_language(language: Language, **kwargs: Any) - RecursiveCharacterTextSplitter此类方法是一个工厂方法根据指定语言来返回一个配置了特定语言分隔符的RecursiveCharacterTextSplitter实例。适用于代码、Markdown、HTML 等语言/文档类型需要结构化分隔符。使用示例fromlangchain_text_splittersimportRecursiveCharacterTextSplitter,Language# 创建一个专门用于处理 Python 代码的文本切分器text_splitterRecursiveCharacterTextSplitter.from_language(languageLanguage.PYTHON,chunk_size100,chunk_overlap20)这会自动选择适合 Python 代码的分隔符如\n class ,\n def 等并初始化一个切分器。不同语言可以通过Language枚举来配置。4.get_separators_for_language(language: Language) - list[str]这个静态方法返回指定语言的分隔符列表适用于从头开始构建分隔符时使用或者调试时查看分隔符。使用示例fromlangchain_text_splittersimportRecursiveCharacterTextSplitter,Language# 查看 Python 语言的分隔符separatorsRecursiveCharacterTextSplitter.get_separators_for_language(Language.PYTHON)print(separators)返回的分隔符列表可以帮助用户了解该语言在代码分割中的常用分隔符例如\n def 或\n class 等。5这些方法配合使用可以帮助我们根据不同的文本类型和需求切分文本处理大规模文本数据并优化模型上下文窗口的输入。对于需要进行语义保留和块大小控制的应用场景RecursiveCharacterTextSplitter是一个非常强大的工具。需要注意的是from_language和get_separators_for_language等方法特别适合结构化文档如代码、Markdown而对于自然语言文本直接使用split_text和create_documents就足够了。结论如果你把它放到 RAG 预处理中最准确的定位是RecursiveCharacterTextSplitter 递归分隔策略 可配置长度度量 面向通用文本的默认首选。默认配置适合英文或带空格文本到了中文场景核心优化不是盲目调大chunk_size而是先把 separators 改对再根据召回和答案完整率调chunk_size / chunk_overlap。(LangChain 文档)

更多文章