知识库的创建(2) - make_text_splitter 生成文件分割器


前言

我们一起来详细解析 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)

步骤解析

  1. 默认分割器设置: 如果 splitter_name 未提供,默认使用 SpacyTextSplitter
  2. Markdown 特殊处理: 如果分割器名称是 MarkdownHeaderTextSplitter,则使用特定的头部信息进行分割。
  3. 加载自定义分割器: 尝试加载用户自定义的分割器模块。
  4. 加载默认分割器: 如果自定义分割器不可用,加载 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
                )

步骤解析

  1. tiktoken 分割器: 根据 tiktoken 加载分割器,尝试使用 zh_core_web_sm 管道。
  2. Huggingface 分割器: 根据 Huggingface 模型加载分割器,如果未指定 tokenizer,使用 get_model_worker_config 获取模型路径。
  3. GPT2 分割器: 使用 GPT2 的分词器进行分割。
  4. 字符长度分割器: 使用 Huggingface 的 AutoTokenizer 进行字符长度分割。
  5. 默认处理: 如果以上配置均不可用,则使用默认分割器配置。

四、 异常处理和最终返回

    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

五、步骤解析

  1. 异常处理: 捕获并打印异常,如果上述加载方式失败,使用 RecursiveCharacterTextSplitter 作为默认备选方案。
  2. 返回分割器实例: 返回配置好的文本分割器实例。

六、设计模式

make_text_splitter 方法主要使用了设计模式中的 工厂模式(Factory Method)

1. 工厂模式概述

工厂模式是一种创建型设计模式,它提供了一种创建对象的接口,而不是明确指定具体类。工厂方法将实例化对象的过程延迟到子类或函数实现,使得代码更加灵活和可扩展。

2. 如何体现工厂模式

make_text_splitter 方法通过参数(如 splitter_namechunk_sizechunk_overlapllm_model)来决定具体创建哪种文本分割器实例。这种模式提供了一种统一的接口,用于创建不同类型的文本分割器,而不需要在客户端代码中显式地实例化具体的分割器类。

3. 具体分析

1) 接口统一:
- make_text_splitter 方法提供了一个统一的接口,通过传递不同的参数来创建不同的文本分割器实例。

2) 延迟实例化:
- 文本分割器的实例化过程被延迟到方法内部,根据传入的 splitter_name 动态决定具体的分割器类型。

3) 灵活性和扩展性:
- 通过使用 try...except 结构和动态导入模块,该方法可以根据实际需求加载用户自定义的分割器模块或默认的分割器模块。这使得代码更加灵活,并且易于扩展新的分割器类型。

4) 异常处理:
- 在实例化过程中,如果某些分割器的创建失败,该方法能够捕获异常并提供一个默认的分割器作为备选方案,保证了系统的鲁棒性。

5. 工厂模式的优点

1) 代码复用: 提供了统一的对象创建接口,避免了重复的实例化代码。
2) 扩展性: 可以通过修改或增加参数来扩展新的分割器类型,而不需要修改客户端代码。
3) 解耦: 客户端代码与具体的分割器实现解耦,客户端只需要知道如何使用接口,而不需要了解具体的实现细节。

通过上述分析可以看出,make_text_splitter 方法很好地体现了工厂模式的特点,使得文本分割器的创建过程更加灵活、可扩展和易于维护。

总结

make_text_splitter 方法提供了一种灵活的方式,根据参数动态加载和配置文本分割器。它通过多种方式尝试加载指定的分割器,并处理各种特殊情况和异常,确保最终能够返回一个有效的分割器实例。这种设计极大地提高了文本分割的适应性和鲁棒性,使其能够应对不同的文本分割需求和场景。

相关推荐

  1. 知识库创建(1) - KnowledgeFile文件加载和分割

    2024-06-18 08:44:01       26 阅读
  2. 分享一个简单文件下载

    2024-06-18 08:44:01       32 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-18 08:44:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-18 08:44:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-18 08:44:01       82 阅读
  4. Python语言-面向对象

    2024-06-18 08:44:01       91 阅读

热门阅读

  1. 解析网络空间的安全威胁与应对

    2024-06-18 08:44:01       30 阅读
  2. 11、Spring之Bean生命周期~依赖注入(2)

    2024-06-18 08:44:01       22 阅读
  3. Go微服务: 悲观锁

    2024-06-18 08:44:01       37 阅读
  4. websocket nignx 配置

    2024-06-18 08:44:01       25 阅读
  5. 力扣-2379. 得到 K 个黑块的最少涂色次数

    2024-06-18 08:44:01       33 阅读
  6. 【快速定位生产问题】

    2024-06-18 08:44:01       32 阅读
  7. linux中如何进行yum源的挂载

    2024-06-18 08:44:01       29 阅读
  8. 设计模式生产环境实践------策略模式

    2024-06-18 08:44:01       33 阅读