1. 什么是文本分割器? #
文本分割器(Text Splitter)是一种将大型文档拆分为较小、可单独检索的文本片段(chunks)的工具。在自然语言处理和机器学习应用中,文本分割器非常重要,因为:
为什么需要文本分割?
模型上下文窗口限制:大多数语言模型(如 GPT、BERT 等)都有输入长度限制。例如,某些模型只能处理 512 个 token,而另一些可能支持 4096 或更多。当文档超过这个限制时,必须将其分割成更小的片段。
提高检索效率:在 RAG(检索增强生成)系统中,将长文档分割成小块可以提高检索的精确度。用户查询时,系统只需要检索相关的片段,而不是整个文档。
保持语义完整性:合理的分割策略可以确保每个文本块包含完整的语义单元(如段落、句子),避免在句子中间切断,从而保持上下文信息的完整性。
文本分割的核心挑战:
- 如何在不破坏语义的情况下分割文本?
- 如何确定合适的块大小?
- 如何处理不同语言的文本(特别是没有词边界的语言)?

2. 安装必要的库 #
在开始之前,我们需要安装 LangChain 的文本分割器库。LangChain 提供了多种文本分割器实现,是最常用的工具之一。
2.1 Windows 系统安装 #
在 Windows PowerShell 或命令提示符中执行:
# 升级 pip 到最新版本(推荐)
python -m pip install --upgrade pip
# 安装 langchain-text-splitters 库
python -m pip install langchain-text-splitters注意事项:
- 如果系统中有多个 Python 版本,可能需要使用
python3代替python - 如果遇到权限问题,可以添加
--user参数:python -m pip install --user langchain-text-splitters
2.2 macOS 系统安装 #
在 macOS 终端中执行:
# 升级 pip 到最新版本(推荐)
python3 -m pip install --upgrade pip
# 安装 langchain-text-splitters 库
python3 -m pip install langchain-text-splitters注意事项:
- macOS 系统通常需要使用
python3命令 - 如果提示找不到
python3,可能需要先安装 Python
2.3 验证安装 #
安装完成后,可以通过以下代码验证是否安装成功:
# 尝试导入文本分割器类
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 如果没有报错,说明安装成功
print("langchain-text-splitters 安装成功!")3. 前置知识 #
3.1 什么是 Chunk Size 和 Chunk Overlap? #
Chunk Size(块大小):
- 每个文本块的最大长度(可以是字符数或 token 数)
- 需要根据模型限制和文档类型来设置
- 太小会丢失上下文,太大会超出模型限制
Chunk Overlap(块重叠):
- 相邻文本块之间的重叠部分
- 用于保持上下文连贯性
- 例如:如果块大小是 100,重叠是 20,那么第一个块是字符 1-100,第二个块是字符 81-180
为什么需要重叠?
- 避免在句子或段落中间切断
- 确保重要信息不会因为分割而丢失
- 提高检索时找到相关内容的概率
3.2 分隔符(Separators)的作用 #
分隔符是用于分割文本的字符或字符串。常见的分隔符包括:
\n\n:段落分隔(两个换行符)\n:行分隔(单个换行符):空格(单词分隔).:句号(句子分隔),:逗号
分隔符的选择直接影响分割质量。通常按照从粗粒度到细粒度的顺序使用分隔符。

4. 文本分割的三种主要策略 #
根据不同的应用场景和文档类型,文本分割可以采用三种主要策略。每种策略都有其独特的优势和适用场景。
4.1 基于长度的分割 #
核心思想: 严格按照指定的长度(字符数或 token 数)进行分割,确保每个块大小一致。
工作原理:
- 按固定长度切分文本
- 不考虑语义边界
- 可以基于字符数或 token 数
优势:
- 实现简单直接
- 块大小一致,便于管理
- 可以精确控制块大小
适用场景:
- 对块大小有严格要求
- 不需要考虑语义边界
- 处理结构化数据
4.1.2 字符分割器(CharacterTextSplitter) #
字符分割器按照字符数进行分割,是最简单的分割方法。
# 导入字符文本分割器类
from langchain_text_splitters import CharacterTextSplitter
# 创建字符分割器实例,设置每个块最大长度为100个字符、不重叠、使用空字符串作为分隔符(即按字符切分)
text_splitter = CharacterTextSplitter(
chunk_size=100, # 每个块最大长度为100个字符
chunk_overlap=0, # 块之间不重叠
separator="" # 使用空字符串作为分隔符(即按字符切分)
)
# 构造一个需要分割的长文本,这里由100个'1'、100个'2'和100个'3'拼接组成
document = f"""{"1"*100}{"2"*100}{"3"*100}"""
# 使用分割器的split_text方法,将原始文本切分为若干个子块
texts = text_splitter.split_text(document)
# 打印原始文本的长度(字符数)
print(f"原文长度:{len(document)} 字符")
# 打印分割后块的数量
print(f"分割为 {len(texts)} 个块")
# 打印前3个分块的内容(如果存在多于3个块)
print("\n前 3 个块:")
for i, text in enumerate(texts[:3], 1):
# 打印每个块的编号、该块的字符长度和内容
print(f"\n块 {i}({len(text)} 字符):{repr(text)}")4.1.2 基于 Token 的分割 #
对于语言模型应用,按 token 数分割通常更准确,因为模型限制通常以 token 数表示。
# 从 langchain_text_splitters 导入 RecursiveCharacterTextSplitter,用于递归字符/Token分割
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 使用 tiktoken 编码器创建递归字符分割器
# 这里的编码名称为 "cl100k_base",适用于 GPT-4
# chunk_size 设置为 100,表示每块最多 100 个 token
# chunk_overlap 为 0,表示不同块之间没有重叠
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
encoding_name="cl100k_base", # 编码名称(GPT-4 使用的编码)
chunk_size=100, # 每个块最多 100 个 token
chunk_overlap=0 # 块之间不重叠
)
# 准备需要分割的长文本,由 100 个 "hello "、100 个 "world " 和 100 个 "python " 组成
document = f"""{"hello " * 100}{"world " * 100}{"python " * 100}"""
# 调用分割器的 split_text 方法,将长文本按 token 拆分成多个块
texts = text_splitter.split_text(document)
# 打印分割后的块数量
print(f"分割为 {len(texts)} 个块")
# 遍历分割后的每一个块,并打印块编号和具体内容
for i, text in enumerate(texts, 1):
print(f"\n块 {i}:{repr(text)}")注意事项:
- 使用
from_tiktoken_encoder需要安装tiktoken库:pip install tiktoken cl100k_base是 GPT-4 使用的编码,其他模型可能使用不同的编码- Token 数量通常小于字符数,因为一个 token 可能包含多个字符
4.2 基于文本结构的分割 #
核心思想: 利用文本的天然层级结构(段落、句子、词语)进行分割,尽可能保持语义单元的完整性。
工作原理:
- 首先尝试按段落分割(使用
\n\n) - 如果段落仍然太大,按句子分割(使用
\n或.) - 如果句子仍然太大,按词语分割(使用空格)
- 最后才按字符分割
优势:
- 保持语义完整性
- 分割结果更自然
- 适合大多数通用文本
适用场景:
- 普通文档、文章、报告
- 需要保持上下文连贯性的场景
- 大多数 RAG 应用
4.2.1. 递归字符文本分割器(推荐使用) #
RecursiveCharacterTextSplitter 是 LangChain 中最常用的文本分割器,它实现了基于文本结构的分割策略。对于大多数应用场景,这是推荐的默认选择。
为什么推荐?
- 在保持上下文完整性和管理块大小之间取得了良好的平衡
- 开箱即用,默认配置就能很好地工作
- 只有在需要针对特定应用进行微调时才需要调整参数
下面的示例演示如何使用 RecursiveCharacterTextSplitter 分割文本。
# 从 langchain_text_splitters 模块导入递归字符文本分割器类
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 创建递归字符文本分割器对象,指定参数
# chunk_size 表示每块最大允许的字符数为 100
# chunk_overlap 表示块与块之间没有重叠(重叠字符数为 0)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=100,
chunk_overlap=0
)
# 构造待分割的文本,包含多段各自为 99 或 100 个相同字符以及换行符
document = f"""{"1"*100}\n{"2"*99}\n\n{"3"*99}\n{"4"*99}"""
# 使用文本分割器的 split_text 方法将 document 分割为多个字符串块
texts = text_splitter.split_text(document)
# 打印一共分割出的块数
print(f"共分割为 {len(texts)} 个块:")
# 枚举输出每个块的序号及块内容(使用 repr 格式便于查看特殊字符)
for i, text in enumerate(texts, 1):
print(i, repr(text))运行说明:
- 保存代码为
splitter_demo.py - 在终端运行:
python splitter_demo.py(Windows)或python3 splitter_demo.py(macOS) - 查看分割结果
RecursiveCharacterTextSplitter 的主要参数:
chunk_size(块大小):
- 每个块的最大大小
- 大小由
length_function决定(默认是字符数) - 建议值:200-1000 字符,取决于你的模型限制
chunk_overlap(块重叠):
- 相邻块之间的重叠大小
- 有助于在上下文被分割到不同块时减轻信息丢失
- 建议值:chunk_size 的 10-20%
length_function(长度函数):
- 用于确定块大小的函数
- 默认是
len(字符数) - 也可以使用 token 计数函数
is_separator_regex(分隔符是否为正则表达式):
- 默认为
False - 如果设置为
True,分隔符列表会被解释为正则表达式
separators(分隔符列表):
- 默认是
["\n\n", "\n", " ", ""] - 按照从粗粒度到细粒度的顺序使用
- 可以自定义分隔符列表

4.3 基于文档结构的分割 #
核心思想: 利用文档的格式结构(如 Markdown 标题、HTML 标签、JSON 对象)进行分割。
工作原理:
- 识别文档的格式标记(如
#标题、<div>标签) - 按照这些标记进行分割
- 保持文档的逻辑结构
优势:
- 保留文档的逻辑结构
- 每个块内保持上下文
- 对结构化文档效果更好
适用场景:
- Markdown 文档
- HTML 网页
- JSON 数据
- 代码文件
4.3.1 Split markdown #
在实际工程中,许多文档(如 Markdown、HTML、代码文件)都具有明显的结构性。针对这类结构化文本,直接用通用分割器可能导致优雅的段落、标题等被切割,影响后续检索和上下文理解。因此,LangChain 提供了专门的结构化文本分割器(如 MarkdownHeaderTextSplitter),能够基于文档的结构标签有层次地拆分文本。
以 Markdown 为例,MarkdownHeaderTextSplitter 支持根据不同级别的标题(如 #、##、### 等)对文本进行递归分割,每个分割块能够保持所属标题信息,便于后续内容聚合、检索与问答等应用。
下面的例子展示了如何使用 MarkdownHeaderTextSplitter 按 Markdown 结构拆分文档:
- 自定义需要拆分的标题等级(如一级标题、二级标题、三级标题)
- 拆分后,每个文本块可以关联上层的标题,保持了文档的层级组织
- 便于后续实现“只检索特定章节内容”以及“溯源原始结构”
from langchain_text_splitters import MarkdownHeaderTextSplitter
markdown_document = f"""# Foo
Hi this is Bob
## Bar
Hi this is Alice
### Boo
Hi this is Lance"""
headers_to_split_on = [
("#", "Header 1"),
("##", "Header 2"),
("###", "Header 3"),
]
markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on,strip_headers=False)
md_header_splits = markdown_splitter.split_text(markdown_document)
for i, text in enumerate(md_header_splits, 1):
print(i, repr(text.page_content))4.3.1 Split code #
对于结构化代码(如 Python、JavaScript、HTML、JSON 等),直接基于字符数或简单的分隔符进行切分往往会破坏代码的结构,造成函数、类、逻辑块等被断裂。LangChain 针对不同的主流编程语言提供了结构感知的分割器(如 RecursiveCharacterTextSplitter.from_language),能够更好地按照语言语法、结构边界(如函数、类、注释分隔)合理拆分代码块。
这种做法的好处包括:
- 每个分割块尽量保持语法和语义完整,便于后续实现代码段检索、问答和溯源定位。
- 可自定义 chunk 大小,自动处理代码块重叠,避免关键上下文信息缺失。
- 支持多种常见编程语言(如 Python、JavaScript、Java、C++、Go、HTML、JSON 等),无需手动实现分割规则。
实际应用中,如果要处理大段代码文本,可以优先选择结构化的分割器,提升检索和问答质量。同时,对于数据格式(如 Markdown、JSON 等),建议结合专用分割器和通用分割器,满足不同应用场景的需求。
# 从langchain_text_splitters模块导入Language和RecursiveCharacterTextSplitter
from langchain_text_splitters import (
Language,
RecursiveCharacterTextSplitter,
)
# 定义一个包含Python代码的多行字符串
PYTHON_CODE = """
def hello_world():
print("Hello, World!")
# Call the function
hello_world()
"""
# 创建一个适用于Python语言的递归字符文本分割器,设置分块大小为50,无重叠
python_splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.PYTHON, chunk_size=50, chunk_overlap=0
)
# 使用分割器将Python代码分割为文档
python_docs = python_splitter.create_documents([PYTHON_CODE])
# 输出分割得到的文档对象
for i, doc in enumerate(python_docs, 1):
print(i, doc.page_content)5. 处理无词边界语言 #
某些语言(如中文、日文、泰文)没有明显的词边界,使用默认分隔符可能导致单词被拆分。本节介绍如何处理这些语言。
5.1 问题说明 #
什么是无词边界语言?
- 中文、日文、泰文等语言在书写时词与词之间没有空格
- 例如:"我喜欢编程" 中,"我"、"喜欢"、"编程" 之间没有分隔符
- 使用默认分隔符
["\n\n", "\n", " ", ""]可能在不合适的位置分割
为什么需要特殊处理?
- 默认分隔符主要针对英文设计
- 对于中文等语言,需要添加额外的标点符号作为分隔符
- 这样可以更好地保持语义完整性
5.2 解决方案:自定义分隔符 #
下面的代码演示如何为中文文本添加合适的分隔符。
# 导入递归字符文本分割器类
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 创建递归字符文本分割器对象,专为中文文本优化
text_splitter = RecursiveCharacterTextSplitter(
# 指定用于分割的分隔符列表,包含常见中英文标点
separators=[
"\n\n", # 两个换行符,分隔段落
"\n", # 单个换行符,分隔行
" ", # 空格,分隔英文单词
".", # 英文句号
"。", # 中文句号
",", # 中文逗号(全角)
"、", # 中文顿号
"\u200b", # 零宽空格(部分亚洲语种分词用)
"\uff0c", # Unicode 全角逗号
"\uff0e", # Unicode 全角句号
"\u3002", # Unicode 中文句号
"", # 最后按字符强制分割
],
# 设置每个块的最大字符数为 100
chunk_size=100,
# 设置相邻块之间的重叠字符数为 20
chunk_overlap=20
)
# 构造待分割的中文文本示例
chinese_text = """
人工智能是计算机科学的一个分支。它试图理解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器。
机器学习是人工智能的一个子领域。它使计算机能够在没有明确编程的情况下学习和改进。
深度学习是机器学习的一个子集。它使用神经网络来模拟人脑的工作方式。
"""
# 使用分割器的 split_text 方法对中文文本进行分块
texts = text_splitter.split_text(chinese_text)
# 打印原文字符总长度
print(f"原文长度:{len(chinese_text)} 字符")
# 打印分割后得到的块数
print(f"分割为 {len(texts)} 个块\n")
# 遍历每个分块,依次打印其编号、长度及内容
for i, text in enumerate(texts, 1):
print(f"块 {i}({len(text)} 字符):")
print(text)
# 打印分隔线便于区分
print("-" * 50)运行说明:
- 运行后会看到中文文本被按照句号、逗号等标点符号合理分割
- 可以尝试不同的分隔符组合,找到最适合你文本的分割方式
5.3 多语言混合文本处理 #
如果你的文档包含多种语言(如中英文混合),可以使用更全面的分隔符列表。
# 导入递归字符文本分割器类
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 创建一个递归字符文本分割器对象,支持多语言分隔符
text_splitter = RecursiveCharacterTextSplitter(
# 指定用于分割的分隔符列表,包含中英文常用符号
separators=[
"\n\n", # 段落分隔符
"\n", # 行分隔符
"。", # 中文句号
".", # 英文句号
"!", # 中文感叹号
"!", # 英文感叹号
"?", # 中文问号
"?", # 英文问号
",", # 中文逗号
",", # 英文逗号
";", # 中文分号
";", # 英文分号
" ", # 空格
"", # 最后按字符进行分割
],
# 设置每个块的最大字符数为 300
chunk_size=300,
# 相邻块之间重叠 50 个字符
chunk_overlap=50
)
# 定义一段中英文混合的示例文本
mixed_text = """
Python is a popular programming language. 它简单易学,功能强大。
You can use Python for web development, data analysis, and machine learning.
你可以用它来开发网站、分析数据和进行机器学习。
The syntax is clean and readable. 语法简洁易读。
"""
# 使用文本分割器将文本分割为多个块
texts = text_splitter.split_text(mixed_text)
# 打印分割后块的总数
print(f"分割为 {len(texts)} 个块\n")
# 遍历每一个分割出来的块,逐块打印其编号和内容
for i, text in enumerate(texts, 1):
print(f"块 {i}:")
print(text)
print("-" * 50)6. 常见问题与解决方案 #
在使用文本分割器的过程中,可能会遇到一些问题。本节列出常见问题及解决方法。
6.1 问题 1:分割后的块大小不一致 #
问题描述: 设置了 chunk_size=500,但实际块的大小可能小于 500。
原因:
- 递归分割器会尽量在语义边界(如段落、句子)处分割
- 如果段落或句子小于 500 字符,块就会小于设定值
- 这是正常行为,有助于保持语义完整性
解决方案:
- 如果确实需要固定大小,使用
CharacterTextSplitter而不是RecursiveCharacterTextSplitter - 或者接受较小的块,因为保持语义完整性通常更重要
6.2 问题 2:中文文本分割效果不好 #
问题描述: 中文文本被不合理地分割,可能在句子中间切断。
原因:
- 默认分隔符主要针对英文设计
- 中文没有词边界,需要添加中文标点符号作为分隔符
解决方案:
- 添加中文标点符号到分隔符列表
- 使用
["\n\n", "\n", "。", ",", " ", ""]这样的分隔符列表
6.3 问题 3:重叠部分导致重复内容 #
问题描述: 设置了 chunk_overlap,但发现相邻块有重复内容。
原因:
- 这是
chunk_overlap的正常行为 - 重叠是为了保持上下文连贯性
解决方案:
- 如果不需要重叠,设置
chunk_overlap=0 - 如果觉得重叠太多,减小
chunk_overlap的值 - 在检索时,可以使用去重逻辑处理重复内容
6.4 问题 4:分割速度慢 #
问题描述: 处理大文件时,分割速度很慢。
原因:
- 递归分割需要多次尝试不同的分隔符
- 大文件需要处理更多内容
解决方案:
- 减少分隔符数量
- 使用更简单的分割器(如
CharacterTextSplitter) - 考虑并行处理多个文件
6.5 问题 5:Token 计数不准确 #
问题描述: 使用 token 分割时,实际 token 数与预期不符。
原因:
- 不同模型使用不同的 tokenizer
tiktoken的编码可能与你的模型不匹配
解决方案:
- 确认使用的编码名称与你的模型匹配
- GPT-4 使用
cl100k_base - GPT-3.5 使用
cl100k_base - 其他模型可能需要不同的编码