人工智能学习

你必须知道的4种高级RAG算法

本文主要是介绍你必须知道的4种高级RAG算法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

→ 12节课中的第5节LLM Twin 免费课程

什么是你的LLM Twin? 它是一个AI角色,通过将你的风格、个性和声音融入到LLM中,写出像你一样的内容。

图片由 DALL-E 创建

这一课程有何不同?

通过完成“ LLM Twin:构建您的生产就绪AI副本 免费课程,您将学习如何设计、训练和部署一个由LLM、向量数据库和LLMOps最佳实践驱动的生产就绪的LLM副本。

为什么你应该在意呢? 🫵

→ 再也没有孤立的脚本或笔记本了!通过构建和部署一个端到端的生产级LLM系统来学习生产级别的机器学习。

本课程结束时,你将学会构建什么?

你将 学习 如何 设计构建一个真实的LLM系统 —— 从 数据收集部署,全程掌握。

你还将 学习 如何 利用MLOps最佳实践 ,例如实验跟踪器、模型注册表、提示监控和版本控制。

最终目标? 构建并部署你自己的LLM孪生模型。

架构 4个Python微服务 组成:

  1. 数据收集管道: 从各种社交媒体平台爬取您的数字数据。通过一系列ETL管道对数据进行清洗、归一化并加载到NoSQL数据库中。使用CDC模式将数据库更改发送到队列中。(部署在AWS上)
  2. 特征管道: 通过Bytewax流处理管道从队列中消费消息。每个消息将被清洗、分块、嵌入(使用Superlinked),并实时加载到Qdrant向量数据库中。(部署在AWS上)
  3. 训练管道: 根据您的数字数据创建自定义数据集。使用QLoRA微调LLM。使用Comet ML的实验跟踪器监控实验。评估并保存最佳模型到Comet的模型注册表中。(部署在Qwak上)
  4. 推理管道: 从Comet的模型注册表中加载并量化微调后的LLM。将其部署为REST API。使用RAG增强提示。使用您的LLM Twin生成内容。使用Comet的提示监控仪表板监控LLM。(部署在Qwak上)

LLM 双胞胎系统架构 [作者绘制的图片]

沿着这4个微服务,你将学习如何集成3个无服务器工具:

  • Comet ML 作为你的 ML 平台;
  • Qdrant 作为你的向量数据库;
  • Qwak 作为你的 ML 基础设施;
这是谁呢?

受众: 希望学习使用LLMOps良好原则构建可投入生产的LLM系统的MLE、DE、DS或SWE。

级别: 中级

前提条件: 具备Python、机器学习和云的基础知识

你将如何学习?

该课程 包含 10个动手实践课时 和你可以 访问 GitHub 获取开源代码,展示如何构建一个端到端的LLM系统。

此外,还包括 2个 bonus 课程,教你如何 改进 RAG系统

你可以按照自己的节奏阅读所有内容。

→ 为了最大限度地利用本课程,我们鼓励你在学习过程中克隆并运行该仓库。

费用?

文章和代码是完全免费的。它们将永远保持免费。

但是如果你打算在阅读代码时运行代码,你必须知道我们使用了几个云工具,这些工具可能会产生额外的成本。

云计算平台(AWS,Qwak)采用按需付费的计费方式。Qwak 提供了几小时的免费计算时间。因此,我们尽量将成本降到最低。

对于其他无服务器工具(Qdrant,Comet),我们将使用它们的免费版本,这是免费的。

认识你的老师!

该课程由以下人员在 Decoding ML 的支持下创建:

  • Paul Iusztin | 高级ML & MLOps工程师
  • Alex Vesa | 高级AI工程师
  • Alex Razvant | 高级ML & MLOps工程师

🔗查看 我们在GitHub上的代码 [1],并给我们一个⭐️支持

教训

→ 快速概览 每节课的内容概览。

课程分为12节课。每篇Medium文章将是一节课:

  1. 构建生产就绪的LLM系统端到端框架:打造您的LLM Twin
  2. 生成式AI时代数据管道的重要性
  3. 变更数据捕获:启用事件驱动架构
  4. 实时微调LLM和RAG的SOTA Python流处理管道
  5. 必须掌握的4种高级RAG算法
  6. 特征存储在微调LLM中的作用
  7. 如何使用Qwak和CometML在自定义数据集上大规模微调LLM
  8. 评估微调LLM的最佳实践
  9. 架构可扩展且成本效益高的LLM&RAG推理管道
  10. 如何使用RAGAs框架评估您的RAG管道
  11. [Bonus] 使用更少的代码构建可扩展的RAG摄取管道
  12. [Bonus] 构建多索引高级RAG应用程序

要更好地理解课程的目标、技术细节和系统设计查看第1课

让我们开始 第5课 ↓↓↓

第5课:必须掌握的4种高级RAG算法

第5课 中,我们将重点介绍用于RAG的高级检索模块的构建。

我们将向您展示如何实现4种检索检索后高级优化技术,以提高您的RAG检索步骤准确性

在这节课中,我们将只关注RAG系统中的检索部分。

Lesson 4中,我们展示了如何清理、切分、嵌入并将社交媒体数据加载到Qdrant向量数据库(RAG的数据摄入部分)。

在未来的课程中,我们将把这个检索模块集成到推理管道中,以构建一个完整的RAG系统。

检索 Python 模块架构

我们假设你已经熟悉了什么是简单的RAG。如果不熟悉,可以查看来自Decoding ML的以下文章,文章在2分钟内介绍了什么是简单的RAG

为什么在LLM应用中的RAG中必须选择流处理而不是批处理管道Lesson 2: RAG、流处理管道、向量数据库、文本处理medium.com
目录
  1. 高级RAG优化技术概述
  2. 高级RAG技术应用于LLM Twin
  3. 检索优化(1):查询扩展
  4. 检索优化(2):自查询
  5. 检索优化(3):混合及过滤向量搜索
  6. 实现高级检索Python类
  7. 检索后优化:使用GPT-4重新排序
  8. 如何使用检索
  9. 结论

🔗查看我们在GitHub上的代码 [1],并用一个⭐️支持我们

1. 高级RAG优化技术概述

一个生产环境中的RAG系统分为 3个主要组件

  • 数据摄入: 清理、切分、嵌入并加载您的数据到向量数据库
  • 检索: 查询您的向量数据库以获取上下文
  • 生成: 将检索到的上下文附加到您的提示中,并将其传递给LLM

摄入组件位于特征管道中,而检索生成组件则实现在推理管道中。

你也可以在你的 训练管道 中使用 检索生成 组件,进一步针对特定领域的提示微调你的大语言模型。

你可以应用高级技术来优化你的RAG系统在数据摄入、检索和生成方面的性能。

说归说,有三种主要的高级RAG技术:

  • 预检索优化 [ingestion]:** 调整你创建分块的方式
  • 检索优化[retrieval]:** 改进对向量数据库的查询
  • 后检索优化[retrieval]: 处理检索到的分块以过滤掉噪音

通过微调或提示工程可以改进生成步骤,这将在未来的课程中进行解释。

预检索优化技术在Lesson 4中有解释。

在本课中,我们将向您展示一些流行检索检索后优化技术

2. 高级RAG技术应用于LLM孪生模型
检索优化

我们将结合3种技术:

  • 查询扩展
  • 自查询
  • 过滤向量搜索
检索后的优化

我们将 使用 重排序 模式 利用 GPT-4提示工程,而不是使用 Cohere 或一个 开源重排序器 cross-encoder [4]。

我不想花太多时间在理论方面。这方面的文章已经很多了。

所以我们将直接实现集成_这些技术到我们的LLM Twin系统中。

但在这之前,让我们先澄清一些事情 ↓

高级RAG架构

2.1 重要说明!

我们将展示一个自定义实现,而不会使用 LangChain,来演示这些高级技术

我们的主要 目标建立 你对他们 背后工作原理直觉。然而,我们将 附上 LangChain 的等效实现,这样你就可以在你的应用中使用它们了。

自定义 LangChain 可能会让人 头疼。因此,了解其工具背后的运作原理可以帮助你构建实际的应用程序。

另外,至关重要的是要知道,如果你不使用LangChain来导入数据,你也无法使用他们的检索功能,因为它们期望数据以特定的格式存在。

我们也没有在Lesson 4中使用LangChain的加载功能(将数据加载到Qdrant的特性管道),因为我们想“亲手”完成所有操作。

2.2. 为什么选择 Qdrant?

有太多的向量数据库……

但自从我们发现了 Qdrant,我们就爱上了它。

为什么?

  • 用 Rust 编写。
  • Apache-2.0 许可证 — 开源 🔥
  • 提供功能强大且直观的 Python SDK。
  • 提供免费的 Freemium 自托管版本,用于构建 PoC。
  • 支持无限大小的文档,并且向量维度最多可达 645536。
  • 已准备好投入生产使用。迪士尼、Mozilla 和微软等公司已经在使用它。
  • 它是目前最受欢迎的向量数据库之一。

为了说明这一点, 其中一个主要竞争对手 Pinecone 只支持最多 40k 令牌的文档和最多 20k 维度的向量……并且需要一个专有许可。

我还可以继续说……

…但如果你 想了解更多查看 Qdrant

3. 检索优化 (1): 查询扩展
问题

在典型的检索步骤中,你使用一个点查询你的向量数据库。

该方法的问题在于,通过使用一个单一向量,你只能覆盖嵌入空间中的一小部分

因此,如果你的嵌入不包含所有所需的信息,检索到的上下文将不会相关。

如果我们可以用多个语义相关的数据点查询向量数据库会怎么样?

那就是“查询扩展”技术在做的事情!

解决方案

查询扩展非常直观。

你使用一个大语言模型生成多个查询,基于你的初始查询。

这些查询应该包含初始查询的多个视角。

因此,当嵌入时,它们会击中你嵌入空间中与我们初始问题仍然相关的不同区域。

你可以通过一个详细的零样本提示来扩展查询。

这里是我们简单且自定义的解决方案 ↓

查询扩展模板 → GitHub 代码 ←

这里是 LangChain的 MultiQueryRetriever 类 [5](他们的等效实现)。

4. 检索优化(2):自查询
问题

在嵌入您的查询时,您不能保证嵌入向量中包含了您用例所需的所有方面。

例如,你希望确保你的检索完全依赖于查询中提供的标签。

问题在于,通过嵌入查询提示,你永远无法确定标签是否被包含在嵌入向量中,或者在与其他向量计算距离时是否有足够的信号。

解决方案

如果你能提取查询中的标签并将其与嵌入查询一起使用会怎么样?

那就是自查询的全部内容!

你使用一个大型语言模型(LLM)来提取对你业务用例至关重要的各种元数据字段(例如,标签、作者ID、评论数量、点赞数、分享数等)。

在我们的自定义解决方案中,我们只提取作者ID。因此,零样本提示工程技术可以完成任务。

但是,在提取多种元数据类型时,你也应该使用少量样本学习来优化提取步骤。

自查询与向量过滤搜索紧密配合,我们将在下一节解释这一点。

这里是我们的问题解决方案 ↓

自查询模板 → GitHub 代码 ←

这里是 LangChain 的 SelfQueryRetriever 类 [6] 的等效实现,这是 使用 Qdrant 的示例 [8]。

5. 检索优化(3):混合及过滤的向量搜索
问题

嵌入式表示非常适合捕捉特定片段的一般语义。

但它们对于查询特定关键词不是很好。

例如,如果我们想要从我们的 Qdrant 向量数据库检索关于 LLM 的文章片段,仅使用嵌入就足够了。

然而,如果我们想要查询特定的LLM类型(例如,LLama 3),仅使用嵌入之间的相似性是不够的。

因此,嵌入式表示不适合用于精确查找特定术语的短语匹配。

解决方案

结合向量搜索技术与一种(或多种)互补的搜索策略,这对于查找确切的单词非常有效。

它没有定义组合哪些算法,但混合搜索最标准的策略是结合传统的基于关键词的搜索和现代的向量搜索。

这些是如何结合的?

第一种方法** 是将2种技术的相似度分数合并如下:

     hybrid_score = (1 - alpha) * sparse_score + alpha * dense_score

其中 alpha 的取值范围为 [0, 1],具体为:

  • alpha = 1 : 向量搜索
  • alpha = 0 : 关键词搜索

此外,相似度得分定义如下:

  • sparse_score: 是关键字搜索的结果,背后使用的是基于 TF-IDF 的 BM25 算法 [7]。
  • dense_score: 是向量搜索的结果,通常使用诸如余弦距离之类的相似度度量。

    第二种方法仍然使用向量搜索技术,并在检索结果的元数据上根据您的关键词应用过滤器。

→ 这也被称为过滤向量搜索

在这个用例中,相似分数 不会根据 提供的 关键词 进行更改。

它只是你在向量的元数据上应用的一个简单的过滤器的花哨说法。

但是理解第一第二方法之间的区别至关重要的

  • 第一种方法 使用 alpha 参数结合关键词与向量之间的相似度得分;
  • 第二种方法 是在你的向量搜索之上进行的一个简单过滤。
这如何融入我们的架构?

记得在自我查询步骤中,我们提取了 author_id 作为需要匹配的精确字段。

因此,我们将使用关键词搜索算法查找 author_id,并将其附加到查询扩展步骤生成的5个查询中。

当我们想要从某个特定作者获取最相关的片段时,最合理的做法是使用一个以作者ID作为过滤条件的过滤器(过滤向量搜索_)如下 ↓

    self._qdrant_client.search(  
          collection_name="vector_posts",  
          query_filter=models.Filter(  
              must=[  
                  models.FieldCondition(  
                      key="author_id",  
                      match=models.MatchValue(  
                          value=metadata_filter_value,  
                      ),  
                  )  
              ]  
          ),  
          query_vector=self._embedder.encode(generated_query).tolist(),  
          limit=k,  
    )

注意,我们可以轻松地用多个关键词(例如,标签)扩展这一点,使自查询和混合搜索的结合成为一个强大的检索组合。

你唯一需要问自己的问题是,我们是否希望使用简单的向量搜索过滤器还是更复杂的混合搜索策略。

注意,LangChain 的 SelfQueryRetriever 类在幕后结合了自查询和混合搜索技术,如其 Qdrant 示例 [8] 所示。这就是为什么我们想从头开始构建所有内容。

6. 实现高级检索的Python类

现在你已经理解了我们使用的_高级检索优化技术,让我们将它们_结合起来,形成一个_Python检索类_。

这里就是主检索器函数的样子 ↓

VectorRetriever: 主要检索函数 → GitHub ←

使用 Python 的 ThreadPoolExecutor 非常强大,可以解决 I/O 瓶颈问题,因为这些操作不会受到 Python GIL 限制的影响。

这里是我们将每个高级检索步骤封装到自己的类中的方式 ↓

查询扩展链封装 → GitHub ←

The SelfQuery 类看起来非常相似 — 🔗 访问它在这里 [1] ←.

现在最后一步是为查询扩展步骤生成的每个查询调用 Qdrant ↓

VectorRetriever: 主搜索函数 → GitHub ←

注意我们有3种类型的数据_:帖子、文章和代码仓库。

因此,我们需要为每个集合分别进行查询,并最终合并结果。

最高效的方法是使用多索引技术,这样可以一次性查询多种类型的数据。

但在我撰写这篇文章时,这还不是在生产环境中解决的问题。

因此,我们分别从每个集合中收集数据,并使用重排序保留了最佳检索结果。

这是文章的最后一步。

7. 检索后优化:使用GPT-4重新排序

我们在Qdrant向量数据库中为N个查询扩展步骤生成的提示进行了不同的搜索

每个 搜索 返回 K 个结果

因此,我们最终得到了 N x K 个片段

在我们特定的情况下,N = 5 & K = 3。因此,我们最终得到了15个片段。

检索后优化:重新排序

问题

检索到的上下文可能包含仅与查询不相关的片段,这些片段仅:

  • 增加噪声: 检索到的上下文可能无关
  • 使提示更大: 会导致更高的成本,并且大模型通常只关注上下文的第一部分和最后一部分。因此,如果你添加了大量上下文,有很大可能性会错过核心内容。
  • 与你的问题不一致: 块是基于查询和块嵌入相似性检索的。问题在于嵌入模型没有针对你特定的问题进行调优,这可能导致高相似度分数,但与你的问题并不完全相关。
解决方案

我们将使用 rerank 根据每个片段相对于初始问题的相关性来对所有 N x K 个片段进行排序,其中第一个片段最为相关,最后一个片段相关性最低。

最终,我们将挑选出最相关的TOP K个片段。

Rerank 在与查询扩展结合使用时表现非常出色。

使用 rerank 时的自然流程如下:

搜索 >K 个片段 >>> 使用 rerank 重新排序 >>> 取前 K 个

因此,结合查询扩展,我们从多个空间点收集潜在有用的上下文,而不仅仅是在一个位置查找超过 K 个样本。

现在流程看起来像:

搜索 N x K 块 >>> 重新排序使用 rerank >>> 取 top K

一个典型的重新排序解决方案使用了来自句子转换器的开源Cross-Encoder模型 [4]。

这些解决方案将问题和上下文作为输入,并返回一个从0到1的分数。

在本文中,我们想采用不同的方法,使用 GPT-4 + 提示工程作为我们的重排器。

如果你想了解如何使用开源算法进行重排序,可以查看 Decoding ML 的这篇实战文章:

面向社交媒体数据的RAG实时检索系统使用流式引擎实时填充向量数据库。通过重排序和UMAP提高RAG的准确性。medium.com

现在让我们看看使用 GPT-4 和提示工程的实现。

类似于我们为扩展和自我查询链所做的,我们定义了一个模板和一个链构建器 ↓

重排链 → GitHub ←

这里是我们如何将重排序链集成到检索器中的:

检索器: 重新排序步骤 → GitHub ←

…就这样!

注意这是一个实验性过程。因此,你可以进一步调整你的提示以获得更好的结果,但主要思路是相同的。

8. 如何使用检索功能

最后一步是运行整个流程。

但是有一个陷阱。

正如开头所说,检索器不会作为独立组件在LLM系统中使用。

它将作为存在于数据Qdrant __向量数据库之间:

  • 训练管道 用于检索原始数据以进行微调(我们没有展示这部分,因为它是一个简单的搜索操作——不涉及RAG)
  • 推理管道 用于执行RAG

    → 那就是为什么在这个课程中没有任何基础设施的参与!

但是,为了测试检索,我们编写了一个简单的脚本 __ ↓

检索器测试入口 → GitHub ←

看看用我们自定义的检索器调用整个链路是多么简单——不需要复杂的LangChain!

现在,要调用这个脚本,运行以下Make命令

make local-test-retriever

…就这样!

在未来的课程中,我们将学习如何将其集成到训练和推理管道中。

查看LLM Twin GitHub 仓库并亲自尝试! … 当然,别忘了给它点个 ⭐️ 以便及时了解最新更新。

结论

恭喜!

第5课 中,你学习了如何 构建 一个 高级RAG检索模块,该模块经过优化,可以搜索来自 Qdrant向量数据库 的帖子、文章和代码库。

首先,你了解了RAG管道可以被优化的地方:

  • 预检索
  • 检索
  • 后检索

你学会从零开始(不使用LangChain的工具)构建以下高级RAG检索及检索后优化技术之后:

  • 查询扩展
  • 自查询
  • 混合搜索
  • 重新排名

最终,你理解了检索组件在一个生成式检索和生成(RAG)大型语言模型系统中的位置,代码被多个微服务共享,并不单独存在于一个Notebook中。

第6课中,我们将进入训练管道,并向您展示如何自动将从LinkedIn、Substack、Medium和GitHub爬取的数据转换为指令数据集,以使用GPT-4微调您的LLM Twin。

再见啦!🤗

🔗查看我们在GitHub上的代码 [1],并用一个⭐️支持我们

喜欢这篇文章吗?

加入Decoding ML Newsletter 以获取经过实战检验的内容,关于设计、编码和部署生产级的ML及MLOps系统_。每周免费提供↓

Decoding ML 通讯 | Paul Iusztin | Substack加入以获取经过实战检验的内容,关于设计、编码和部署生产级的 ML 和 MLOps 系统。每周更新。decodingml.substack.com
参考资料
文献

[1] 您的 LLM 双胞胎课程 — GitHub 仓库 (2024), Decoding ML GitHub 组织

[2] Bytewax,Bytewax 主页

[3] Qdrant, Qdrant 文档

[4] 检索与重排序,Sentence Transformers 文档

[5] MultiQueryRetriever, LangChain 文档

[6] 自我查询, LangChain 的文档

[7] Okapi BM25,维基百科

[8] Qdrant 自查询示例, LangChain 文档

图像

如果没有特别说明,所有图片均由作者创建。

这篇关于你必须知道的4种高级RAG算法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!