(17-3-01)检索增强生成(RAG):Recursively文本分割器
Text Splitters作为一种处理与转换文档的设备,在LangChain中被广泛采用。它能够辅助开发者将长文档划分为更小且具有语义意义的片段,并以适应我们的应用程序或模型所涉及的具体上下文窗口。
5.3 文本分割器(Text Splitters)
文本分割器(Text Splitting Mechanism)是LangChain中用于将文档进行处理和转换的工具,能够将长文档分割成较小的块,并为我们的应用程序或模型的需求提供适应性的支持。
5.3.1 文本分割器介绍
文本分割器有助于提升文档的可管理性,在涉及将文本输入至具有特定字符限制的语言模型时尤其实用。特别适用于那些要求输入文本长度受限的语言模型。文本分割器的工作原理如下所示。
- 将文本划分为具有意义的小单元。
- 逐步合并这些单元形成较大的段落,并基于特定标准确定截止点。
- 当达到指定长度时,则将其视为独立的段落,并启动新的分段工作。
在LangChain的包langchain-text-splitters中包含多种文本分割工具,请具体信息如下。
- Recursive 分割器:通过递归机制将相关文本进行整合。
- HTML 分割器:根据 HTML 标签或特殊字符进行划分,并附加每个块的来源信息。
- Markdown 分割器:根据 Markdown 标签和语法元素进行划分,并提供来源信息。
- Code 分割器(Code):基于编程语言特定字符划分,并支持超过 15 种编程语言。
- Token 分割器(Token):根据预定义标记进行划分,并采用多种评估标准来衡量结果。
- Char 分割器(Character):这是最简单的分隔方法之一。
- 实验性语义分段工具(Semantic Chunker):首先按句子分段,在结合足够语义相似度的相邻段落生成最终片段集;参考文献 Greg Kamradt.
- AI21 智能文本分段系统 (AI21 Semantic Text Splitter):识别不同主题内容块并沿这些主题切割文字段落;附加每个块的相关上下文信息
5.3.2 Recursively文本分割器
在LangChain中, RecursiveCharacterTextSplitter 是 LangChain 框架中的一个专门用于文本分割的工具,其主要功能是将长段落划分为较小且易于处理的部分.该分割器采用递归方式应用字符分隔符列表,从而实现对输入文本的有效切割.其核心设计理念在于最大限度地维持原始文本中的语义关联性,具体表现为倾向于将整段落、句子及单词等语义单位保留在同一划分结果中.
RecursiveCharacterTextSplitter有如下两种文本分割方式:
- 按字符列表分割:RecursiveCharacterTextSplitter 基于一个字符序列集合来进行文本分割,默认的分隔符集合为 ["\n\n", "\n", " ", ""], 这意味着它会首先尝试在两个空行、一个空行、空格和制表符之间进行分割。
- 块大小的度量:文本块大小是以字符数量作为衡量标准来确定的。
下面将展示一个实例:采用LangChain框架中的RecursiveCharacterTextSplitter工具对一个长文本文件(某国的国情咨文文件state_of_the_union.txt)进行处理。该分割器通过递归方式在字符层面上进行处理,直至达到预设的块大小。
案例编号5-1:利用RecursiveCharacterTextSplitter进行长文本文件的分割操作(源码路径位于codes文件夹中的第5个子目录fen01.py)
实例文件fen01.py的具体实现代码如下所示。
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 这是一个我们可以分割的长文本。
with open("state_of_the_union.txt") as f:
state_of_the_union = f.read()
text_splitter = RecursiveCharacterTextSplitter(
# 设置一个非常小的块大小,仅作展示。
chunk_size=100,
chunk_overlap=20,
length_function=len,
is_separator_regex=False,
)
texts = text_splitter.create_documents([state_of_the_union])
print(texts[0])
print(texts[1])
上述代码的实现流程如下所示:
解析文本文件:通过与open语句交互解析state_of_the_union.txt文件的内容,并将其存储到变量state_of_the_union中。
(2)生成分割器实例:生成RecursiveCharacterTextSplitter实例,并将其参数设置为所需值。
- segment_size=100:将每个文本块的目标大小设置为100个字符。
- chunk_overlap=20:规定相邻段落之间的重叠数量设为20个字符。
- length_function=len:采用Python内置函数len来计算字符数量。
- is_separator_regex=False:选择不使用正则表达式而直接进行字符串匹配。
通过调用 create_documents 方法,并将获取的国情咨文文本作为输入传递进去,在按照指定的参数划分后,生成多个独立的文本块。
执行打印操作以显示分隔后的第一条和第二条文本片段。因为 create_documents 函数返回了一个文档列表,在其中每个元素对应一个文本片段。分别使用 print 函数调用 texts[0] 和 texts[1] 展示第一条和第二条文档的内容。
执行后会输出:
page_content='Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and'
page_content='of Congress and their families, the Cabinet, and distinguished guests: three years ago, we gathered'
该处的输出即为生成并打印分段后第一段和第二段的部分内容。其中每段不超过100个字符,并且相邻两段之间保留有20个字符的内容重复。这种处理方式旨在通过重复信息来保证内容连贯性及上下文完整性。
在实际应用环境中, 当应用于中文、日文和泰文等没有明显单词边界的书写系统时, 使用默认设置生成的结果可能会导致无法识别出自然段落边界的问题。为了避免这种情况, 可以替换现有的分隔符设置, 包括更多适用于这类语言的标点符号, 这一做法的具体说明了这一方法的应用场景。通过修改RecursiveCharacterTextSplitter算法参数, 使其更适合这些语言的特点, 具体来说就是增加更多的适用标点符号设置, 这样就可以有效避免将词语拆分成不连贯的部分。
实例5-4:分割中文内容的文本(源码路径:codes*5*fen04.py******)****
实例文件fen04.py的具体实现代码如下所示。
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 假设我们有以下中文文本
chinese_text = """
“孔子曰:‘学而时习之,不亦说乎?有朋自远方来,不亦乐乎?人不知而不愠,不亦君子乎?’”
孔子强调学习的重要性,并且强调了学以致用的理念。他认为不断地学习和实践是一种快乐,同时也提倡了宽容包容、不以小人之见而忧愤的胸怀。这表达了孔子的教育理念和人生态度。
“曾子曰:‘吾日三省吾身:为人谋而不忠乎?与朋友交而不信乎?传不习乎?’”
曾子是孔子的学生之一,他在这段话中表达了对自我反省和修养的追求。他提出了自我审问的三个问题:是否对他人真诚,是否对朋友诚信,是否不断学习不断进步。这反映了儒家强调修身养德的核心价值观。
“子曰:‘温故而知新,可以为师矣。’”
孔子认为,通过温习过去的知识和经验,才能够更好地理解和把握新知识,因此可以成为他人的良师益友。这体现了孔子对于教育的理念,即尊重传统、融会贯通,使之能够应用于当下的实际生活。
“子曰:‘学而不思则罔,思而不学则殆。’”
孔子强调了学习和思考的相辅相成。他认为,单纯地学习而不进行思考,会导致知识的空泛和浅薄;而单纯地思考而不进行学习,则会陷入无法确证的迷茫之中。这句话鼓励人们在学习过程中注重思考,反思和总结经验,以求得真知。
“子曰:‘知之者不如好之者,好之者不如乐之者。’”
孔子强调了对于学识、道德、美德等的追求应该是一种内心的热爱和欢愉。他认为,仅仅是拥有知识还不足以体现一个人的价值,真正有价值的是能够将知识转化为行动,并从中获得愉悦和满足。
"""
# 创建 RecursiveCharacterTextSplitter 实例,添加适合中文的分隔符
text_splitter = RecursiveCharacterTextSplitter(
separators=["\n", "。", ",", ";", "!", "?", " "],
chunk_size=200, # 设置合适的块大小
chunk_overlap=50, # 设置合适的重叠大小
length_function=len,
is_separator_regex=False,
)
# 分割中文文本
chinese_splits = text_splitter.split_text(chinese_text)
# 打印第一个文本块
print(chinese_splits[0][:200])
# 在尝试打印第二个文本块之前检查是否有多个块
if len(chinese_splits) > 1:
print(chinese_splits[1][:200]) # 打印第二个文本块的前200个字符
else:
print("没有足够的文本块可供打印。")
在给定的代码中,定义了一个名为chinese_text的变量,并且该变量存储了一段中文文本。随后初始化了一个RecursiveCharacterTextSplitter实例,并配置了一个适合处理中文文本的分隔符集合。通过这种方式,在对文本进行分割时,分隔器会特别关注标点符号的位置,并尽力避免在词语内部进行切分。运行该代码块后将输出以下内容:
“孔子曰:‘学而时习之,不亦说乎?有朋自远方来,不亦乐乎?人不知而不愠,不亦君子乎?’”
孔子强调学习的重要性,并且强调了学以致用的理念。他认为不断地学习和实践是一种快乐,同时也提倡了宽容包容、不以小人之见而忧愤的胸怀。这表达了孔子的教育理念和人生态度。
“曾子曰:‘吾日三省吾身:为人谋而不忠乎?与朋友交而不信乎?传不习乎?’”
“曾子曰:‘吾日三省吾身:为人谋而不忠乎?与朋友交而不信乎?传不习乎?’”
曾子是孔子的学生之一,他在这段话中表达了对自我反省和修养的追求。他提出了自我审问的三个问题:是否对他人真诚,是否对朋友诚信,是否不断学习不断进步。这反映了儒家强调修身养德的核心价值观。
“子曰:‘温故而知新,可以为师矣。’”
RecursiveCharacterTextSplitter分割器专为处理冗长文本字符数有限的模型或系统设计。在这些应用中使用该分割器能够有效地将冗长内容划分为适当大小的部分,并尽量减少潜在信息损失。
