文本分割器#

在本教程中,我们将讨论:

  1. 文本分割器概述

  2. 它是如何工作的

  3. 如何使用它

  4. 分块技巧

  5. 与其他文档类型的集成和自定义技巧

文本分割器概述#

LLMs的上下文窗口是有限的,当输入非常长且无意义时,性能通常会下降。 较短的内容更易于管理,并且符合内存限制。 TextSplitter的目标是将大数据分割成较小的部分,可能提高嵌入和检索的效率。

TextSplitter 旨在高效处理和分块纯文本。 它利用可配置的分隔符来促进将document object分割成更小、更易管理的文档块。

它是如何工作的#

TextSplitter 首先使用 split_by 来指定文本分割标准,并将长文本分割成较小的文本。 然后我们创建一个滑动窗口,length= chunk_size。它以 step= chunk_size - chunk_overlap 的步长移动。 每个窗口内的文本将被合并成一个较小的块。从分割的文本生成的块将被返回。

分割类型#

TextSplitter 支持两种类型的分割。 以下是示例,您将在使用部分看到 TextSplitter 的实际输出。

  • 类型1: 指定确切的文本分割点,例如空格<” “>和句点<”.”>。例如,如果您设置 split_by = "word",您将得到:

"Hello, world!" -> ["Hello, " ,"world!"]
"Hello, world!" -> ["Hello", ",", " world", "!"]

分词与模型如何以标记形式查看文本对齐(参考)。当您的嵌入模型对标记效果更好,或者您将数据块输入到对标记限制敏感的LLM模型时,请考虑使用分词。

注意

Tokenizer反映了模型实际接收的token数量,并帮助开发者控制预算。

定义#

  • split_by 指定了分割规则,即分割时的最小单位。我们支持 "word", "sentence", "page", "passage", 和 "token"。分割器使用 SEPARATORS 字典中的相应分隔符。

对于类型1的分割,我们应用Python str.split()来拆分文本。

  • 分隔符: 将split_by标准映射到它们的确切文本分隔符,例如,空格<” “>用于“单词”或句点<”.”>用于“句子”。

注意

对于选项token,其分隔符为“”,因为我们直接通过分词器进行分割,而不是特定的文本点。

  • chunk_size 是每个块中的最大单位数。要找出最适合您的 chunk_size,您可以首先预处理您的原始数据,选择一个 chunk_size 的范围,然后使用一组查询在您的用例上运行评估。

  • chunk_overlap 是每个块应该重叠的单位数。在边界处包含上下文可以防止句子/上下文之间的文本意义突然变化,特别是在情感分析中。

以下是split_bychunk_sizechunk_overlap如何工作的示例。

输入文档文本:

Hello, this is adalflow. Please implement your splitter here.
Chunking Example Detailed#

按分割

块大小

块重叠

结果块

单词

5

2

“你好,这是adalflow。请”, “adalflow。请实现你的分割器”, “你的分割器在这里。”

句子

1

0

“你好,这是adalflow。”, “请在这里实现你的分割器。”

token

5

2

“你好,这是 l”, “是 adalflow。”, “trag. 请实现你的”, “在这里实现你的分割器。”

当使用chunk_size = 5chunk_overlap = 2word分割时, 每个块将重复前一个块的2个单词。这2个单词由chunk_overlap设置。 这意味着每个块与其前一个块相比有5-2=3个单词(分割单位)的差异。

当使用分词器进行分割时,每个块仍然保留5个标记。 例如,分词器将adalflow转换为[‘l’, ‘igh’, ‘trag’]。因此,第二个块实际上是is + l + igh + trag + .

注意

chunk_overlap 应始终小于 chunk_size,否则窗口将不会移动,分割会卡住。 我们的默认分词模型是 cl100k_base。如果您使用分词(split_by = token),标点符号也会被视为分词。

如何使用它#

你需要的是以这种方式指定参数并输入你的文档:

按单词分割#

from adalflow.components.data_process.text_splitter import TextSplitter
from adalflow.core.types import Document

# Configure the splitter settings
text_splitter = TextSplitter(
    split_by="word",
    chunk_size=5,
    chunk_overlap=1
)

# Example document
doc = Document(
    text="Example text. More example text. Even more text to illustrate.",
    id="doc1"
)

# Execute the splitting
splitted_docs = text_splitter.call(documents=[doc])

for doc in splitted_docs:
    print(doc)

# Output:
# Document(id=44a8aa37-0d16-40f0-9ca4-2e25ae5336c8, text='Example text. More example text. ', meta_data=None, vector=[], parent_doc_id=doc1, order=0, score=None)
# Document(id=ca0af45b-4f88-49b5-97db-163da9868ea4, text='text. Even more text to ', meta_data=None, vector=[], parent_doc_id=doc1, order=1, score=None)
# Document(id=e7b617b2-3927-4248-afce-ec0fc247ac8b, text='to illustrate.', meta_data=None, vector=[], parent_doc_id=doc1, order=2, score=None)

按标记分割#

from adalflow.components.data_process.text_splitter import TextSplitter
from adalflow.core.types import Document
import tiktoken

# Configure the splitter settings
text_splitter = TextSplitter(
    split_by="token",
    chunk_size=5,
    chunk_overlap=0
)

doc = Document(
    text="Example text. More example text. Even more text to illustrate.",
    id = "doc1"
    )

splitted_docs = (text_splitter.call(documents=[doc]))

for doc in splitted_docs:
    print(doc)

# Output:
# Document(id=27cec433-b400-4f11-8871-e386e774d150, text='Example text. More example', meta_data=None, vector=[], parent_doc_id=doc1, order=0, score=None)
# Document(id=8905dc5f-8be5-4ca4-88b1-2ae492258b53, text=' text. Even more text', meta_data=None, vector=[], parent_doc_id=doc1, order=1, score=None)
# Document(id=ba8e1e23-82fb-4aa8-bfc5-e22084984bb9, text=' to illustrate.', meta_data=None, vector=[], parent_doc_id=doc1, order=2, score=None)

分块技巧#

选择合适的分块策略需要考虑几个关键因素:

  • 内容类型: 根据特定的内容类型调整你的分块方法,例如文章、书籍、社交媒体帖子或基因序列。

  • 嵌入模型: 选择与您的嵌入模型训练相匹配的分块方法以优化性能。例如,基于句子的分块与sentence-transformer模型配合良好,而基于标记的分块则非常适合OpenAI的text-embedding-ada-002

  • 查询动态: 查询的长度和复杂性应影响您的分块策略。对于缺乏详细规范且需要广泛上下文的较短查询,较大的块可能更合适,而对于更具体的较长查询,更细的粒度可能会提高准确性。

  • 结果的应用: 应用场景,无论是语义搜索、问答系统还是摘要生成,决定了适当的分块方法,特别是考虑到大型语言模型(LLMs)中内容窗口的限制。

  • 系统集成:高效的分块与系统能力相匹配。例如,全文搜索:使用较大的块,使算法能够有效地探索更广泛的上下文。例如,根据大量摘录或章节搜索书籍。细粒度搜索系统:使用较小的块,精确检索与用户查询相关的信息,例如直接响应用户问题检索特定指令。例如,如果用户问“如何重置我的密码?”,系统可以直接检索到解决该操作的具体句子或段落。

分块策略#

固定大小的分块#

  • 非常适合需要统一块大小的内容,如基因序列或标准化数据条目。这种方法将文本分割成大小相等的单词块,简单高效,但可能会损害语义连贯性,并有可能破坏重要的上下文联系。

内容感知分块#

  • 按句子分割: 适用于需要对完整句子进行深入理解的文本,如学术文章或医学报告。此方法保持语法的完整性和上下文的流畅性。

  • 按段落分割: 对于保持大型文档的结构和连贯性非常有用。通过专注于特定的文本部分,支持详细的任务,如问答和摘要。

  • 按页分割: 对于每页包含不同信息的大型文档(如法律或学术文本)非常有效,有助于精确导航和信息提取。

基于令牌的分割#

  • 适用于嵌入模型有严格令牌限制的场景。此方法根据令牌计数划分文本,优化与GPT等LLMs的兼容性,尽管由于模型的复杂性可能会减慢处理速度。

即将推出的分割功能#

  • 语义分割: 专注于根据意义而非结构对文本进行分组,增强主题搜索或高级上下文检索任务的相关性。

如果您使用的策略不基于分词器,请在将数据块输入模型时注意您的标记长度。

与其他文档类型的集成#

此功能非常适合将文本分割成句子、单词、页面或段落,然后可以进一步处理用于NLP应用。 对于PDFs,开发者需要在使用分割器之前提取文本。可以使用像PyPDF2PDFMiner这样的库来实现这一目的。 AdalFlow的未来实现将引入用于JSONHTMLmarkdowncode的分割器。

自定义技巧#

您还可以自定义SEPARATORS。例如,通过定义SEPARATORS = {"question": "?"} ``和 设置 ``split_by = "question",文档将在每个?处分割,非常适合处理结构化为一系列问题的文本。如果您需要自定义core.tokenizer.Tokenizer,请查看参考