LLM之RAG理论(九)| 如何在LLM应用程序中提高RAG结果:从基础到高级

       如果你正在用LLM(大型语言模型)构建产品或者功能,你可能会使用一种名为RAG(检索增强生成)的技术。RAG允许用户将LLM的训练数据中不可用的外部数据集成到LLM的文本生成过程中,这可以大大减少幻觉的产生,并提高文本响应的相关性。

       RAG的想法其实很简单:查询并检索最相关的文本块,并将其插入LLM的原始提示中,这样LLM就可以访问这些引用文本片段,并可以使用它们生成响应。但是,要获得一个高质量的RAG管道(在生产环境中产生用户想要的确切结果)可能相当困难

       在这篇文章中,让我们探讨一下从最基本到更高级的技术,以提高LLM应用程序的RAG结果。

一、基本RAG

       首先让我们介绍一下基本的RAG,它主要包括三个阶段:索引检索生成

       索引过程是为检索过程准备数据。你应该收集你想让你的LLM知道的一切,例如,产品文档、产品政策、公司网站等,这取决于你想让聊天机器人做什么。然后你会把它分解成更小的文本块(这样你就可以很容易地把这些块放进LLM的上下文大小)。然后,你将通过嵌入模型将块转换为矢量表示(这样以后你就可以很容易地找到类似的块)。最后,你可以将所有这些文本嵌入对保存在索引或矢量数据库中,以供检索使用。

       检索过程发生在用户查询LLM时。在用户提出问题后,你可以保留该查询,而不是直接将其发送到LLM。相反,你将使用索引中文本块中的一些附加信息来丰富查询。你将使用相同的嵌入模型对用户的原始查询进行编码,然后执行相似性搜索,在数据库中找到最相似(大多数时候也是最相关)的文本块。

      然后,为了生成,需要将文本块插入到包括用户原始查询的提示中,LLM将使用检索到的文本块中提供的信息生成答案。

以下是RAG的基本提示:

Answer the following question based on the given information only. If the given information is not enough to answer the question, simply reply "I don't know".Question: "<user's original query>"Given information: "<the text chunk you retrieved from the database>"

       RAG是业界公认的流程,LlamaIndex[1]和LangChain[2]两个流行的库支持上述这些步骤用于RAG流程。RAG需要矢量数据库来创建索引和检索,如Pinecone[3]和Chroma[4]。

这个过程简单有效,但在现实世界中,经常会面临以下问题:

  • RAG无法检索用于生成的最相关的信息块。当检索到类似但不相关的块时,LLM将对用户的原始查询给出不正确的答案;
  • RAG检索到的块没有正确的上下文。有时,检索到的块会错过周围的上下文,使它们无法生成有用的答案,甚至无法向LLM提供矛盾的信息;
  • 用户的不同查询需要不同的检索或生成策略;
  • 用户的数据结构可能不适合使用嵌入进行相似性搜索。

       在下一节中,我们将介绍一些克服这些问题并提高RAG性能的技术。

二、提高RAG性能的技术

       经过近一年的LLM使用,我学到了许多提高RAG性能的技术,并总结了一些使用RAG的经验教训。在本节中,我将介绍许多在检索前、检索中和检索后提高RAG性能的技术。

2.1 预检索技术

       预检索技术包括可以在索引步骤中或在搜索数据库中的块之前使用的技术。

       第一种技术是提高索引数据的质量。在机器学习领域,有一句话叫“垃圾进,垃圾出”,我认为这也适用于RAG,但许多人只是忽略了这一步骤,并在这一非常关键的初始步骤之后专注于优化步骤。您不应该期望将每一个文档(无论是否相关)都放入您的矢量数据库,并抱着最好的希望。为了提高索引数据的质量,您应该:(1)删除与特定任务无关的文本/文档(2)将索引数据重新格式化为与最终用户可能使用的格式类似的格式(3)向文档中添加元数据,以实现高效和有针对性的检索。

       这是我自己的一个例子。我需要检索的文本是数学问题,但关于不同概念的两个数学问题在语义上可能相似。例如,许多问题可能使用“汤姆第一天吃了8个苹果……”,但它们可能测试加法、乘法和除法,这是非常不同的。在这种情况下,最好使用概念和级别的元数据对它们进行标记,并在检索它们之前检查正确的概念。

       另一个非常典型的情况是,块在拆分时可能会丢失信息。考虑一篇典型的文章,开头的句子通过名字介绍实体,而后面的句子只依靠代词来指代它们。不包含实际实体名称的分割块将失去语义,无法通过向量搜索进行检索。因此,在这种情况下,用实际名称替换代词可以提高分割块的语义意义。

       第二种技术是分块优化。根据你的下游任务是什么,你需要确定块的最佳长度是多少,以及你希望每个块有多少重叠。如果你的块太小,它可能不包括LLM回答用户查询所需的所有信息;如果块太大,它可能包含太多不相关的信息,从而混淆LLM,或者可能太大而无法适应上下文大小。

       根据我自己的经验,对于管道中的所有步骤,您不必拘泥于一种块优化方法。例如,如果您的管道同时涉及高级任务(如摘要)和低级任务(如基于函数定义的编码),则可以尝试使用较大的块大小进行摘要,然而使用较小的块大小作为编码参考。

       还有另一种技术是在尝试在矢量数据库中匹配用户的查询之前重写该查询。此步骤的本质是将用户的查询转换为与矢量数据库中的查询格式和内容类似的格式和内容。Query2Doc技术生成伪文档,并用这些文档扩展查询[5]。类似地,HyDE(假设文档嵌入)生成与查询相关的假设文档[6]。

        以下是一些如何生成假设文档的示例:

# if your reference documents are blog articles.prompt = f"Please generate a paragraph from a blog article on {user_query}"# if your reference documents are code documentations in markdown.prompt = f"Please generate a code documentation for {user_query} in markdown format."

       使用Query2Doc或HyDE技术时的一个陷阱是,假设文档可能与实际文档相矛盾或完全不一致,这可能导致不准确的检索。为了解决这个问题,您可以检索包含和不包含假设文档的文档,这样您就可以应用我稍后将介绍的后期检索技术来找到最佳参考文本。

       当用户的查询很复杂,可能需要多个参考文本时,可以使用LLM将其分解为多个子查询,然后为每个查询找到相关的文本块。例如,如果用户问两个不同的问题“ChomaDB和Weaviate之间的区别是什么?”,可以分为“什么是ChromaDB?”和“什么是Weaviate?”。

        下面是一个要求LLM分解查询的示例:

Please rephrase the following query into three or fewer subqueries, so that each sub-query contains only one topic. Show each sub-query in each new line.Query:"<original user query>"

       如果您的聊天机器人或代理可以处理多个下游任务和不同格式的用户查询,您可以考虑使用查询路由,在该路由中,您可以将查询动态路由到不同的RAG进程。例如,如果你的用户正在询问一个问题的特定答案,你可以将他们路由到查询特定的块;如果你的用户要求一个整体的摘要,你可以将他们路由到一个递归创建的许多检索到的文档的摘要;如果您的用户要求在两个文档之间进行比较,您可能需要使用上面提到的子查询技术。您可以使用LLM本身进行路由,也可以使用关键字匹配/嵌入相似性进行路由。

2.2 检索技术

       准备好查询后,可以在RAG管道的第二步中进一步改进检索结果。

       第一种技术经常被忽视,因为人们只是跟着别人做——一直坚持向量相似性搜索。但是,您可以也应该考虑使用其他搜索方法来取代向量相似性搜索,或者通过混合搜索来补充它。尽管矢量相似性搜索在大多数情况下可以找到相关文档,但对于某些情况或数据结构,最好使用全文搜索、结构化查询、基于图的搜索或混合搜索方法。

       例如,如果您的文本数据包含许多语义非常相似的块,但仅在某些关键字上有所不同,或者如果您的文字数据包含太多通用文字,则最好使用精确的关键字匹配进行搜索。例如,在电子商务中搜索仅按功能组不同的特定药物名称或数以万计的类似产品名称,可能会受益于全文匹配和过滤器。

       另一个经常被忽视的技术是针对特定任务测试和使用不同的嵌入。许多人甚至不会考虑这一点,因为框架/向量数据库有一个默认的嵌入选项,他们只是随波逐流。但不同的嵌入模型实际上可以捕获不同的语义信息,并可能适用于不同的任务。一个有用的嵌入模型是指导嵌入,它允许您提供关于嵌入的数据类型和任务的具体说明[7][8]。您也可以参考MTEB排行榜,它是文本嵌入模型的基准。一定要测试这些模型,因为在排行榜上排名靠前并不意味着它最适合你的特定任务[9]。

      除此之外,您还可以在检索过程中进行一些调整,使检索更具相关性。Small2big、递归或上下文感知检索是一种最初检索较小的数据块,由于更具体和更详细,这些数据块更有可能与查询匹配,然后继续检索父文档或围绕这些较小数据块的较大文本块,以包括更多上下文的技术。它们确保您检索相关的块以及所有重要的上下文。一些框架提供了对这种检索的支持,如LangChain[2]中的ParentDocumentRetriever、句子窗口和LlamaIndex[1]中的节点引用。

       如果您可以从小到大地检索文档,那么您也可以用另一种方式来检索,分层检索从更通用到更具体。例如,您可以创建两层数据,一层包含原始块,另一层包含块的摘要。您首先在摘要索引中搜索最相关的文档,然后在这些文档中再次搜索特定的块。这样,你可以在第一关快速过滤掉不相关的文档,然后在第二关找到实际的信息进行问答。

       类似地,您可以将递归搜索与图形搜索结合使用。该方法将相似性搜索与图形数据结构相结合。您首先通过向量相似性搜索找到最相关的块,然后探索与这些块相关的节点,以探索更多潜在的有用信息。例如,如果您有一个包含Notion或Obsidian等互连文档的数据库,则可以通过链接轻松找到LLM的相关文档。LlamaIndex通过RecursiveRetriever模块支持类似的搜索。

       还有更多的代理方式来执行检索,方法是首先使用查询文档的工具/功能创建检索器代理,并让它决定是搜索更多信息还是仅将相关的检索块返回给原始代理以回答用户的查询。但这些技术通常需要更长的响应时间,而且可能不稳定,因此可能不是很好的生产选择。希望通过更强大的模型和更快的推理,我们可以在这个方向上获得更好的结果。

2.3 后检索技术

       在从数据库中检索到相关的块之后,仍然有更多的技术可以提高生成质量。根据任务的性质和文本块的格式,您可以使用以下一种或多种技术。

       如果你的任务与一个特定的块更相关,一种常用的技术是重新排序或评分。正如我前面提到的,向量相似性搜索中的高分并不意味着它总是具有最高的相关性。你应该进行第二轮重新排序或评分,找出对生成答案真正有用的文本块。对于重新排序或评分,您可以要求LLM对文档的相关性进行排序,也可以使用一些其他方法,如关键字频率或元数据匹配,在将这些文档传递给LLM以生成最终答案之前,对选择进行细化。

       另一方面,如果你的任务与多个块有关——比如摘要或比较。您可以在将信息传递给LLM之前进行一些信息压缩作为后处理,以减少噪声或上下文长度。例如,您可以首先从每个块中总结、转述或提取关键点,然后将聚合的、浓缩的信息传递给LLM进行生成。

2.4 平衡质量和延迟

       我发现还有一些其他技巧可以帮助改进和平衡生成质量和延迟。在实际生产中,您的用户可能没有时间等待多步骤RAG过程完成,尤其是当存在LLM调用链时。如果您想提高RAG管道的延迟,以下选择可能会有所帮助。

       第一种是在某些步骤中使用更小、更快的模型。对于RAG过程中的所有步骤,您不一定需要使用最强大的模型(通常是最慢的)。例如,对于一些简单的查询重写、假设文档的生成或文本块的汇总,您可能可以使用更快的模型(如7B或13B本地模型)。这些模型中的一些甚至能够为用户生成高质量的最终输出。

      如果你感兴趣,你可以关于如何运行本地模型的信息[11],并在这个GitHub Repo[12]中查看我对一些小型LLM的评级。

       下一个技术是使一些中间步骤并行运行。你不必总是等到一步完成后再进入第二步。您可以进行一些中间步骤,如并行混合搜索或多个块并行的摘要。要做到这一点,您可能需要大量修改RAG框架或自己创建RAG管道,但这可以大大减少最终输出的时间。

      第三种技术是如果可能的话,让LLM做出多项选择,而不是生成长文本。例如,在重新排序/评分时,您可以要求LLM仅列出文本块的分数/排名,而不是将其生成或包括详细解释。

       另一个有用的提示是为常见问题或常见查询实现缓存。如果新查询与旧查询非常相似或几乎相同,则系统可以提供即时答案,而无需每次都经过整个RAG过程。如果新查询有点相似,但仍然相关,您甚至可以将上一个查询的答案包含到LLM中,作为生成新答案的参考。

三、结论

       在本文中,我介绍了许多可以在LLM支持的应用程序中改进RAG管道的技术,包括:

-RAG的基本过程:索引、检索和生成

-预检索技术:

  • 提高索引数据的质量
  • 块优化
  • 查询重写

-检索技术

  • 使用其他搜索方法
  • 使用不同的嵌入模型
  • Small2big、递归或上下文感知检索
  • 分层检索

-后期检索技术

  • 重新排序或对检索到的块进行评分
  • 信息压缩

-平衡质量和延迟

  • 在某些步骤中使用更小、更快的模型
  • 使中间步骤平行运行
  • 让LLM做出选择而不是生成
  • 实现缓存       

      您可以在RAG管道中使用其中一种或多种技术,使其更加准确和高效。我希望这些技术可以帮助你为你的应用程序构建一个更好的RAG管道。

参考文献:

[1] http://www.llamaindex.ai/

[2] http://www.langchain.com/

[3] http://www.pinecone.io/

[4] http://www.trychroma.com/

[5] https://browse.arxiv.org/abs/2303.07678

[6] https://browse.arxiv.org/abs/2212.10496

[7] https://browse.arxiv.org/abs/2212.09741

[8] https://github.com/xlang-ai/instructor-embedding

[9] https://huggingface.co/spaces/mteb/leaderboard

[10] https://doi.org/10.48550/arXiv.2312.10997

[11] https://medium.com/design-bootcamp/a-complete-guide-to-running-local-llm-models-3225e4913620

[12] https://github.com/Troyanovsky/Local-LLM-Comparison-Colab-UI

[13] https://bootcamp.uxdesign.cc/how-to-improve-rag-results-in-your-llm-apps-from-basics-to-advanced-822818014144

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/368092.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PADS VX 2.7安装记录

PADS 画PCB&#xff0c;Orcad用来画原理图&#xff0c;是一种常见的layout PCB板的方式。 一、资源&#xff1a; 资源1&#xff1a;百度云安装包&#xff1a;PADS VX 2.7 提取码&#xff1a;dbjm 二、安装 2.1 双击打开安装包 在PADS VX 2.7/PADSVX.2.7_ESDM文件夹下双击se…

DevOps落地笔记-11|持续集成:软件持续集成,发布信手拈来

上一讲我主要介绍了如何快速的构建环境&#xff0c;以及测试阶段对环境的要求。现在测试环境已经不是阻碍软件开发的障碍了&#xff0c;但另一个问题又出现了&#xff1a;每次测试结果不是不理想&#xff0c;就是问题太多无法继续测试。这是因为&#xff0c;团队成员平时都在自…

mysql升级到8.x

1.下载和安装 1.1.下载 mysql下载地址&#xff1a; https://dev.mysql.com/downloads/mysql/5.5.html?os31&version5.1 应该下载这个类似版本 mysql-8.0.36-linux-glibc2.17-x86_64-minimal.tar.xz 1.2 安装 解压&#xff1a; tar xvf mysql-8.0.36-linux-glibc2.17…

学习Spring的第十三天

非自定义bean注解开发 设置非自定义bean : 用bean去修饰一个方法 , 最后去返回 , spring就把返回的这个对象,放到Spring容器 一 :名字 : 如果bean配置了参数 , 名字就是参数名 , 如果没有 , 就是方法名字 二 : 如果方法产生对象时 , 需要注入数据 , 在方法参数设置即可 , …

Acwing---802.区间和

区间和 1.题目2.基本思想3.代码实现 1.题目 假定有一个无限长的数轴&#xff0c;数轴上每个坐标上的数都是 0。 现在&#xff0c;我们首先进行 n 次操作&#xff0c;每次操作将某一位置 x 上的数加 c。 接下来&#xff0c;进行 m次询问&#xff0c;每个询问包含两个整数 l 和…

基于Web停车场管理系统

技术架构&#xff1a; Spring MVC JSP MySQL 有需要该项目的小伙伴可以私信我你的Q。 功能描述&#xff1a; 基于Web停车场管理系统主要用于实现停车场相关信息管理&#xff0c;基本功能包括&#xff1a;系统信息管理模块、车位信息管理模块、IC卡信息管理模块、固定车主…

【Docker篇】Linux安装Docker、docker安装mysql、redis、rabbitmq

1.Linux安装docker 官方帮助文档&#xff1a;Install Docker Engine on CentOS | Docker Docs 1.1安装命令 # 1. 卸载之前的dockersudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate…

编程实例分享,眼镜店电脑系统软件,配件验光管理顾客信息记录查询系统软件教程

编程实例分享&#xff0c;眼镜店电脑系统软件&#xff0c;配件验光管理顾客信息记录查询系统软件教程 一、前言 以下教程以 佳易王眼镜店顾客档案管理系统软件V16.0为例说明 如上图&#xff0c; 点击顾客档案&#xff0c;在这里可以对顾客档案信息记录保存查询&#xff0c;…

Windows Server 2025 Active Directory 新变化

自 Windows Server 2016 以来&#xff0c;AD DS 尚未收到任何重大更新&#xff0c;并且 Server 2019/2022 中的功能级别没有增加。随着长期服务渠道 (LTSC) 中操作系统的下一个版本的发布&#xff0c;该版本暂且被称为 Windows Server 2025。 Windows Server 2025 新功能级别 …

C++ 日期类的实现

目录 前言 日期类中的成员函数和成员变量 日期类中成员函数的详解和实现 1.天数前后的判断 2.天数加减的实现 3.前置 && 后置 4.计算天数差值 前言 日期类的实现将综合前面所学的&#xff08;类的6个默认成员函数&#xff09;&#xff0c;进一步理解和掌握类的…

SOME/IP SD 协议介绍(四)服务发现通信行为

服务发现通信行为 启动行为 服务发现将根据服务实例处于以下三个阶段之一&#xff1a; • 初始等待阶段 • 重复阶段 • 主要阶段 一旦系统启动并且用于服务实例的接口连接已建立&#xff0c;服务发现将进入该服务实例的初始等待阶段。 在进入初始等待阶段并在发送第一条服…

【C++栈和队列:数据结构中的经典组合,高效处理先进先出与后进先出问题的最佳方案】

[本节目标] 1. stack的介绍和使用 2. queue的介绍和使用 3. priority_queue的介绍和使用 4. 容器适配器 1. stack的介绍和使用 1.1 stack的介绍 1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的…

c语言--求第n个斐波那契数列(递归、迭代)

目录 一、概念二、用迭代求第n个斐波那契数1.分析2.完整代码3.运行结果4.如果求第50个斐波那契数呢&#xff1f;看看会怎么样。4.1运行结果&#xff1a;4.2画图解释 三、用迭代的方式求第n个斐波那契数列1.分析2.完整代码3.运行结果4.求第50个斐波那契数4.1运行结果4.2运行结果…

2024/2/3 牛客寒假算法基础集训营1

目录 why买外卖 G-why买外卖_2024牛客寒假算法基础集训营1 (nowcoder.com) 要有光 L-要有光_2024牛客寒假算法基础集训营1 (nowcoder.com) why买外卖 G-why买外卖_2024牛客寒假算法基础集训营1 (nowcoder.com) 题目要求&#xff1a;这道题要求计算鸡排最贵为多少 思路&a…

C语言经典面试题——翻转单词顺序VS左旋转字符串

目录 1. 翻转单词顺序1.1 题目描述1.2 解法1.3 完整代码 2. 左旋转字符串2.1 题目描述2.1.1 解法一&#xff1a;2.1.2 解法二&#xff1a;2.1.2.1 strcpy2.1.2.2 strcat2.1.2.3 完整代码 2.1.3 解法三&#xff1a; 1. 翻转单词顺序 1.1 题目描述 输入一个英文句子&#xff0c;…

AI专题:2023年AI和标准化网络安全报告

今天分享的是AI系列深度研究报告&#xff1a;《AI专题&#xff1a;2023年AI和标准化网络安全报告》。 &#xff08;报告出品方&#xff1a;enisa&#xff09; 报告共计&#xff1a;37页 文件目的和目标 本文件的总体目标是概述与人工智能(AI)网络安全有关的标准(现有的、正在…

作业2024/2/3

第二章 引用内联重载 一&#xff0e;选择题 1、适宜采用inline定义函数情况是&#xff08;C&#xff09; A. 函数体含有循环语句 B. 函数体含有递归语句 C. 函数代码少、频繁调用 D. 函数代码多、不常调用 2、假定一个函数为A(int i4, int j0) {;}, 则执行“A (1);”语句…

三路快排解决TopK问题

前言&#xff1a; 我们首先要明白什么是三路快排&#xff0c;什么是topk问题。 三路快排&#xff1a; 思想&#xff1a; 三路快排就是数组分3块&#xff0c;三个指针&#xff0c;先随机取一个基准值key&#xff0c;然后将数组划分为3个部分&#xff1a; 【小于key】【等于…

【八大排序】冒泡排序 | 快速排序 + 图文详解!!

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构冒险记 ✅C语言进阶之路 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 交换排序一、冒泡排序1.1 算法步骤 动图演示1.2 冒泡排序的效率分析1.3 代码实现1.4 …

【Vue】组件间通信的7种方法(全)

目录 组件之前的通信方法 1. props/$emit 2.parent/children 3.ref 4.v-model 5.sync 6.attrs,attrs,attrs,listeners 7.provide/inject 7.eventBus 组件之前的通信方法 1. props/$emit 父传子 props 这个只能够接收父组件传来的数据 不能进行修改 可以静态传递 也可…
最新文章