理解 LangChain 的 RecursiveCharacterTextSplitter

2025-06-04

理解 LangChain 的 RecursiveCharacterTextSplitter

大型语言模型是功能强大的工具,拥有广泛的功能;然而,它们也面临着一个明显的限制,即所谓的“上下文窗口”。这个上下文窗口定义了这些模型能够高效处理文本的边界。例如,GPT-3.5-turbo的运行上下文长度为 4,096 个词条,大约相当于 3,500 个单词。

但是,当你向这些模型呈现超出其上下文窗口的文档时会发生什么?这时,一种名为“分块”的巧妙策略就派上用场了。分块是指将文档划分成更小、更易于管理的部分,使其能够轻松适应大型语言模型的上下文窗口。

Langchain为用户提供了多种分块技术供选择。然而,在这些选项中,RecursiveCharacterTextSplitter是最受欢迎且强烈推荐的方法。

快速概览

该函数RecursiveCharacterTextSplitter接收一段较长的文本,并根据指定的块大小进行拆分。它使用一组字符来实现拆分。默认提供的字符为["\n\n", "\n", " ", ""]

它接收较大的文本,然后尝试按第一个字符 进行拆分\n\n。如果第一个拆分结果\n\n仍然很大,则移动到下一个字符\n,并尝试按该字符进行拆分。如果仍然大于我们指定的块大小,则移动到集合中的下一个字符,直到得到小于我们指定块大小的拆分结果。

代码实现

我的工作内容

2021年2月

上大学之前,课外我主要做的两件事是写作和编程。我不写论文。我写的是当时初学写作的人应该写的东西,现在可能仍然如此:短篇小说。我的小说很糟糕。它们几乎没有情节,只有一些有着强烈情感的人物,我以为这会让它们变得深刻。

我尝试编写的第一个程序是在 IBM 1401 上写的,当时我们学区用它来做当时所谓的“数据处理”。那时我九年级,十三四岁。学区的 1401 恰好在我们初中的地下室,我和我的朋友 Rich Draves 获准使用它。地下室就像一个迷你版的邦德反派老巢,各种看起来像外星人的机器——CPU、磁盘驱动器、打印机、读卡器——都堆放在明亮的荧光灯下的高架地板上。

以上文字摘自Paul Graham撰写的一篇文章,标题为:我的工作内容。让我们利用RecursiveCharacterTextSplitter将其分成小块,每块最多 100 个字符。

首先我们从 langchain 导入它:



from langchain.text_splitter import RecursiveCharacterTextSplitter


Enter fullscreen mode Exit fullscreen mode

我们将想要创建块的文本加载到名为的变量中text



text = """What I Worked On

February 2021

Before college the two main things I worked on, outside of school, were writing and programming. I didn't write essays. I wrote what beginning writers were supposed to write then, and probably still are: short stories. My stories were awful. They had hardly any plot, just characters with strong feelings, which I imagined made them deep.

The first programs I tried writing were on the IBM 1401 that our school district used for what was then called "data processing." This was in 9th grade, so I was 13 or 14. The school district's 1401 happened to be in the basement of our junior high school, and my friend Rich Draves and I got permission to use it. It was like a mini Bond villain's lair down there, with all these alien-looking machines — CPU, disk drives, printer, card reader — sitting up on a raised floor under bright fluorescent lights.
"""


Enter fullscreen mode Exit fullscreen mode

接下来,我们创建一个RecursiveCharacterTextSplitter实例,将其配置为chunk_size100,并将chunk_overlap值设置为零。我们的方法是使用长度函数根据每个块的字符数来测量它。



text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = 100,
    chunk_overlap  = 0,
    length_function = len,
)


Enter fullscreen mode Exit fullscreen mode

提供RecursiveCharacterTextSplitter了几种执行拆分的方法。在本例中,我们将使用split_text方法。此方法需要一个表示文本的字符串输入,并返回一个字符串数组,每个字符串代表拆分后的一个块。



texts = text_splitter.split_text(text)
print(len(texts)) # 11
print(texts[0]) # 'What I Worked On\n\nFebruary 2021'


Enter fullscreen mode Exit fullscreen mode

执行拆分后,我们的文本被成功分成总共 11 个独立的块。

深入解释

递归

正如其名称所示,它RecursiveCharacterTextSplitter使用递归作为实现文本拆分的核心机制。现在,让我们详细了解一下之前的代码是如何实现这一功能的。

在我们的演示中,我们将使用与代码实现过程中相同的文本和参数。这涉及 Paul Graham 文章中的一段,我们将考虑 100 个字符的块大小。我们用于拆分的字符将是['\n\n', '\n', ' ', '' ]

保罗·格雷厄姆的文章

让我们从初始文本开始。目前,它以人类可读的形式呈现,下一步是将其转换为计算机可以轻松理解的格式。

Paul Graham 的计算机论文

现在,新线路已转换为\n,这正是我们进行拆分过程所需要的。

重点介绍 Paul Graham 的文章

让我们选择文本。这可以比作split_text在我们的 上调用方法text

如前所述,它RecursiveCharacterTextSplitter会尝试使用一组预定义的字符来启动拆分。它的第一次尝试涉及\n\n字符,该字符用作按段落拆分的手段。现在让我们在文本中识别出所有出现此字符的位置。

文章中段落的出现

一旦我们找到了所有\n\n字符的实例,下一步就是使用该字符作为指定的分隔符来执行拆分。

按段落拆分文本

目前,我们有四个分片。下一步是评估每个分片,检查它们是否满足小于我们指定的块大小(设置为 100 个字符)的条件。

前两个拆分满足此条件,因此赢得了良好拆分的标签。由于两个片段都包含少于 100 个字符,因此我们可以将它们组合起来以创建初始块。

RecursiveCharacterTextSplitter 的初始块

进行第二次拆分时,我们发现使用\n\n字符无法进一步缩减。因此,我们继续处理下一个字符:\n。我们的目标是使用 字符执行拆分,\n并确定是否可以缩减拆分的大小。

此操作类似于split_text在第二个拆分文本上调用,但包含字符\n。这就是递归概念发挥作用的地方。

第二块

使用字符执行拆分后\n,我们得到了两个拆分。第一个拆分由于只包含一个字符,因此算是一个好的拆分。然而,第二个拆分超出了我们指定的块大小。

因此,我们需要split_text再次对这个特定的拆分调用该方法。不过,这次我们将使用字符列表中的下一个字符(恰好是该' '字符)进行拆分。

使用空格的 RecursiveCharacterTextSplitter

最终,我们成功减小了分片大小。现在,我们继续迭代每个分片以执行合并。合并的指导原则是,合并后的分片大小不得超过我们指定的 100 个字符的块大小。

合并列表

合并后,我们得到四个块,每个块都遵循我们的条件,即每个块不应超过 100 个字符。

现在,让我们重新审视原始文本分割并确定哪些分割仍有待处理。

RecursiveCharacterTextSplitter 中的最后一个块

我们仍然有一个分片大于我们的块大小。我们再次重复相同的步骤。

使用 RecursiveCharacterTextSplitter 执行拆分

我们使用换行符作为分隔符来开始分割。

使用空格通过 RecursiveCharacterTextSplitter 执行拆分

我们使用空格作为分隔符进行拆分。

使用 RecursiveCharacterTextSplitter 执行合并

接下来,我们进行合并,确保合并的段不超过定义的块大小。

经过整个流程,我们最终生成了 11 个独立的区块。这 11 个区块均成功遵守了 100 个字符的限制。
这一结果与我们通过编程实现的结果完全一致。

使用 RecursiveCharacterTextSplitter 的最终块


就这样,我们深入探究了 LangChain 的内部工作原理RecursiveCharacterTextSplitter。感兴趣的朋友可以点击此处探索源代码。如果您觉得本文内容丰富,请点赞:💖 🦄 🤯 🙌 🔥

文章来源:https://dev.to/eteimz/understanding-langchains-recursivecharactertextsplitter-2846
PREV
国际公司在多个领域提供的在线课程(免费) Online_courses #international_companies #certification #Google #IBM #Microsoft #Amazon #Huawei #VMware #Red Hat #Oracle #Nvidia #Cisco #hp #Dell #Facebook #Linkedin #Pluralsight #Technology_Innovation #tech #tech_fady #learn_from_fady #listen_and_learn_from_fady
NEXT
5 Great Programming Books Rarely Mentioned in "Great Programming Books" Articles The Usual Suspects 1. Practical Object-Oriented Design: An Agile Primer Using Ruby 2. Test-Driven Development with Python (aka, Obey the Testing Goat) 3. Functional Programming in C# 4. 24 Deadly Sins of Software Security: Programming Flaws and How to Fix Them 5. Agile Testing: A Practical Guide for Testers and Agile Teams Conclusion