(17-3-01)检索增强生成(RAG):Recursively文本分割器

文本分割器(Text Splitters)是 LangChain 中用于处理和转换文档的工具,可以帮助开发者将长文档分割成更小的、语义上有意义的块,以适应我们的应用程序或模型的上下文窗口。

5.3  文本分割器(Text Splitters)

文本分割器(Text Splitters)是 LangChain 中用于处理和转换文档的工具,可以帮助开发者将长文档分割成更小的、语义上有意义的块,以适应我们的应用程序或模型的上下文窗口。

5.3.1  文本分割器介绍

文本分割器使得文档更容易被处理和分析,尤其是在需要将文本输入到具有特定长度限制的语言模型时。文本分割器的工作原理如下所示。

  1. 将文本分割成小的、语义上有意义的块(通常是句子)。
  2. 开始将这些小块组合成较大的块,直到达到一定的大小(通过某种函数来衡量)。
  3. 一旦达到该大小,就将该块作为自己的文本片段,并开始创建一个新的文本块,同时保持一定的重叠(以保持块之间的上下文联系)。

在LangChain的包langchain-text-splitters中提供了多种文本分割器,具体说明如下所示。

  1. 递归分割器(Recursive):递归地分割文本,尝试将相关文本放在一起。这是开始分割文本的推荐方式。
  2. HTML分割器:基于 HTML 特定字符分割文本。会添加关于每个块来源的相关信息。
  3. Markdown分割器:基于 Markdown 特定字符分割文本。同样会添加来源信息。
  4. 代码分割器(Code):基于编程语言(如 Python、JS)特定字符分割文本。支持 15 种不同的编程语言。
  5. 标记分割器(Token):基于标记分割文本。有几种不同的衡量标记的方法。
  6. 字符分割器(Character):基于用户定义的字符分割文本。这是最简单的方法之一。
  7. [实验性] 语义分割器(Semantic Chunker):首先基于句子分割,然后结合足够语义相似的相邻句子。来自 Greg Kamradt。
  8. AI21 语义文本分割器(AI21 Semantic Text Splitter):识别形成连贯文本片段的不同主题,并沿这些主题进行分割。会添加关于每个块来源的相关信息。

5.3.2  Recursively文本分割器

在LangChain中,RecursiveCharacterTextSplitter 是 LangChain 框架中的一个文本分割器,专门用于将长文本分割成更小的、易于处理的块。RecursiveCharacterTextSplitter通过递归应用字符分隔符列表来分割文本,直到文本块达到指定的大小为止。它的设计目的是尽可能地保持文本的语义相关性,例如,它会尝试将整个段落、句子和单词保持在一起,因为这些通常是文本中最具有语义关联的部分。

RecursiveCharacterTextSplitter有如下两种文本分割方式:

  1. 按字符列表分割:RecursiveCharacterTextSplitter 使用一个字符序列列表来进行文本分割。默认的分隔符列表是 ["\n\n", "\n", " ", ""], 这意味着它会首先尝试在两个空行、一个空行、空格和制表符之间进行分割。
  2. 块大小的度量:文本块的大小是按照字符数来衡量的。

请看下面的例子,使用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])

上述代码的实现流程如下所示:

(1)读取文本文件:使用 with open 语句打开并读取 state_of_the_union.txt 文件的内容,将其存储在变量 state_of_the_union 中。

(2)创建分割器实例:实例化 RecursiveCharacterTextSplitter,设置以下参数:

  1. chunk_size=100:每个文本块的目标大小为100个字符。
  2. chunk_overlap=20:相邻文本块之间的重叠字符数为20。
  3. length_function=len:使用Python的内置 len 函数来计算字符数。
  4. is_separator_regex=False:不将分隔符作为正则表达式处理,而是直接作为字符串匹配。

(3)分割文本:调用 create_documents 方法,传入读取的国情咨文文本,分割器会根据设置的参数将其分割成多个文本块。

(4)打印分割结果:打印分割后的第一个和第二个文本块。由于 create_documents 返回的是一个文档列表,每个文档包含一个文本块,print(texts[0]) 和 print(texts[1]) 分别输出第一个和第二个文档的 page_content。

执行后会输出:

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分割器特别适用于需要将长文本输入到有输入长度限制的模型或系统中的场景,例如自然语言处理模型。通过这种方式,可以确保文本被分割成合适大小的块,同时尽量减少语义上的断裂。

  • 12
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值