文章目录
前言
我们一起来详细解析 make_text_splitter
方法
在自然语言处理和文本分析中,文本分割是一项重要的任务,尤其是当处理大型文档或连续文本时。make_text_splitter
方法提供了一种灵活且可定制的方式,根据参数获取特定的文本分割器。本文将详细解析该方法的各个部分。
一、 方法定义和参数
def make_text_splitter(
splitter_name: str = TEXT_SPLITTER_NAME,
chunk_size: int = CHUNK_SIZE,
chunk_overlap: int = OVERLAP_SIZE,
llm_model: str = LLM_MODELS[0],
):
"""
根据参数获取特定的分词器
"""
参数解析
splitter_name
: 分割器的名称,默认为TEXT_SPLITTER_NAME
。chunk_size
: 每个文本块的大小,默认为CHUNK_SIZE
。chunk_overlap
: 文本块之间的重叠部分,默认为OVERLAP_SIZE
。llm_model
: 使用的语言模型,默认为LLM_MODELS[0]
。
该方法旨在根据给定的参数获取特定的文本分割器实例,以便后续对文本进行分割操作。
二、 分割器选择逻辑
splitter_name = splitter_name or "SpacyTextSplitter"
try:
if splitter_name == "MarkdownHeaderTextSplitter": # MarkdownHeaderTextSplitter特殊判定
headers_to_split_on = text_splitter_dict[splitter_name]['headers_to_split_on']
text_splitter = langchain.text_splitter.MarkdownHeaderTextSplitter(
headers_to_split_on=headers_to_split_on)
else:
try: ## 优先使用用户自定义的text_splitter
text_splitter_module = importlib.import_module('text_splitter')
TextSplitter = getattr(text_splitter_module, splitter_name)
except: ## 否则使用langchain的text_splitter
text_splitter_module = importlib.import_module('langchain.text_splitter')
TextSplitter = getattr(text_splitter_module, splitter_name)
步骤解析
- 默认分割器设置: 如果
splitter_name
未提供,默认使用SpacyTextSplitter
。 - Markdown 特殊处理: 如果分割器名称是
MarkdownHeaderTextSplitter
,则使用特定的头部信息进行分割。 - 加载自定义分割器: 尝试加载用户自定义的分割器模块。
- 加载默认分割器: 如果自定义分割器不可用,加载
langchain
库中的分割器。
三、 文本分割器的详细配置
if text_splitter_dict[splitter_name]["source"] == "tiktoken": ## 从tiktoken加载
try:
text_splitter = TextSplitter.from_tiktoken_encoder(
encoding_name=text_splitter_dict[splitter_name]["tokenizer_name_or_path"],
pipeline="zh_core_web_sm",
chunk_size=chunk_size,
chunk_overlap=chunk_overlap
)
except:
text_splitter = TextSplitter.from_tiktoken_encoder(
encoding_name=text_splitter_dict[splitter_name]["tokenizer_name_or_path"],
chunk_size=chunk_size,
chunk_overlap=chunk_overlap
)
elif text_splitter_dict[splitter_name]["source"] == "huggingface": ## 从huggingface加载
if text_splitter_dict[splitter_name]["tokenizer_name_or_path"] == "":
config = get_model_worker_config(llm_model)
text_splitter_dict[splitter_name]["tokenizer_name_or_path"] = \
config.get("model_path")
if text_splitter_dict[splitter_name]["tokenizer_name_or_path"] == "gpt2":
from transformers import GPT2TokenizerFast
from langchain.text_splitter import CharacterTextSplitter
tokenizer = GPT2TokenizerFast.from_pretrained("gpt2")
else: ## 字符长度加载
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(
text_splitter_dict[splitter_name]["tokenizer_name_or_path"],
trust_remote_code=True)
text_splitter = TextSplitter.from_huggingface_tokenizer(
tokenizer=tokenizer,
chunk_size=chunk_size,
chunk_overlap=chunk_overlap
)
else:
try:
text_splitter = TextSplitter(
pipeline="zh_core_web_sm",
chunk_size=chunk_size,
chunk_overlap=chunk_overlap
)
except:
text_splitter = TextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap
)
步骤解析
- tiktoken 分割器: 根据
tiktoken
加载分割器,尝试使用zh_core_web_sm
管道。 - Huggingface 分割器: 根据 Huggingface 模型加载分割器,如果未指定 tokenizer,使用
get_model_worker_config
获取模型路径。 - GPT2 分割器: 使用 GPT2 的分词器进行分割。
- 字符长度分割器: 使用 Huggingface 的
AutoTokenizer
进行字符长度分割。 - 默认处理: 如果以上配置均不可用,则使用默认分割器配置。
四、 异常处理和最终返回
except Exception as e:
print(e)
text_splitter_module = importlib.import_module('langchain.text_splitter')
TextSplitter = getattr(text_splitter_module, "RecursiveCharacterTextSplitter")
text_splitter = TextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
# If you use SpacyTextSplitter you can use GPU to do split likes Issue #1287
# text_splitter._tokenizer.max_length = 37016792
# text_splitter._tokenizer.prefer_gpu()
return text_splitter
五、步骤解析
- 异常处理: 捕获并打印异常,如果上述加载方式失败,使用
RecursiveCharacterTextSplitter
作为默认备选方案。 - 返回分割器实例: 返回配置好的文本分割器实例。
六、设计模式
make_text_splitter
方法主要使用了设计模式中的 工厂模式(Factory Method)。
1. 工厂模式概述
工厂模式是一种创建型设计模式,它提供了一种创建对象的接口,而不是明确指定具体类。工厂方法将实例化对象的过程延迟到子类或函数实现,使得代码更加灵活和可扩展。
2. 如何体现工厂模式
make_text_splitter
方法通过参数(如 splitter_name
、chunk_size
、chunk_overlap
和 llm_model
)来决定具体创建哪种文本分割器实例。这种模式提供了一种统一的接口,用于创建不同类型的文本分割器,而不需要在客户端代码中显式地实例化具体的分割器类。
3. 具体分析
1) 接口统一:
- make_text_splitter
方法提供了一个统一的接口,通过传递不同的参数来创建不同的文本分割器实例。
2) 延迟实例化:
- 文本分割器的实例化过程被延迟到方法内部,根据传入的 splitter_name
动态决定具体的分割器类型。
3) 灵活性和扩展性:
- 通过使用 try...except
结构和动态导入模块,该方法可以根据实际需求加载用户自定义的分割器模块或默认的分割器模块。这使得代码更加灵活,并且易于扩展新的分割器类型。
4) 异常处理:
- 在实例化过程中,如果某些分割器的创建失败,该方法能够捕获异常并提供一个默认的分割器作为备选方案,保证了系统的鲁棒性。
5. 工厂模式的优点
1) 代码复用: 提供了统一的对象创建接口,避免了重复的实例化代码。
2) 扩展性: 可以通过修改或增加参数来扩展新的分割器类型,而不需要修改客户端代码。
3) 解耦: 客户端代码与具体的分割器实现解耦,客户端只需要知道如何使用接口,而不需要了解具体的实现细节。
通过上述分析可以看出,make_text_splitter
方法很好地体现了工厂模式的特点,使得文本分割器的创建过程更加灵活、可扩展和易于维护。
总结
make_text_splitter
方法提供了一种灵活的方式,根据参数动态加载和配置文本分割器。它通过多种方式尝试加载指定的分割器,并处理各种特殊情况和异常,确保最终能够返回一个有效的分割器实例。这种设计极大地提高了文本分割的适应性和鲁棒性,使其能够应对不同的文本分割需求和场景。