LangChain:文本切割器如何根据tokens拆分文本

大语言模型存在Token数量限制,不应超出该限制(如 GPT-4 Turbo 支持 128K Token)。超出限制会导致截断或报错。

因此,在分割文本成块时,需要计算好Token的数量。市面上存在多种tokenizer,计算文本token数量时,应使用与语言模型相匹配的tokenizer

官方文档:How to split text by tokens

tiktoken

tiktokenOpenAI创建的一个快速BPE标记器。

我们可以使用 tiktoken来估算会使用到的token数量。对于OpenAI模型来说,这会比较准确。

  1. 文本如何分割:按传入的字符。
  2. 如何测量块大小:通过tiktoken标记器。

分割器CharacterTextSplitter, RecursiveCharacterTextSplitter, 和TokenTextSplitter可以被tiktoken直接使用。

安装tiktoken

1
%pip install --upgrade --quiet langchain-text-splitters tiktoken

CharacterTextSplitter

1
2
3
4
5
6
7
8
9
10
11
12
13
from langchain_text_splitters import CharacterTextSplitter

text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
encoding_name="cl100k_base", chunk_size=100, chunk_overlap=0
)
# This is a long document we can split up.
with open("../file/report.txt", encoding="utf-8") as f:
report_content = f.read()
#print(report_content)
texts = text_splitter.split_text(report_content)
for text in texts:
print(text)
print("-" * 50)

执行结果

1
2
3
4
2024年是实现“十四五”规划目标任务的关键一年。中央经济工作会议明确提出稳中求进的工作总基调,要求扎实推动高质量发展。上市公司是加快培育新质生产力的重要载体,肩负着实现高质量发展的时代使命。
--------------------------------------------------
截至5月7日,除公告延迟披露公司外,沪、深、北三家证券交易所共5412[1]家上市公司公布2024年年度报告。数据显示,上市公司群体以创新驱动为核心,扎实推进产业优化升级,以稳健经营应对风险挑战,以深化改革激发内生动力,发展质量和投资价值持续提升。
--------------------------------------------------

注意CharacterTextSplitter 默认的切割符是\n\n,切割出来的块的大小不是固定的,有可能比设置的限制大。

API指南CharacterTextSplitter

使用CharacterTextSplitter进行分割,然后使用tiktoken.from_tiktoken_encoder()方法合并块。注意,此方法的分割的块可能大于tiktoken标记器计算的块大小。

.from_tiktoken_encoder()方法接受的参数:

  • encoding_name:指定使用的 tiktoken 编码名称。cl100k_baseOpenAIgpt-3.5-turbogpt-4 模型设计的编码方案,文本分割器会依据这个编码方案把文本转换为 token 序列,再按 token 数量进行分割。

  • model_name:指定要使用的模型名称,进而获取对应的 tiktoken 编码。

    如果 model_name 不为 None,会调用 tiktoken.encoding_for_model(model_name) 方法,依据传入的模型名称获取对应的编码。不同的模型可能使用不同的编码方案,使用 encoding_for_model 能确保获取到正确的编码。若 model_name 为 None,则使 编码。

    模型与 tiktoken 编码映射:见 tiktoken 包的 model.py文件的常量MODEL_TO_ENCODING

  • chunk_size:设置每个分割后的文本块包含的最大 token 数量。这里表示每个文本块最多包含 100 个 token。

  • chunk_overlap:设置相邻文本块之间重叠的 token 数量。示例里设为 0,意味着相邻文本块之间没有重叠。

RecursiveCharacterTextSplitter

如果要强制硬约束 token 限制的数量,可以使用 RecursiveCharacterTextSplitter.from_tiktoken_encoder,如果每个分割的块较大时,则将其递归分割,直到满足限制。

CharacterTextSplitterRecursiveCharacterTextSplitterfrom_tiktoken_encoder()方法都是继承自TextSplitter

1
2
3
4
5
6
7
from langchain_text_splitters import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
model_name="gpt-4",
chunk_size=100,
chunk_overlap=0,
)

API指南RecursiveCharacterTextSplitter

TokenTextSplitter

还可以使用TokenTextSplitter分割器,它直接与tiktoken一起工作,并确保每次拆分都小于设置的块大小。

1
2
3
4
5
6
from langchain_text_splitters import TokenTextSplitter

text_splitter = TokenTextSplitter(chunk_size=10, chunk_overlap=0)

texts = text_splitter.split_text(state_of_the_union)
print(texts[0])

执行结果

1
2
3
4
5
6
7
8
2024年是实现“十四五
--------------------------------------------------
”规划目标任务的关键
--------------------------------------------------
一年。中央经济工
--------------------------------------------------
作会议明确提出稳中
--------------------------------------------------

API指南TokenTextSplitter

某些书面语言(如中文、日文)的字符会编码为2个或更多分词(token)。直接使用TokenTextSplitter可能导致字符的分词被拆分到不同文本块中,从而产生无效的Unicode字符。建议改用RecursiveCharacterTextSplitter.from_tiktoken_encoderCharacterTextSplitter.from_tiktoken_encoder方法,以确保每个文本块包含合法的Unicode字符串。

spaCy分割器

spaCy 用于高级自然语言处理的开源软件库,是 langchain 库中的一个文本分割工具,借助 spaCy 库可以根据语言规则对文本进行分割,用Python和Cython编程语言编写的。

LangChain基于spaCy标记器实现了分割器。

  1. 文本如何分割:通过spaCy标记器。
  2. 如何测量块大小:按字符数。

安装依赖

1
%pip install --upgrade --quiet  spacy

主要参数

  1. pipeline:指定要使用的 spaCy 语言模型管道名称,默认值为 "en_core_web_sm"。不同语言模型支持不同语言,例如 "zh_core_web_sm" 用于中文。
  2. chunk_size:每个文本块的最大字符数,默认值为 500
  3. chunk_overlap:相邻文本块之间重叠的字符数,默认值为 200。该值必须小于 chunk_size
  4. length_function:用于计算文本长度的函数,默认使用 len 函数。

pipeline语言模型库的安装:

1
2
3
4
5
# 默认使用英文语言模型 en_core_web_sm
python -m spacy download en_core_web_sm

# 使用中文语言模型 zh_core_web_sm
python -m spacy download zh_core_web_sm

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from langchain_text_splitters import SpacyTextSplitter

# 使用中文语言模型,设置每个文本块最大字符数为 100,重叠字符数为 10
text_splitter = SpacyTextSplitter(
pipeline="zh_core_web_sm",
chunk_size=100,
chunk_overlap=10
)
with open("../file/report.txt", encoding="utf-8") as f:
text_content = f.read()
texts = text_splitter.split_text(text_content)
# print(texts[0])
for text in texts:
print(text)
print("-" * 50)

API指南SpacyTextSplitter

SentenceTransformers

SentenceTransformersTokenTextSplitter 是专为sentence-transformers设计的文本分词和分割工具。其默认行为是将文本分割成适合目标模型分词窗口大小的文本块。

SentenceTransformersTokenTextSplitter通过对齐模型的分词机制,使分割后的文本块最大程度保留原始语义信息,为后续的嵌入、检索、生成等任务提供高质量输入基础。

模型感知的分割(核心优势)

  • 与目标模型对齐:使用与 Sentence Transformer 模型完全相同的分词器,确保:
    • 分割边界与模型预训练时的语义单元一致
    • 避免在语义关键位置(如词根、词组中间)切割
  • 规避模型截断风险:精确计算token数量,确保每个chunk不超过模型最大长度

✅ 效果:提升下游任务(如嵌入生成)质量10-25%(Hugging Face 基准测试

若需根据 sentence-transformers 分词器进行文本分割并控制分词数量,安装依赖库

1
pip install sentence-transformers

实例化参数

实例化 SentenceTransformersTokenTextSplitter,可选的配置项包括:

  1. model_name:指定预训练模型的名称或本地路径,其核心目的是确定模型的架构、预训练权重及训练目标,从而为后续的文本编码或微调任务提供基础模型支持。

    默认值为 sentence-transformers/all-mpnet-base-v2

  2. chunk_size:分割的每个文本块的理想 token 数量,分割器会尽量创建接近该大小的块。实际分割可能略低于或高于此值(为保持语义完整性),默认值为 512

  3. chunk_overlap:相邻文本块之间重叠的 token 数量,默认值为 0

  4. tokens_per_chunk:分割的每个文本块的绝对最大token数量,硬性限制。此参数具有最高优先级,如果设置,会覆盖chunk_size的限制,可能导致句子被强行截断(影响语议完整性),适用于严格控制 token 预算的特殊场景。

    建议:优先使用 chunk_size 作为主要控制参数,仅在需要严格限制token数量时才使用tokens_per_chunk,并始终考虑模型的实际token限制。

  5. encoding_name:指定使用的编码名称,若未指定,会根据 model_name 自动选择合适的编码。

  6. disallowed_special:不允许出现在 token 中的特殊字符集合,默认值为 DENY_LIST,即不允许任何特殊字符。

  7. allowed_special:允许出现在 token 中的特殊字符集合,默认值为 set(),即不允许任何特殊字符。

model_name说明

model_name 参数本质是模型架构的标识符,但通过 Hugging Face 的 API 设计,它间接关联了对应的分词器。开发者无需单独指定分词器名称,只需确保 model_name 正确,即可自动完成模型与分词器的协同加载。

SentenceTransformer 或 Hugging Face 的 transformers 库中,model_name 参数同时关联模型架构和分词器

  • 模型标识model_name 主要用于指定预训练模型的架构和权重(如 BERT、MPNet 等),通常包含分词器类型信息,例如
    • bert-base-uncased → BERT 模型 + 对应的分词器(WordPiece)
    • gpt2 → GPT-2 模型 + 对应的分词器(BPE)
  • 分词器绑定:模型名称隐含了分词器的类型,通过 AutoTokenizer.from_pretrained(model_name) 自动匹配与模型预训练时相同的分词规则。

使用示例一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 从 langchain_text_splitters 模块导入 SentenceTransformersTokenTextSplitter 类
# 该类用于基于 Sentence Transformers 模型进行文本分词和分割
from langchain_text_splitters import SentenceTransformersTokenTextSplitter

# 以下是一个注释掉的示例配置,展示了如何初始化 SentenceTransformersTokenTextSplitter 类
# 配置信息包括使用的模型名称、每个分块的大小、分块重叠部分、是否保留分隔符、是否添加起始索引以及是否去除空白字符
# splitter = SentenceTransformersTokenTextSplitter(
# model_name="sentence-transformers/paraphrase-multilingual-mpnet-base-v2",
# chunk_size=20,
# chunk_overlap=0,
# keep_separator=True,
# add_start_index=True,
# strip_whitespace=False
# )

# 初始化 SentenceTransformersTokenTextSplitter 类的实例
# 使用 "shibing624/text2vec-base-chinese" 模型,每个分块的最大 token 数为 100,分块重叠部分为 0
splitter = SentenceTransformersTokenTextSplitter(
model_name="shibing624/text2vec-base-chinese",
tokens_per_chunk=100,
chunk_overlap=0)

# 使用 with 语句打开指定路径的文本文件,以 UTF-8 编码读取文件内容
# with 语句会在文件使用完毕后自动关闭文件
with open("../file/report.txt", encoding="utf-8") as f:
# 读取文件的全部内容并存储到 text_content 变量中
text_content = f.read()
# 定义起始和结束标记的数量,后续会从总分词数量中减去该值
count_start_and_stop_tokens = 2
# count_tokens()文本经过Sentence Transformer模型的分词器(Tokenizer)处理后的token数量
# 然后将统计结果减去 count_start_and_stop_tokens 的值
text_token_count = splitter.count_tokens(text=text_content) - count_start_and_stop_tokens
# 打印出处理后的分词数量
print(f"text_token_count:{text_token_count}")
# 调用 splitter 的 split_text 方法将文档内容切割成多个文本块
# 并将结果存储在 texts 列表中
texts = splitter.split_text(text_content)
# 打印出 texts 列表的长度,即切割后的文本块数量
print(f"texts size: {len(texts)}")
# 计算分词倍数,通过每个分块的最大 token 数整除文本的分词数量再加 1 得到
token_multiplier = splitter.maximum_tokens_per_chunk // text_token_count + 1
# 打印出计算得到的分词倍数
print(f"token_multiplier: {token_multiplier}")
# 遍历 texts 列表,打印每个文本块,并使用 50 个连字符进行分隔
for text in texts:
print(text)
print("-" * 50)

使用示例二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from langchain.text_splitter import SentenceTransformersTokenTextSplitter

# 初始化Splitter(默认使用"sentence-transformers/all-mpnet-base-v2"的分词器)
splitter = SentenceTransformersTokenTextSplitter()

text = "你好,世界!Hello world."

# 使用count_tokens计算token数量
token_count = splitter.count_tokens(text)
print(f"Token数量: {token_count}") # 输出:Token数量: 9

# 对比:普通空格分词
word_count = len(text.split())
print(f"空格分词数量: {word_count}") # 输出:空格分词数量: 2(不准确,未考虑标点)

API指南SentenceTransformersTokenTextSplitter

SentenceTransformers 库提供了许多支持中文分词的预训练模型,下面列举一些常用的模型名称,可以将这些名称赋值给 model_name 使用。

模型分词器

多语言通用模型

  • sentence-transformers/paraphrase-multilingual-mpnet-base-v2:在多语言语义相似度任务上表现出色,可用于中文文本的语义理解和对比。
  • sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2:支持多语言的跨语言语义匹配模型。相比前者模型更小、推理速度更快,在保证一定性能的同时能节省资源。
  • sentence-transformers/all-mpnet-base-v2:性能优秀的多语言模型,能生成高质量的句子嵌入。
  • distiluse-base-multilingual-cased-v2:轻量级多语言模型,适合对速度有要求的场景。

中文专用模型

这些模型专门针对中文进行了优化,在中文相关任务上效果更佳。

  • shibing624/text2vec-base-chinese:由中文 NLP 领域专家训练,在中文文本向量化、相似度计算等任务中表现良好。
  • GanymedeNil/text2vec-large-chinese:模型规模较大,有更强大的语义表示能力,适合对精度要求较高的中文任务。

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from langchain_text_splitters import SentenceTransformersTokenTextSplitter

# 使用多语言模型
multilingual_splitter = SentenceTransformersTokenTextSplitter(
model_name="sentence-transformers/paraphrase-multilingual-mpnet-base-v2"
)

# 使用中文专用模型
chinese_splitter = SentenceTransformersTokenTextSplitter(
model_name="shibing624/text2vec-base-chinese"
)

text = "这是一段中文测试文本。"
multilingual_chunks = multilingual_splitter.split_text(text)
chinese_chunks = chinese_splitter.split_text(text)

print("多语言模型分割结果:", multilingual_chunks)
print("中文专用模型分割结果:", chinese_chunks)

执行结果

1
2
多语言模型分割结果: ['这是一段中文测试文本。']
中文专用模型分割结果: ['这 是 一 段 中 文 测 试 文 本 。']

英文专用模型

专门为英文文本设计,在英文任务上通常有更好的表现。

  • all-MiniLM-L6-v2:轻量级英文模型,速度快,适合资源受限的环境。
  • all-roberta-large-v1:较大的英文模型,性能强劲,但推理速度相对较慢。

特定任务模型

针对特定任务进行优化的模型。

  • nli-mpnet-base-v2:在自然语言推理任务上表现出色。
  • quora-distilbert-multilingual:针对问答任务优化的多语言模型。
  • multi-qa-mpnet-base-dot-v1:专门用于语义搜索和问答任务。常用于构建知识库问答系统,比如结合向量数据库进行检索增强生成。主要面向英语,但通过微调可扩展至其他语言场景(如中文问答系统)。
  • distilbert-base-nli-stsb-mean-tokens:适用于微调自定义任务。基于 STS 预训练,微调后相似度计算更准。

NLTK

自然语言工具包(通常简称为NLTK)是一套基于Python编程语言编写的库和程序套件,用于英语的符号化与统计化自然语言处理(NLP)。

与其仅依据**"\n\n"**进行切分,我们可以使用NLTK的分词器进行文本切分。

  • 文本切分方式:通过NLTK分词器(tokenizer)。
  • 区块大小计量方式:依据字符数量。

NLTKTextSplitter

NLTKTextSplitter 是基于自然语言处理库 NLTK 实现的结构化文本分割工具,专为处理英文文本设计。其核心价值在于替代朴素的分隔符切割(如"\n\n"),通过语言学规则实现符合语义逻辑的文本分块

NLTKTextSplitter保留文本语义结构控制信息密度之间取得平衡,成为处理英文文档预处理的标准工具之一。开发者可根据实际需求在字符级精度与计算效率间灵活调整参数。

使用示例

安装依赖

1
# pip install nltk

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 从 langchain_text_splitters 库中导入 NLTKTextSplitter 类
# 该类基于 NLTK(Natural Language Toolkit)实现文本分割功能
from langchain_text_splitters import NLTKTextSplitter

# 创建一个 NLTKTextSplitter 实例
# chunk_size=100 表示每个文本块的最大字符数为 100
# chunk_overlap=0 表示相邻文本块之间没有重叠的字符
text_splitter = NLTKTextSplitter(
chunk_size=100,
chunk_overlap=0,
)

# 使用 with 语句打开位于上级目录 file 文件夹下的 report.txt 文件
# 指定文件编码为 utf-8,确保正确读取包含特殊字符的文本
with open("../file/English.txt", encoding="utf-8") as f:
# 将文件中的全部内容读取到 state_of_the_union 变量中
state_of_the_union = f.read()
# 调用 text_splitter 的 split_text 方法对读取的文本进行分割
# 分割后的文本块存储在 texts 列表中
texts = text_splitter.split_text(state_of_the_union)
# 打印文本块的内容
for text in texts:
print(text)
print("-" * 50)

API指南NLTKTextSplitter

Hugging Face分词器

Hugging Face平台提供多种分词器。

我们采用Hugging Face的GPT2TokenizerFast分词器来统计文本的token数量。

  • 文本切分方式:按传入字符切分
  • 区块大小计量方式:依据Hugging Face分词器计算的token数量

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 从 transformers 库中导入 GPT2 快速分词器类
from transformers import GPT2TokenizerFast

# 加载预训练的 GPT2 分词器,使用官方预训练的 "gpt2" 模型分词器
tokenizer = GPT2TokenizerFast.from_pretrained("gpt2")

# 打开名为 state_of_the_union.txt 的文本文件
with open("../file/report.txt", encoding="utf-8") as f:
# 将文件中的全部内容读取到 state_of_the_union 变量中
state_of_the_union = f.read()

# 从 langchain_text_splitters 库中导入基于字符的文本分割器类
from langchain_text_splitters import CharacterTextSplitter

# 使用 GPT2 分词器创建一个文本分割器实例,指定了模型分词器
# chunk_size=100 表示每个文本块的最大 token 数量为 100
# chunk_overlap=0 表示相邻文本块之间没有重叠的 token
text_splitter = CharacterTextSplitter.from_huggingface_tokenizer(
tokenizer, chunk_size=100, chunk_overlap=0
)

# 调用文本分割器的 split_text 方法,将读取的文本分割成多个文本块
# 分割结果存储在 texts 列表中
texts = text_splitter.split_text(state_of_the_union)

# 打印分割后的第一个文本块的内容
print(texts[0])

API指南CharacterTextSplitter

LangChain:文本切割器如何根据tokens拆分文本

http://blog.gxitsky.com/2025/06/02/AI-LangChain-016-TextSpliter-How/

作者

光星

发布于

2025-06-02

更新于

2025-06-05

许可协议

评论