文本分割器#
在本教程中,我们将讨论:
文本分割器概述
它是如何工作的
如何使用它
分块技巧
与其他文档类型的集成和自定义技巧
文本分割器概述#
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!"]
类型 2: 使用
core.tokenizer.Tokenizer。它的工作原理如下:
"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_by、chunk_size与chunk_overlap如何工作的示例。
输入文档文本:
Hello, this is adalflow. Please implement your splitter here.
按分割 |
块大小 |
块重叠 |
结果块 |
|---|---|---|---|
单词 |
5 |
2 |
“你好,这是adalflow。请”, “adalflow。请实现你的分割器”, “你的分割器在这里。” |
句子 |
1 |
0 |
“你好,这是adalflow。”, “请在这里实现你的分割器。” |
token |
5 |
2 |
“你好,这是 l”, “是 adalflow。”, “trag. 请实现你的”, “在这里实现你的分割器。” |
当使用chunk_size = 5和chunk_overlap = 2按word分割时,
每个块将重复前一个块的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,开发者需要在使用分割器之前提取文本。可以使用像PyPDF2或PDFMiner这样的库来实现这一目的。
AdalFlow的未来实现将引入用于JSON、HTML、markdown和code的分割器。
自定义技巧#
您还可以自定义SEPARATORS。例如,通过定义SEPARATORS = {"question": "?"} ``和 设置 ``split_by = "question",文档将在每个?处分割,非常适合处理结构化为一系列问题的文本。如果您需要自定义core.tokenizer.Tokenizer,请查看参考。