当前位置:   article > 正文

RAG 为什么需要文本分割(Chunking)_文本切片策略在rag中的重要性

文本切片策略在rag中的重要性

Picone上的一个博客,翻译过来学习一下,其中加入了一些个人的理解和调整,有兴趣更深入研究的可以看一下文章的原文。

为什么需要文本分割(Chunking)

在构建与LLM相关的应用程序时,Chunking是将大量文本分解为较小段的过程。这是很重要的一环,有助于优化从向量数据库中获得的LLM上下文嵌入内容的相关性。在这篇文章中,我们将探讨它是否以及如何有助于提高与LLM相关的应用程序中的效率和准确性。

如我们所知,我们在Pinecone中索引的任何内容都需要先进行嵌入(Embedded)。Chunking的主要目的是对上下文中的一个片段进行嵌入的过程中尽可能少的噪声,而还要保证内容仍然与语义相关。

例如,在语义搜索场景中,我们为一个文档集建立索引,每个文档都包含有关特定主题的宝贵信息。通过采用有效的分块(chunk)策略,可以确保搜索结果准确匹配用户查询的本意。如果我们的块太小会导致错过真正的相关内容,太大则可能导致搜索结果不准确。一般来说,如果一段文字脱离语境的上下文,对于人类来说仍然可以理解其含义,那么这段文字对于语言模型来说也是可以理解。因此,确定语料库中文档的最佳块大小对提高搜索结果准确性和相关性是非常重要的。

再举一个会话智能体(conversational agents)的例子(之前用Python和Javascript解释过)。使用知识库中嵌入的文本段构建一个让会话智能体使用的知识上下文。这种情况下,必须要对这些文本段作出正确的选择。有两个原因:

  • 首先,这决定嵌入的知识是否与我们的Prompt相关(Prompt中会嵌入真正的的用户问题)。
  • 其次,检索到文本的大小决定了我们是否能够将嵌入到要发送的上下文中传递给外部模型提供商(例如OpenAI),因为每个模型支持的发送Token的数量是有限的。 例如使用有32k上下文窗口的GPT-4,文本切分的问题可能不大。然而,在使用非常大的文本块时,仍需要谨慎处理,因为这可能对从Pinecone得到的结果的相关性产生负面影响。

这篇文章中,我们将探讨几种文本切分方法,并讨论在选择切分尺度和方式时应该考虑的权衡因素。最后,将给出一些建议,帮助确定最适合应用的文本切分尺度和方法。

Embedding大文本和小文本

当嵌入内容时,可以根据内容是简短(例如句子)还是长(例如文本段或整个文档)来设计不同的Embedding行为。

当一个句子被嵌入时,得到的向量会聚焦于该句子的特定含义。当用其他句子的嵌入进行搜索时,通常在这一层面上进行。这也意味着该嵌入可能会遗漏在文本段或文件中会找到的更宽泛的上下文信息。

当一个完整的段落或文档被嵌入时,嵌入过程要关注整体的上下文以及文本内部句子和短语之间的关系。这可能会产生一个更全面的向量表示,向量会表示出文本更广泛的含义和主题。另一方面,较大的输入文本尺寸可能会引入噪声、淡化单个句子或短语的重要性,使得在查询索引时找到精确匹配更困难。

查询的长度也影响着嵌入向量之间的关系。像一个单独的句子或短语这类较短的查询,会专注于具体内容,可能更适合与句子级别的嵌入进行匹配。一个跨越多个句子或一个段落的较长查询可能与段落或文档级别的嵌入更匹配,因为它可能在寻找更广泛的上下文或主题。

索引也可能是非均质的,并包含不同大小块的嵌入。这可能对查询结果的相关性提出挑战,但也可能有一些积极的影响。一方面,由于长短内容的语义表示之间的差异,查询结果的相关性可能会波动。另一方面,非均质索引可能能够更广泛地捕获上下文和信息,因为不同的块大小代表文本中不同级别的粒度。这可能更灵活地适应不同类型的查询。

分块的思路

确定最佳分块策略的有几个变量,这些变量因使用场景而异。以下是一些需要注意的问题:

  1. 索引内容的特性是什么? 是在处理长篇文档,如文章或书籍,还是较短的内容,如推文或即时消息?这个答案将决定哪种模型更适合目标,并因此决定应用哪种分块策略。
  2. 正在使用哪种嵌入模型,它在哪种块大小上表现最佳? 例如,句子转换模型在单个句子上表现良好,但像text-embedding-ada-002这样的模型在包含256或512个标记的块上表现更优。
  3. 对用户查询的长度和复杂度有什么期望? 用户的问题会简短并具体,还是长且复杂?这也可能影响你选择如何分块你的内容,以便嵌入的查询和嵌入的块之间有更紧密的关系。
  4. 应用中如何利用检索到的结果? 比如,检索的文本段将用于语义搜索、问题回答、摘要,还是其他目的?再比如,结果需要输入另一个有Token限制的LLM,那么必须根据LLM的限制确定召回的块的数量来限制整体输入的大小。 反思这些问题会促使我们制定在性能和准确性之间相对平衡分块策略,这将确保查询结果更加相关。

分块的方法

列出几个不同的Chuking方法,每种方法都有不同的适用场景。了解每种方法的优势和劣势,目标是正确的场景下使用正确的Chunking方法。

定长Chunking(Fixed-size chunking)

这是最常见,也是最直接的分块方法:简单地决定我们的块中的标记数量,并选择性地决定它们之间是否应该有任何重叠。一般来说,块之间应该保持一些重叠,以确保语义上下文不会在块之间丢失。在大多数常见情况下,固定大小的分块将是最佳路径。与其他形式的分块相比,固定大小的分块的计算代价较低且使用成本不高,因为它不需要使用任何NLP库。 LangChain中的一个Demo

text = "..." # your text
from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(
    separator = "\n\n",
    chunk_size = 256,
    chunk_overlap  = 20
)
docs = text_splitter.create_documents([text])

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

内容感知分片(“Content-aware” Chunking)

这是一系列利用我们正在分块的内容性质并对其应用更复杂分块的方法。以下是一些例子:

句子分割

之前提到过,许多模型都被优化过,用于嵌入句子级内容。当然,我们会使用句子分块,并且有几种方法和工具可以达成目的,包括:

  • Naive splitting: 最简单方法是按(“.”)和换行符出现的频率分割句子。尽管这种方法直接快速,但这种方法不会考虑所有可能的产生的边界情况。一个很简单的实现例子:
text = "..." # your text
docs = text.split(".")

  • 1
  • 2
  • 3
    • [NLTK]: Natural Language Toolkit(NLTK)是一个流行的用于处理自然语言数据的Python库。它提供了一个句子分词器,可以将文本分为句子,可以更有意义的Chunking。例如,要将NLTK与Langchain一起使用,可以按照下面的例子实现:
text = "..." # your text
from langchain.text_splitter import NLTKTextSplitter
text_splitter = NLTKTextSplitter()
docs = text_splitter.split_text(text)

  • 1
  • 2
  • 3
  • 4
  • 5
text = "..." # your text
from langchain.text_splitter import SpacyTextSplitter
text_splitter = SpaCyTextSplitter()
docs = text_splitter.split_text(text)

  • 1
  • 2
  • 3
  • 4
  • 5

递归Chunking(Recursive Chunking)

Recursive Chunking使用分层、迭代的概念形成一组分割器,用分割器将文本分割为较小的块。如果当前文本拆分出的段大小不满足需求大小,那么会递归地在带有不同的分离器或标准的结果块上继续调用,直到达到所需的块大小或结构为止。这意味着,尽管块的尺寸并不完全相同,但它们仍然与“预期”的尺寸相似。 下面是LangChain中的例子

text = "..." # your text
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
    # Set a really small chunk size, just to show.
    chunk_size = 256,
    chunk_overlap  = 20
)

docs = text_splitter.create_documents([text])

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

固定格式的分割

Markdown和Latex是经常遇到的两个结构化、格式化内容的示例。在这中情况下,可以使用专门的Chunking方法来获取、分割内容。

  • [Markdown]: Markdown is a lightweight markup language commonly used for formatting text. By recognizing the Markdown syntax (e.g., headings, lists, and code blocks), you can intelligently divide the content based on its structure and hierarchy, resulting in more semantically coherent chunks. For example:
from langchain.text_splitter import MarkdownTextSplitter
markdown_text = "..."

markdown_splitter = MarkdownTextSplitter(chunk_size=100, chunk_overlap=0)
docs = markdown_splitter.create_documents([markdown_text])

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
from langchain.text_splitter import LatexTextSplitter
latex_text = "..."
latex_splitter = LatexTextSplitter(chunk_size=100, chunk_overlap=0)
docs = latex_splitter.create_documents([latex_text])

  • 1
  • 2
  • 3
  • 4
  • 5

确定应用中最佳的块大小

有一些经验可以帮助我们明确最佳的块尺寸,如果固定的块(例如固定的块)不容易应用您的用例,请使用最佳的块。

  • 预处理数据:在确定最佳的块大小之前,先预处理数据,保证数据质量。举个例子,如果数据是从网络上获取的,你可能需要删除HTML标签或其他特定元素标签,去掉所有噪音。
  • 决定一个块的尺寸范围: 预处理数据后,下一步就是选择一些尺寸进行测试。如前所述,尺寸的选择需要考虑内容的性质(例如,短消息或冗长的文档)、LLM的限制(例如令牌限制)。目的是在保留环境和保持准确性之间找到平衡。首先探索各种尺寸,包括较小的块(例如128或256Token),以捕获更多的粒状语义信息和较大的块(例如512或1024代币),以保留更多上下文。

如何学习AI大模型?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/924733
推荐阅读
相关标签