质量工程师眼中的检索增强生成(RAG)解析

2024/11/15 21:03:06

本文主要是介绍质量工程师眼中的检索增强生成(RAG)解析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

构建这样的RAG很容易,但建立高质量的这样的RAG却很难。

检索增强生成(RAG)已成为增强大型语言模型(LLMs)能力的常见方式。

RAG 的理论其实很简单(只需要把数据加到上下文窗口里就行了!),但在实践中却很复杂。不过在这些框图背后隐藏了高级的分块策略、重新排序的操作、多查询的检索器、从小到大的检索策略、假设的文档嵌入、预嵌入的数据增强、动态的路由规则、自定义的嵌入模型……等等。

虽然搭建初始流程可能快速简单,但要达到生产级别的质量则复杂得多。如果不加小心,RAG系统可能会返回错误、无关或不一致的信息;它们可能性能不佳,消耗昂贵资源,或者在扩展到生产规模的数据源时出现问题。

理解如何有效地评估RAG系统的质量,需要理解每一个部分如何协同工作来构建完整的RAG管道。每个部分的设计决策都会影响质量。这对于尝试部署RAG应用的每个人来说都是重要的。

以下是从测试和质量保障的角度对RAG的概念和模式的介绍。我们将首先解释为什么RAG有价值,然后讨论构建高质量RAG时所涉及的许多设计决策如何改进它。这一介绍将为我们进一步讨论RAG系统的具体评估方法和技术打下基础。

大型语言模型(LLM)的局限

为了更好地理解RAG管道,我们先来理解一下,先了解下LLM存在的问题,这些问题正是RAG想要解决的。

说白了,大语言模型很简单:你给它发个提示,就能得到回复。

要给出回应,LLM必须对模型进行一次推理计算。此计算涉及将输入与定义模型的数百万甚至数百亿的_参数_进行组合。这需要大量的计算资源。

虽然调用大型语言模型(LLM)很昂贵,但训练一个LLM要难得多,甚至难上百倍。训练就是找到模型内部参数的最佳值。有多种算法用来计算最佳权重,但所有这些算法都涉及一个迭代过程,即在给定的输入上运行模型,计算误差,然后反向传播一个修正调整,使得答案会稍微好一点。这个过程会在众多输入上反复进行,最终你将得到一个训练完成的模型。虽然模型推理可能只需要几秒钟时间,但模型训练可能需要几周时间,即使是在大规模的GPU集群上。

一块NVIDIA H100,价格大约在40,000美元左右(2024年第一季度左右)

高昂的训练成本成为了将新的或更新的信息整合到大型语言模型中的瓶颈。大多数公司没有足够的资源来进行模型训练,因此不能简单地通过用私人数据训练来“添加新信息”到大型语言模型中。相反,大型且资金充裕的技术公司在大型公共数据集上训练通用的基础模型,并通过二次过程如检索增强生成(RAG)来增强这些模型的能力和信息。

具体而言,RAG旨在以一种绕过昂贵的训练新模型过程的方式,为大型语言模型提供大量的额外信息。

RAG 基本知识

咱们来看看RAG它是怎么工作的。

发送给大型语言模型的提示具有有限的长度,称为上下文窗口(context窗口)。上下文窗口以令牌(对于我们的目的来说,每个令牌大约相当于一个词)为单位进行测量。上下文窗口通常有1K、4K或更多令牌,不过,更大的上下文窗口正变得越来越普遍,比如,Gemini 1.5 Pro具有128K。

许多人直觉上认为上下文窗口仅仅是你能输入的“最长的问题”,但这是一种局限性的理解。由于LLM的设计机制,上下文窗口中提供的信息在生成回复时是可见和可用的,因此可以用来提供额外的信息。这通常被称为“上下文中的学习”或“上下文学习”。

因此,我们可以利用上下文窗口的大小提供相关信息,以便LLM回答问题。例如,我们可以创建一个询问某公司丧假政策的提示,然后将整个公司手册(包括有关丧假的部分)放入提示中,只要它能适应上下文窗口。这样做的好处是,LLM就能根据提供的新信息来回应。

这个解决方案在我们已经拥有相关信息,并且这些信息能够适应上下文窗口的大小的情况下很简单。不幸的是,实际情况并非总是如此。因此,我们需要一些方法来检索并筛选与我们提示相关的信息。

一个简单的方法是,在所有可能相关的数据中搜索提示里的关键词,复制找到的相关文字,将这些文字添加到提示里。

这种简单的_关键词查找_的RAG(检索和生成)可以提升LLM(大型语言模型)的回复质量,并可能在某些情况下有用,但可能会因关键词误用而产生误报。幸运的是,我们可以通过利用_语义搜索_来做得更好一些,即根据文本的_意义_进行匹配,而不仅仅是匹配原始单词。

具体而言,我们可以利用_嵌入模型_从可能相关的数据片段中创建嵌入,然后在这些嵌入之间进行搜索,以找到与我们提示相关的数据。这种方法非常简化,但已经开始看起来有点像真正的RAG了。

明话题:RAG 和嵌入

要理解RAG的好处,我们需要先了解它比简单的关键词搜索更优越的原因,这需要了解嵌入模型的用途和特点。这本身是一个复杂且深入的话题,但对理解RAG来说是必不可少的。

嵌入模型和我们原来的LLM很相似,但嵌入模型不是生成新内容,而是将输入转换成一个向量(即一串数字)。嵌入模型生成的向量通常包含768或1536个数字(也就是维度),如768或1536个数字,但也有不同长度的向量。

嵌入模型创建的向量不仅仅是一组随机数字;它是按照模型的理解,输入数据意义的提炼。这个向量对其他模型来说没有意义,但在同一个嵌入模型中,相似的文本会生成相似的向量。这里的“相似”不仅仅是“含有相同的关键词”——嵌入模型经过训练能从无结构数据中提炼出更深层次的语义。例如,“马不会飞”和“一个在瞎胡闹的家伙”虽然这些句子包含类似的词语,但它们生成的向量并不会相近。

向量的一大优点是你可以对其执行数学运算,而且是超级快速的运算。甚至可以在相对较短的时间内在数以百万计的向量中找到相似向量。(这里是一些常用的算法。)

我们现在有了RAG流水线的所有组件,让我们来一步一步看这些步骤吧。

第一步到第四步只需要做一次或当源数据变化时进行更新。对于每一个推理请求,则需要针对第五步到第八步执行。

  1. 我们收集所有可能相关的数据——数据量之大以至于无法全部放入提示的上下文窗口中。
  2. 我们将其分为较小的部分,稍后会详细介绍如下。
  3. 然后,我们将每个部分通过嵌入模型处理,生成一个可以概括该部分的含义的向量。
  4. 我们将向量保存到向量数据库中。
  5. 每当收到推理请求时: 当我们收到提示时,会通过与分块数据相同的嵌入模型处理该提示,生成另一个向量(称为“提示向量”或“查询向量”)。
  6. 我们在向量数据库中搜索与提示向量相似的向量。返回的向量相比于仅通过关键词搜索原始数据有更好的匹配度。
  7. 我们(可选地)重新排序识别的相关向量,然后返回每个最佳向量的原始数据。
  8. 原始数据与初始提示结合后发送给大语言模型。

基础的RAG:绿色表示已完成的预处理步骤,蓝色表示每个推理步骤已完成。

看——我们的LLM现在表现得就像它已经用我们输入到向量搜索中的新专有数据进行了训练过一样,而无需进行昂贵得无法承受的基础模型训练。

至少可以说,它应该在理论上如何运作。实际上,这种过于简单的流水线可能无法满足你的实际需求,你可能需要对其进行调整、改进、更换或扩展,以适应你的具体应用需求,才能达到质量过关并准备好投入生产的RAG系统。

RAG 设计与质量

上面提到的RAG,但正如我们之前所说,实际应用中的RAG可能复杂得多,这些实际中的复杂性可能会影响应用质量。让我们一步一步地来看看,来看看RAG流程中的实现挑战、质量风险以及可能的替代方案。

#1—获取相关数据并进行数据采集和丰富数据

从头开始,我们得找到所有“可能相关的数据”。

图中的单个图标(#1)更可能代表一个完整的数据管道(或多个管道!),从多个来源获取并处理数据;对数据进行分阶段处理;整理并清洗数据;可能还会对其进行转换、匿名化和标记处理;并执行数据管道中常见的其他处理步骤。

有些管道可能会变得非常复杂,尤其是当原始数据格式不是文本时。例如,有些管道会广泛使用OCR技术来摄入大量的扫描纸质文件。

随着数据管道的复杂性,随之而来的还有测试数据管道的挑战。

如果源数据根本无法进入向量数据库,即使是最完善的RAG管道也会惨遭失败。而根据这些数据的种类、速度和变化率,以及数据的数量,RAG的这个数据摄入阶段可能会相当复杂,也可能成为导致应用程序质量相关问题的主要因素。

除了正常的数据管道活动之外,RAG 还可以从“数据增强(Data Enrichment)”中获益。通常,其他系统(或人员)对源数据有所了解,这些信息对于评估其意义非常有帮助。例如,客户数据库也可以通过其他系统的标签或注释来丰富,提供额外的信息。通常,会使用其他生成模型或NLP来生成更干净或更简洁的元数据。这可以被视为嵌入生成前的预处理步骤,如果处理得当,可以显著提高检索效果。

如果你在评估RAG系统的质量时,花时间了解数据是如何收集和导入的,在它进入RAG管道中的AI部分之前,这非常值得。

#2—分块法

在数据被摄入后,但在通过嵌入模型处理之前,必须将其分割成独立的小块。那么,你又是如何分割数据的呢?这被称为你的分块策略

多大的块最理想?块之间是否需要重叠?是否有比按页面、段落或特定长度更聪明的分块方法?如何分块非标准格式(如代码、JSON等)?

这些是分块策略试图回答的问题,并且没有完美的解决方案。不同的策略有不同的权衡。有些策略简单且快速实施,能提供过得去的结果。有些策略更复杂,它们可以提供更好的命中率和大型语言模型的响应质量。如果分块太粗犷,可能会把不相关的数据塞进上下文窗口,挤掉其他相关的块,或者生成过于通用的嵌入向量,难以找到有意义的相关性。如果分块太细,可能会“截取”相关数据。

这篇文章探讨了五种分块方法:固定大小、递归、文档为基础、语义和代理型(利用AI进行分块,简直太棒!)。参见这篇文章(点击链接查看原文)。

还有许多其他方法可以用来优化分块。例如,在 小到大检索法 中,使用小块进行搜索,但每个小块都关联到一个较大的大块,该大块被检索并插入到上下文模型中。 上下文感知分块 根据文档本身的了解,智能地将文档分割成逻辑块。

这个列表可能并不完整,但展示了 RAG 实现者可以使用的多种选项,并强调了合适的分块策略对于应用整体质量的重要性。Pinecone 博客 还提供了更多关于这些策略的详细信息。

#3—选择和配置嵌入模型

有许多模型可以用来生成嵌入,不同的模型在不同的情况下表现会有好有坏。有些模型是预先训练用于通用目的的,而有些则是针对特定领域(比如说医疗记录)进行了微调。你也可以针对应用处理的特定数据微调自己的嵌入模型以适应这些数据。

此外,许多模型有不同的大小(这会影响生成嵌入的成本和时间)、有不同的输入长度(它可以处理的最大输入长度)以及有不同的输出向量维度(维度越高,越准确,但需要更多存储空间,速度也更慢)。

有些嵌入模型只能通过API来访问(例如,OpenAI 嵌入接口),而其他模型则是完全开放源代码的,可以下载并在本地运行或托管在云端。

也可以在应用程序中的不同数据路径使用不同的嵌入模型。

虽然通常不错的嵌入模型可能对许多RAG应用来说已经足够,然而,其他应用可能需要特定的嵌入模型或自定义训练的模型来获益。

了解您的嵌入策略的设计考虑及其质量特性,将帮助您更好地理解应用程序的评估需求和方法。想了解更多,这里有一篇更深入的讨论,帮助您更好地评估嵌入模型的选择。

#5—查询处理和嵌入

并没有规定你必须完全按照收到的查询运行嵌入模型。实际上,有很多方法可以优化查询及其后的嵌入搜索,从而提高你应用程序的总体质量。尤其当查询直接来自人类用户时,这些用户可能会写下模糊、随意或模糊的问题,这种情况更加明显。

如果知道应用程序的性质或意图,可能可以使用大型语言模型或传统逻辑来简化或重写查询内容,使其更简洁明了,也就是说,将查询重写为原本 意图 的内容,而不是实际问的问题。

一种高级的查询处理方法是HyDE,它创建一个假设的答案集合,从而进行向量搜索以找到相似的答案,而不是直接在查询和答案之间进行搜索。

另一种选项是拆分成多个相关的查询,并同时运行每个查询,然后合并结果——这就是多检索器模式的使用。这样做显然会增加处理成本,但可以提升检索的质量。

根据你的具体需求或场景,你可能需要自定义查询,这会显著影响应用程序的表现。

#4,#6—向量数据库及向量搜索

虽然向量搜索虽然快,但在向量数据库中搜索与查询相似的嵌入时,仍然会有时间(和可能的金钱)成本。一种减少这种成本的方法是使用语义缓存机制。在语义缓存机制中,每当嵌入被检索后,响应就会被缓存,因此未来的类似搜索可以直接从缓存中获取数据。

当然,缓存会让事情变得更复杂(这也是计算机科学中的两个难题之一——另一个名字我已经忘了)。虽然缓存可以提高性能,但过时的缓存会严重影响响应质量,尤其是在源数据经常变化的环境中。

#7 重新排列

在我们上面的描述中,我们天真地认为可以将向量搜索返回的所有相关数据全部放入上下文中。显然,这只是一个简化的假设,肯定有一套流程来决定应该优先选择哪些返回的向量放入上下文中。

即使我们能够让搜索结果适配上下文窗口,许多研究表明,通过填充上下文(填满上下文窗口)可能会通过引入中间信息丢失问题而负面影响大型语言模型的回忆能力,从而影响响应的质量。回忆是指大型语言模型如何利用其上下文窗口中的信息的能力。

解决办法是在最初的向量搜索之后增加一个重新排序的步骤。

重排序的要点可以简单总结如下:嵌入模型被优化以提高速度,因为它们需要对大量的文档进行计算。而其他被称为 重排序模型(或 交叉编码器)的模型虽然较慢,但更注重准确度。因此,先使用快速但不够准确的嵌入模型生成嵌入结果,并将这些结果保存到向量数据库中,然后使用较慢但准确的模型在较小的集合中找到质量最高的文档。在上下文窗口中,优先展示这些较慢但准确搜索中找到的最佳匹配项。

当然,这还远不止如此,但这正是重新排序的关键。Pinecone 的博客 对这个过程有更详细的说明。

重新排序技术可以显著提升RAG返回的数据的相关性,这是一个反映检索质量的指标。更相关或相对不那么不相关的数据在上下文窗口内会提高响应质量。尽管这会增加复杂性和延迟,但这种质量上的权衡在许多RAG应用中可能值得付出。

大上下文窗口技术 vs. 检索增强生成(RAG)

在那之前,我们终于准备调用LLM,但在我们开始讨论提示工程之前,我们稍微提一下RAG与大上下文窗口的关系。

LLM技术正在迅速发展,其中一个改进维度是上下文窗口大小。一个典型例子是Gemini 1.5 Pro,于2024年2月发布,具备128K大小的上下文窗口,并且有一个尚未公开的选项,可以扩展到上百万(!!!)token。

一开始有些人猜测,一个一百万个令牌的上下文窗口会使得RAG管道变得不再适用,但这并不是真的。这篇博客解释了为什么即使在使用具有巨大上下文窗口的模型时,RAG仍然很有价值,甚至必不可少(剧透:成本、延迟和检索质量)。

大型上下文模型这类模型很有价值,可以帮助LLM处理需要整合大量事实的查询(这些事实可能是通过RAG筛选过的,也可能未经过筛选)。

较大的上下文窗口与RAG之间的关系将继续发展,实施RAG的开发人员和测试人员应该了解这些权衡及其对应用质量的影响。

#8—生成提示

你从向量数据库(VectorDB)得到了一堆相关数据,再排个序,最后得到了适合你大语言模型(LLM)上下文窗口的相关内容。然后呢?你只是把数据塞到初始问题后面,然后就完事了?

正如任何与大语言模型合作过的人可以告诉你的一样,这比你想象的更复杂。大语言模型可以非常强大,但它们也可能多变且令人沮丧。事实证明,提示中的细节会对响应质量产生重大影响。你如何措辞提示、数据的顺序、使用的语气、比如“慢慢来”这样的建议,甚至使用带有情感色彩的语言都会影响大语言模型的响应质量。有策略可以自动生成最佳提示,利用……没错,也就是其他专门训练来生成提示的模型。所有这些都是迅速发展的提示工程领域的一部分。

生成最高质量响应的精确提示模板通常需要针对特定的模型和应用场景进行定制,往往需要经过一些试错实验。鉴于这个看似微小的细节对RAG质量的巨大影响,这种具体提示设计也应该像系统中的其他部分一样,经过严格的评估和测试。

衡量和评估RAG系统

在简要讨论了RAG管道对应用质量的影响后,我们已经走过了RAG管道的主要部分。这样的一次入门介绍应该能让你了解这些应用程序内部的工作原理及其质量挑战。有许多优秀的文章、博客和论文对RAG进行了更深入的探讨。如果你只读一篇,我建议你读基于检索的增强生成技术在大型语言模型中的应用研究。

最关键的一点是,在实施RAG的过程中,有很多选项和选择,每个选择都有其权衡和对质量的影响。一些选择可以直接评估,而另一些则需通过其对整体检索或响应质量的影响来评估。了解这些选择及其可能对您的RAG系统产生的影响,对于确保你的应用程序达到生产质量标准至关重要。

显然下一个问题是:好的,但具体该怎样评估RAG呢?我该如何衡量开放性自由回答的质量?我可以使用什么指标来衡量?这些评估如何才能自动化?自动化程度能达到什么水平?在大型语言模型本质上是不可预测的,它们所依赖的数据也具有易变性的前提下,我该如何确保质量?

这些问题不仅有趣,还有着有趣的答案。我们将探讨使用ARC和HellaSwag等框架进行模型评估,采用包括“LLM作为裁判”这样的方法,进行类似“大海捞针”的测试,以及使用困惑度、忠实度和相关度等指标。我们还将使用像Ragas和LlamaIndex这样的工具。

不过,这些好玩的事只能等到下次再聊了。

特别感谢埃蒂安·奥尔和杰克·本内托对本文的技术反馈。



这篇关于质量工程师眼中的检索增强生成(RAG)解析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程