中国建设教育网官网是什么网站,鲜花网站的网络营销与策划书,设计师关注的十大网站,wordpress插件pdf本文是对检索增强生成#xff08;Retrieval Augmented Generation, RAG#xff09;技术和算法的全面研究#xff0c;对各种方法进行了系统性的梳理。文章中还包含了我知识库中提到的各种实现和研究的链接集合。
鉴于本文的目标是对现有的RAG算法和技术进行概览和解释#…本文是对检索增强生成Retrieval Augmented Generation, RAG技术和算法的全面研究对各种方法进行了系统性的梳理。文章中还包含了我知识库中提到的各种实现和研究的链接集合。
鉴于本文的目标是对现有的RAG算法和技术进行概览和解释我不会深入代码实现的具体细节只会提及相关内容并推荐阅读详尽的文档和教程[1]。
介绍
如果你已经熟悉检索增强生成Retrieval Augmented Generation, RAG的概念请直接跳转到高级 RAG 部分。
检索增强生成Retrieval Augmented Generation, RAG是一种技术它通过从数据源中检索信息来辅助大语言模型Large Language Model, LLM生成答案。简而言之RAG 结合了搜索技术和大语言模型的提示词功能即向模型提出问题并以搜索算法找到的信息作为背景上下文这些查询和检索到的上下文信息都会被整合进发送给大语言模型的提示中。
到了2023年基于大语言模型的系统中RAG 已成为最受欢迎的架构之一。许多产品几乎完全基于 RAG 构建范围从结合了网络搜索引擎和大语言模型的问答服务到数以百计的“与数据对话”的应用程序。
即使是向量搜索领域也受到了这一趋势的推动尽管早在2019年就已经有基于 faiss[2] 构建的搜索引擎。像 chroma、weavaite.io 和 pinecone 这样的向量数据库初创公司是基于现有的开源搜索索引构建的主要是 faiss 和 nmslib它们最近还增加了对输入文本的额外存储和一些其他工具。
在基于大语言模型的管道和应用领域两个最著名的开源库分别是LangChain和LlamaIndex它们分别于2022年10月和11月成立彼此相差一个月。这两个库的创建受到了ChatGPT发布的启发并在2023年获得了广泛的采用。 本文的宗旨在于系统整理并介绍关键的高级检索增强生成Retrieval Augmented Generation, RAG技术并重点参考了 LlamaIndex 中的实现案例以便于其他开发者更深入地掌握这项技术。 现存的问题是大多数教程通常只选择介绍一两种技术的具体实现方法而未能涵盖所有可用工具的丰富多样性。 另外值得一提的是LlamaIndex和LangChain都是极为出色的开源项目。它们发展迅速以至于至今所累积的文档资料已比2016年的机器学习教科书还要庞大。 技术交流
前沿技术资讯、算法交流、求职内推、算法竞赛、面试交流(校招、社招、实习)等、与 10000来自港科大、北大、清华、中科院、CMU、腾讯、百度等名校名企开发者互动交流~
我们建了大模型面试与技术交流群 想要进交流群、需要源码资料、提升技术的同学可以直接加微信号mlc2060。加的时候备注一下研究方向 学校/公司CSDN即可。然后就可以拉你进群了。 方式①、微信搜索公众号机器学习社区后台回复技术交流 方式②、添加微信号mlc2060备注技术交流CSDN 用通俗易懂的方式讲解系列
用通俗易懂的方式讲解不用再找了这是大模型最全的面试题库用通俗易懂的方式讲解这是我见过的最适合大模型小白的 PyTorch 中文课程用通俗易懂的方式讲解一文讲透最热的大模型开发框架 LangChain用通俗易懂的方式讲解基于 LangChain ChatGLM搭建知识本地库用通俗易懂的方式讲解基于大模型的知识问答系统全面总结用通俗易懂的方式讲解ChatGLM3 基础模型多轮对话微调用通俗易懂的方式讲解最火的大模型训练框架 DeepSpeed 详解来了用通俗易懂的方式讲解这应该是最全的大模型训练与微调关键技术梳理用通俗易懂的方式讲解Stable Diffusion 微调及推理优化实践指南用通俗易懂的方式讲解大模型训练过程概述用通俗易懂的方式讲解专补大模型短板的RAG用通俗易懂的方式讲解大模型LLM Agent在 Text2SQL 应用上的实践用通俗易懂的方式讲解大模型 LLM RAG在 Text2SQL 上的应用实践用通俗易懂的方式讲解大模型微调方法总结用通俗易懂的方式讲解涨知识了这篇大模型 LangChain 框架与使用示例太棒了用通俗易懂的方式讲解掌握大模型这些优化技术优雅地进行大模型的训练和推理用通俗易懂的方式讲解九大最热门的开源大模型 Agent 框架来了
基础RAG
本文讨论的检索增强生成Retrieval Augmented Generation, RAG管道的起点是一系列文本文档。在此之前的所有内容比如数据的获取和加载都是由功能强大的开源数据加载工具完成的这些工具可以连接到各种数据源从Youtube到Notion都能涵盖。 A scheme by author, as well all the schemes further in the text
基础 RAG 的操作流程大致如下首先你需要将文本切分成小段然后利用某种 Transformer 编码器模型将这些文本段转换成向量形式。接着把所有向量汇集到一个索引里。最后你需要为大语言模型Large Language Model, LLM制定一个提示词这个提示词会指导模型根据我们在搜索步骤中找到的上下文信息来回答用户的查询。
在实际运行过程中我们会用同一个编码器模型把用户的查询转换成向量然后根据这个向量在索引中进行搜索。系统会找到最相关的前k个结果从数据库中提取相应的文本段然后把这些文本段作为上下文信息输入到大语言模型的提示词中。
提示词的具体形式可以是这样的
def question_answering(context, query):prompt fGive the answer to the user query delimited by triple backticks {query}\using the information given in context delimited by triple backticks {context}.\If there is no relevant information in the provided context, try to answer yourself, but tell user that you did not have any relevant context to base your answer on.Be concise and output the answer of size less than 80 tokens.response get_completion(instruction, prompt, modelgpt-3.5-turbo)answer response.choices[0].message[content]return answer在改进RAG管道的方法中优化提示词Prompt Engineering[3]是最具成本效益的尝试。不要忘记查阅OpenAI提供的全面的提示优化指南[4]。
虽然 OpenAI 作为大语言模型LLM的提供者在市场上占据领先地位但还有许多其他选择如 Anthropic 的 ClaudeMistral 的 Mixtral 等最近流行的小型但功能强大的模型Microsoft 的 Phi-2以及众多开源选择如 Llama2、OpenLLaMA、Falcon 等为您的 RAG 管道提供了多种“大脑”选择。
高级RAG
现在我们来深入了解高级RAG技术的概述。这里是一个展示核心步骤和相关算法的示意图。为了保持示意图的清晰易懂一些逻辑循环和复杂的多步骤智能体行为被省略了。 高级RAG架构的一些关键组件。它更多的是一个可用工具的选择而不是一个蓝图。
在这个方案中绿色部分代表我们接下来将深入探讨的核心 RAG 技术而蓝色部分则表示文本。需要注意的是并不是所有高级 RAG 概念都能在这样一个单一的方案中被清晰展示比如一些用于扩展上下文的方法就没有包括在内 —— 我们会在后续的讨论中逐一探究这些话题。
1. 分块和向量化
首先我们需要创建一个向量索引这个索引代表了我们文档的内容。然后在程序运行时我们会搜索这些向量与查询向量之间的最小余弦距离以找到语义上最接近的匹配。
1.1 分块
Transformer 模型的输入序列长度是固定的即使输入上下文窗口很大用一个句子或几个句子的向量来代表它们的语义含义通常比对几页文本进行平均向量化更为有效。因此需要对数据进行分块处理将文档切分成合适大小的段落同时保持其原有意义不变例如将文本划分为句子或段落而不是将单个句子切割成两部分。市面上有多种文本分割工具可用于此任务。
需要考虑的一个参数是块的大小这取决于你使用的嵌入模型及其处理token的能力。例如基于BERT的标准Transformer编码器模型最多处理512个token而OpenAI ada-002能处理更长的序列如8191个token。但这里需要权衡的是为大语言模型提供足够上下文以进行推理与实现高效搜索所需的足够具体的文本嵌入。关于选择块大小的研究[5]可以在LlamaIndex的NodeParser[6]类中找到该类提供了一些高级选项比如定义自己的文本分割器、元数据、节点/块关系等。
1.2 向量化
接下来的步骤是选择一个模型来嵌入这些文本块。有很多种模型可以选择我推荐使用像bge-large[7]或E5[8]嵌入系列这样的搜索优化模型。可以查看MTEB排行榜[9]来获取最新的模型信息。
要实现分块和向量化的端到端操作可以参考LlamaIndex中一个完整的数据输入流程示例[10]。
2.搜索索引
2.1向量存储索引 在这个方案及文中后续内容中为了保持方案的简洁性我省略了编码器Encoder这一环节直接将查询内容发送至索引。当然查询内容在此之前已经被转换成了向量形式。这同样适用于前k个块的处理——索引实际检索的是前k个向量而非块本身但在这里我以块的形式呈现它们因为从索引中提取这些块是一个简单的步骤。
在RAG管道中至关重要的部分是搜索索引它用来存储我们在前一步骤中生成的向量化内容。最基础的实现方式是使用flat索引它通过暴力法计算查询向量与所有块向量之间的距离。
一个高效的搜索索引针对超过10000个元素的大规模检索进行了优化例如使用faiss、nmslib或annoy这样的向量索引。这些索引采用近似最近邻方法如聚类、树状结构或HNSW算法。
还有一些像OpenSearch或ElasticSearch这样的托管解决方案和向量数据库它们在幕后处理第1步中描述的数据摄入过程例如Pinecone、Weaviate或Chroma。
根据您选择的索引类型、数据和搜索需求您还可以将元数据与向量一起存储然后使用元数据过滤器来搜索特定日期或来源的信息。
LlamaIndex支持多种向量存储索引类型但也支持其他更简单的索引实现方式如列表索引、树索引和关键词表索引——我们将在后面的融合检索部分进一步讨论这些索引类型。
2.2 层次索引 如果您需要从大量文档中检索信息高效的搜索方法非常关键这样才能找到相关信息并将其汇总为一个包含源引用的统一答案。在处理大型数据库时一个有效的做法是创建两个索引——一个由摘要组成另一个由文档块组成然后分两步进行搜索首先通过摘要过滤出相关文档接着只在这个相关群体内进行搜索。
2.3 假设性问题和HyDE
另一个方法是让LLM为每个块生成一个假设性问题并将这些问题以向量形式嵌入。在运行时针对这个问题向量的索引进行查询搜索用问题向量替换我们索引中的块向量检索后将原始文本块作为上下文发送给LLM以获取答案。这种方法由于查询和假设性问题之间的语义相似性更高从而提高了搜索质量。
还有一种反向逻辑的方法叫做HyDE[11]——您可以让LLM根据查询生成一个假设性回答然后将该回答的向量与查询向量一起用来提高搜索质量。
2.4 上下文增强
这里的理念是检索较小的块以提高搜索质量但同时增加周围的上下文以供LLM进行推理分析。
有两种方法——一是通过在检索到的较小块周围添加句子来扩展上下文二是递归地将文档分割成多个包含较小子块的大型父块。
2.4.1 句子窗口检索[12]
在这种方案中文档中的每个句子都被单独嵌入向量这样做可以提高查询到上下文的余弦距离搜索的准确度。
为了更好地推理分析找到的上下文我们会在检索到的关键句子前后各扩展k个句子然后将这个扩展的上下文发送给LLM。
绿色部分代表在索引搜索中找到的句子的向量表示而整个黑色加绿色的段落会被输入到大语言模型LLM中目的是在分析提供的查询时扩大其上下文范围。
2.4.2 自动合并检索器又名父文档检索器[13]
这里的思路与句子窗口检索器十分相似——它旨在搜索更精细的信息片段然后在将这些上下文信息提供给LLM进行推理之前先扩展上下文窗口。文档被分割成较小的子块这些子块又与更大的父块相对应。 文档被分割成一个层级化的块结构随后最小的叶子块被发送至索引中。在检索过程中我们会检索出k个叶子块。如果存在n个块都指向同一个更大的父块那么我们就用这个父块来替换这些子块并将其送入大语言模型LLM用于生成答案。
在检索过程中首先获取较小的数据块。如果在前k个检索到的块中有超过n个块指向同一个父节点即更大的块那么我们就用这个父节点来替换原先提供给大语言模型LLM的上下文内容。这个过程类似于自动将几个小块合并成一个更大的父块因此得名。需要注意的是这种搜索仅在子节点的索引中进行。想要更深入了解这个方法可以查看LlamaIndex关于递归检索器和节点引用的教程[14]。
2.5 融合检索或混合搜索
这是一个相对较旧的概念它结合了两种不同的搜索方法一种是基于关键词的传统搜索方法使用稀疏检索算法如tf-idf或行业标准BM25另一种是现代的语义或向量搜索。这两种方法被融合在一起以产生一个综合的检索结果。
这里的关键是正确结合具有不同相似度评分的检索结果。这个问题通常通过Reciprocal Rank Fusion算法[15]解决该算法会对检索结果进行重新排名以产生最终输出。 说明了查询转换原则
在LangChain中这一功能是通过Ensemble Retriever[16]类实现的它结合了您定义的一系列检索器例如faiss向量索引和基于BM25的检索器并使用逆序位融合算法RRF来进行结果的重新排名。
在LlamaIndex中实现这一功能的方式非常类似。[17]
混合或融合搜索通常能提供更好的检索结果因为它结合了两种互补的搜索算法既考虑了查询与存储文档之间的语义相似性也考虑了关键词的匹配。
3. 重新排名和过滤
因此我们使用上述任何一种算法得到了检索结果接下来需要通过过滤、重新排名或进行一些转换来进一步优化这些结果。LlamaIndex提供了多种后处理器可以基于相似度评分、关键词、元数据等过滤结果或者使用其他模型进行重新排名如LLM、句子-转换器交叉编码器[18]、Cohere重新排名端点[19]或者基于元数据如日期的新近性来进行——几乎涵盖了你能想到的所有情况。
这是在将检索到的上下文输入到大语言模型LLM以得到最终答案之前的最后一步。
现在我们将介绍更高级的RAG技术如查询转换和路由这两者都涉及到LLM因此代表了智能体行为——涵盖了我们RAG管道中涉及到的一些复杂的大语言模型推理逻辑。
4. 查询转换
查询转换是一组技术它们使用LLM作为推理引擎来修改用户输入以此提高检索质量。实现这一目标有多种不同的方法。
如果查询内容复杂大语言模型LLM可以将其分解为几个子查询。例如如果您问
—— “在Github上Langchain和LlamaIndex哪个框架的star更多”我们不太可能直接在语料库中找到这样的比较因此将这个问题分解为两个假设更简单和具体信息检索的子查询是合理的
——“Langchain在Github上有多少star”
——“LlamaIndex在Github上有多少star”
这些查询将并行执行然后检索到的上下文将组合在一个提示中供大语言模型综合出对初始查询的最终答案。两个库都实现了这一功能——Langchain中作为多查询检索器[20]在LlamaIndex中作为子问题查询引擎[21]。 回退式提示词[22]使用大语言模型生成更一般的查询检索我们获得的更一般或高级的上下文有助于为我们原始查询的答案打下基础。也对原始查询进行检索最终生成答案时将两个上下文输入大语言模型。这是LangChain的实现方式[23]。 查询重写使用大语言模型重新构造初始查询以提高检索效果。LangChain[24]和LlamaIndex[25]都有实现尽管有些不同但我认为LlamaIndex的解决方案在这里更为强大。
参考引用
这一部分没有编号因为它更像是一个工具而非一种检索改进技术尽管它非常重要。
如果我们使用了多个来源来生成答案无论是由于初始查询的复杂性我们不得不执行多个子查询然后将检索到的上下文合并为一个答案还是因为我们在不同文档中找到了单个查询的相关上下文就会出现一个问题即我们是否能准确地反向引用我们的来源。
有几种方法可以做到这一点 将这个引用任务插入我们的提示中并要求大语言模型提及所使用来源的ID。 将生成的响应的部分与我们索引中的原始文本块匹配——llamaindex为这种情况提供了一种基于模糊匹配的高效解决方案[26]。如果你没有听说过模糊匹配这是一种非常强大的字符串匹配技术[27]。
5. 对话引擎
在构建一个能够对单个搜索查询反复有效工作的高效 RAG 系统中下一个关键进展是聊天逻辑的开发。这种逻辑考虑到对话上下文其原理类似于LLM时代之前的经典聊天机器人。
这种逻辑的开发是为了支持用户提出后续问题、处理上下文中的指代或与先前对话上下文相关的任意命令。为了解决这一问题研究者们采用了一种查询压缩技术这种技术在处理用户的查询时同时考虑了聊天的上下文。
关于上下文的压缩有几种不同的方法 — 一种受欢迎且相对简单的方法是使用 ContextChatEngine[28]。这种引擎首先检索与用户查询相关的上下文然后将其连同聊天历史从内存缓冲区一起发送给 LLM确保 LLM 在生成下一条回答时能够理解之前的上下文。 更为复杂的一个例子是 CondensePlusContextMode[29]。在这种模式下每次互动中的聊天历史和最后一条消息会被压缩成一个新的查询。然后这个查询被发送到索引系统检索到的上下文连同原始用户消息一起回传。
值得注意的是LlamaIndex 还支持基于 OpenAI 智能体的聊天引擎[30]提供了更灵活的聊天模式Langchain 也支持[31] OpenAI 功能性 API。 还有其他聊天引擎类型如ReAct Agent[32]本部分内容会在第7节中详细介绍。
6. 查询路由
查询路由是一种基于LLM的决策步骤用于确定针对用户的查询接下来应采取的行动。通常的选项包括概括回答、针对某个数据索引执行搜索或尝试多条不同的途径然后将它们的结果综合成一个答案。
查询路由器还用于选择合适的索引或更广泛的数据存储位置来处理用户查询。这可能涉及多个数据来源比如传统的向量存储、图数据库或关系型数据库或者是一个索引层级结构。在多文档存储情况下一个常见的设置是一个概要索引和另一个文档块向量的索引。
设置查询路由器涉及确定它能做出的选择。路由选项的选择是通过 LLM 的调用来实现的返回的结果按照预定义的格式来引导查询到指定的索引。或者如果涉及多智能体行为它可以引导到子链或其他智能体如下面的多文档智能体方案所示。
LlamaIndex[33] 和 LangChain[34] 都支持查询路由器。
7. RAG 中的智能体
智能体Langchain[35] 和 LlamaIndex[36] 都支持自从第一个 LLM API 发布以来就已存在。其核心理念是为具备推理能力的 LLM 提供一套工具和一个待完成的任务。这些工具可能包括确定性函数如代码功能或外部 API或其他智能体。正是这种 LLM 链接的思想促成了 LangChain 的命名。
智能体本身是一个非常广泛的领域在 RAG 概述中无法深入探讨因此我将直接继续讨论基于智能体的多文档检索案例并简要介绍 OpenAI 助手。OpenAI 助手是在最近的 OpenAI 开发者大会上作为 GPTs 提出的相对较新的概念[37]并在下面描述的 RAG 系统中发挥作用。
OpenAI Assistants[38]集成了许多围绕LLM必需的工具这些工具我们以前在开源项目中已经见过 —— 包括聊天记录管理、知识库存储、文档上传界面以及最关键的功能调用 API[39]。这个 API 的重要功能是能够将自然语言请求转换为外部工具或数据库查询的 API 调用。
在 LlamaIndex 中OpenAIAgent[40] 类融合了这些高级功能并与 ChatEngine 和 QueryEngine 类结合提供了基于知识的、具有上下文感知能力的聊天体验。此外它还能在一次对话交互中调用多个 OpenAI 功能从而真正实现智能代理行为。
接下来让我们来了解一下多文档代理方案[41] —— 这是一个相当复杂的设计涉及到在每个文档上初始化一个代理OpenAIAgent这个代理不仅能进行文档摘要处理还能执行经典的问答流程。还有一个顶级代理负责将查询任务分配给各个文档代理并合成最终答案。
每个文档代理配备了两种工具 —— 向量存储索引和摘要索引它会根据接收到的查询决定使用哪个工具。对于顶级代理来说所有文档代理都是其工具可供其调度使用。
这个方案展示了一个高级的 RAG 架构涉及每个代理做出的复杂路由决策。这种架构的优势在于它可以比较不同文档中描述的不同解决方案或实体以及它们的摘要同时也支持经典的单文档摘要处理和问答流程 —— 这实际上覆盖了大多数与文档集合交互的常见用例。
这是一个展示多文档代理工作方式的方案其中包括了查询的路由处理和代理的智能行为模式。
这个复杂方案的一个缺点可以通过图像来理解 —— 由于需要在代理内部与大语言模型LLM进行多轮迭代因此处理速度较慢。需要注意的是在 RAG 架构中调用 LLM 总是最耗时的步骤而搜索则是出于设计考虑而优化了速度。因此对于涉及大量文档的存储系统我建议对这一方案进行简化以提高其扩展性。
8. 响应合成器
这是 RAG 架构中的最后一步 —— 基于我们精心收集的所有上下文和用户的初步查询来生成答案。
最简单的方法是直接将所有相关度较高的上下文和查询串联起来一次性输入到LLM中。
然而还有一些更复杂的方法这些方法涉及多次使用LLM来细化检索到的上下文并据此生成更加准确的答案。响应合成的几种主要方法包括 将检索到的上下文分块后逐次发送给大语言模型LLM以此迭代地精炼答案。 总结检索到的上下文使其适应输入提示。 基于不同上下文块生成多个答案然后将这些答案连接或总结起来。
更多细节请参考响应合成器模块的文档[42]。
编码器和LLM微调
这个方法涉及对我们 RAG 架构中的两种深度学习模型之一进行精细调整。这可以是负责生成高质量嵌入从而影响上下文检索效果的 Transformer 编码器也可以是用于最佳地利用所提供上下文以回答用户问题的LLM— 幸运的是后者非常擅长少样本学习。
目前一个重要的优势是我们能够使用像 GPT-4 这样的高端大语言模型来创造高质量的合成数据集。
但同时我们也必须认识到对一个由专业团队在大型、经过精心筛选和清洗的数据集上训练的开源模型进行快速而简单的调整尤其是使用小型合成数据集时可能会限制模型的整体性能和能力。
编码器的微调
我曾对编码器的微调持保留态度因为最新的为搜索优化的 Transformer 编码器已经非常高效了。
所以我在 LlamaIndex notebook[43]环境中测试了 bge-large-en-v1.5[44]在撰写本文时该模型在 MTEB 排行榜上排名前四的微调效果。测试结果表明检索质量提高了 2%。虽然这个提升不是非常显著但了解这一微调选项还是有益的特别是在为特定领域的数据集构建 RAG 时。
Ranker的微调
另一个传统的选择是如果你对基础编码器的效果不完全满意可以使用一个交叉编码器来重新评估你检索到的结果。
这个方法的工作原理是这样的 —— 你需要将查询语句和检索到的前 k 个文本块一起传递给交叉编码器每部分之间用 SEP token 分隔并对其进行微调以便对相关的文本块输出 1对不相关的输出 0。 这种调整过程的一个很好的例子可以在这里[45]找到结果显示通过交叉编码器的微调成对得分提升了 4%。
LLM的微调
OpenAI 最近推出了大语言模型微调 API[46]LlamaIndex 也提供了一个教程[47]介绍如何在 RAG 环境下微调 GPT-3.5-turbo从而“吸收”GPT-4 的部分知识。这个过程包括使用一份文档利用 GPT-3.5-turbo 生成问题然后用 GPT-4 基于该文档内容回答这些问题即构建一个由 GPT-4 驱动的 RAG 架构接着对 GPT-3.5-turbo 进行微调训练它处理这些问题与答案对。通过这种方式使用 ragas[48] 框架进行的 RAG 架构评估显示信实度指标提高了 5%意味着经过微调的 GPT 3.5-turbo 在利用提供的上下文生成答案方面比原模型表现得更好。
Meta AI Research 最近的一篇论文《RA-DIT: Retrieval Augmented Dual Instruction Tuning》展示了一种更为复杂的方法它提出了一种同时对LLM和检索器原论文中的双编码器进行微调的技术这种微调是基于查询、上下文和答案的三元组进行的。具体实施细节请参考相关指南[49]。这种技术被用于通过微调 API 对 OpenAI 大语言模型进行微调同时也用于开源模型 Llama2如原论文所述在知识密集型任务的指标上实现了约 5% 的提升与使用 RAG 的 Llama2 65B 相比并在常识推理任务上也有一定的提升。
评估
RAG 系统的性能评估通常涉及多个独立的指标包括整体答案的相关性、答案的根据性、信实度以及检索到的上下文的相关性等。
之前提到的 Ragas 主要利用信实度[50]和答案相关性[51]作为评估生成答案质量的指标并使用传统的上下文精确度[52]和召回率[53]来评估 RAG 架构的检索效果。
Andrew NG 最近推出的精彩短课程《构建和评估高级 RAG》[54]中结合 LlamaIndex 和评估框架 Truelens提出了 RAG 的三大评估维度检索到的上下文与查询的相关性、答案的根据性大语言模型的答案在多大程度上得到提供的上下文的支持以及答案对查询的相关性。
最关键也是最容易控制的指标是检索到的上下文相关性。实际上高级 RAG 架构的前 1-7 部分以及编码器和排名器的微调部分都是为了提高这一指标而第 8 部分和大语言模型的微调则侧重于提高答案的相关性和根据性。
关于简单的检索器评估流程的一个很好的例子可以在这里找到[55]它在编码器微调部分得到了应用。一个更高级的方法考虑到了不仅仅是命中率还有平均倒数排名一种搜索引擎常用的指标以及生成答案的信实度和相关性指标这在 OpenAI cookbook[56]中有展示。
LangChain 提供了一个先进的评估框架 LangSmith[57]不仅可以实现自定义的评估方法还可以监控在 RAG 架构内部运行的流程从而增加系统的透明度。
如果你正在使用 LlamaIndex 进行构建那么有一个 rag_evaluator llama[58] 包它提供了一个快捷的工具可以利用公共数据集来评估你的架构。
结论
我努力概述了 RAG 的核心算法方法并通过一些示例展示它们希望这能激发你在自己的 RAG 架构中尝试一些新思路或者对今年推出的众多技术有更系统的理解 —— 对我而言2023 年是迄今为止机器学习领域最令人兴奋的一年。
还有很多其他方面需要探索如基于网络搜索的 RAG例如 LlamaIndex、webLangChain[59] 的 RAGs[60]、更深入地研究智能体架构[61]以及关于大语言模型长期记忆功能的一些构想[62]。
RAG 系统在生产中的主要挑战除了答案的相关性和信实度之外还包括速度尤其是在采用更灵活的基于智能体的方案时更是如此但这需要另外的讨论。ChatGPT 和许多其他助手所采用的流式特性并不是随机的赛博朋克风格而是为了缩短用户感知的答案生成时间。这也是我认为小型大语言模型以及近期发布的 Mixtral 和 Phi-2 等产品在未来将大有可为的原因。
相关链接
[1] https://app.iki.ai/playlist/236 [2] https://faiss.ai/ [3] https://docs.llamaindex.ai/en/latest/examples/prompts/prompts_rag.html [4] https://platform.openai.com/docs/guides/prompt-engineering/strategy-write-clear-instructions [5] https://www.pinecone.io/learn/chunking-strategies/ [6] https://docs.llamaindex.ai/en/stable/api_reference/service_context/node_parser.html [7] https://huggingface.co/BAAI/bge-large-en-v1.5 [8] https://huggingface.co/intfloat/multilingual-e5-large [9] https://huggingface.co/spaces/mteb/leaderboard [10] https://docs.llamaindex.ai/en/latest/module_guides/loading/ingestion_pipeline/root.html# [11] https://boston.lti.cs.cmu.edu/luyug/HyDE/HyDE.pdf [12] https://docs.llamaindex.ai/en/stable/examples/node_postprocessor/MetadataReplacementDemo.html [13] https://python.langchain.com/docs/modules/data_connection/retrievers/parent_document_retriever [14] https://docs.llamaindex.ai/en/stable/examples/retrievers/recursive_retriever_nodes.html [15] https://plg.uwaterloo.ca/~gvcormac/cormacksigir09-rrf.pdf [16] https://python.langchain.com/docs/modules/data_connection/retrievers/ensemble [17] https://docs.llamaindex.ai/en/stable/examples/retrievers/reciprocal_rerank_fusion.html [18] https://www.sbert.net/examples/applications/cross-encoder/README.html [19] https://txt.cohere.com/rerank/ [20] https://python.langchain.com/docs/modules/data_connection/retrievers/MultiQueryRetriever?refblog.langchain.dev [21] https://docs.llamaindex.ai/en/stable/examples/query_engine/sub_question_query_engine.html [22] https://arxiv.org/pdf/2310.06117.pdf?refblog.langchain.dev [23] https://github.com/langchain-ai/langchain/blob/master/cookbook/stepback-qa.ipynb?refblog.langchain.dev [24] https://github.com/langchain-ai/langchain/blob/master/cookbook/rewrite.ipynb?refblog.langchain.dev [25] https://llamahub.ai/l/llama_packs-fusion_retriever-query_rewrite [26] https://github.com/run-llama/llama-hub/tree/main/llama_hub/llama_packs/fuzzy_citation [27] https://github.com/run-llama/llama-hub/tree/main/llama_hub/llama_packs/fuzzy_citation [28] https://docs.llamaindex.ai/en/stable/examples/chat_engine/chat_engine_context.html [29] https://docs.llamaindex.ai/en/stable/examples/chat_engine/chat_engine_condense_plus_context.html [30] https://docs.llamaindex.ai/en/stable/examples/chat_engine/chat_engine_openai.html [31] https://python.langchain.com/docs/modules/agents/agent_types/openai_multi_functions_agent [32] https://docs.llamaindex.ai/en/stable/examples/chat_engine/chat_engine_react.html [33] https://docs.llamaindex.ai/en/stable/module_guides/querying/router/root.html [34] https://docs.llamaindex.ai/en/stable/module_guides/querying/router/root.html [35] https://python.langchain.com/docs/modules/agents/ [36] https://docs.llamaindex.ai/en/latest/use_cases/agents.html# [37] https://openai.com/blog/new-models-and-developer-products-announced-at-devday [38] https://platform.openai.com/docs/assistants/overview [39] https://platform.openai.com/docs/assistants/overview [40] https://docs.llamaindex.ai/en/stable/examples/agent/openai_agent.html [41] https://docs.llamaindex.ai/en/stable/examples/agent/multi_document_agents.html [42] https://docs.llamaindex.ai/en/stable/module_guides/querying/response_synthesizers/root.html [43] https://docs.llamaindex.ai/en/stable/examples/finetuning/embeddings/finetune_embedding.html [44] https://huggingface.co/BAAI/bge-large-en-v1.5 [45] https://docs.llamaindex.ai/en/latest/examples/finetuning/cross_encoder_finetuning/cross_encoder_finetuning.html# [46] https://platform.openai.com/docs/guides/fine-tuning [47] https://docs.llamaindex.ai/en/stable/examples/finetuning/openai_fine_tuning.html [48] https://docs.ragas.io/en/latest/index.html [49] https://docs.llamaindex.ai/en/stable/examples/finetuning/knowledge/finetune_retrieval_aug.html#fine-tuning-with-retrieval-augmentation [50] https://docs.ragas.io/en/latest/concepts/metrics/faithfulness.html [51] https://docs.ragas.io/en/latest/concepts/metrics/answer_relevance.html [52] https://docs.ragas.io/en/latest/concepts/metrics/context_precision.html [53] https://docs.ragas.io/en/latest/concepts/metrics/context_recall.html [54] https://learn.deeplearning.ai/building-evaluating-advanced-rag/ [55] https://github.com/run-llama/finetune-embedding/blob/main/evaluate.ipynb [56] https://github.com/openai/openai-cookbook/blob/main/examples/evaluation/Evaluate_RAG_with_LlamaIndex.ipynb/ [57] https://docs.smith.langchain.com/ [58] https://github.com/run-llama/llama-hub/tree/dac193254456df699b4c73dd98cdbab3d1dc89b0/llama_hub/llama_packs/rag_evaluator [59] https://blog.langchain.dev/weblangchain/ [60] https://github.com/run-llama/rags [61] https://blog.langchain.dev/openais-bet-on-a-cognitive-architecture/ [62] https://blog.langchain.dev/adding-long-term-memory-to-opengpts/