赞
踩
1.1 定义
检索增强生成 (Retrieval-Augmented Generation, RAG) 是指在利用大语言模型回答问题之前,先从外部知识库检索相关信息。
早在2020年就已经有人提及RAG的概念(paper:Retrieval-augmented generation for knowledge-intensive nlp tasks),首版发布在arxiv于2020年5月,当年还是seq2seq的时代,但实验就已经发现,通过检索,能快速从海量知识中找到和原本问题相关的知识,借助知识带来的信息能提升生成效果。
RAG 的方法使得开发人员无需为每一个特定任务重新训练整个庞大的模型。他们可以简单地给模型加上一个知识库,通过这种方式增加模型的信息输入,从而提高回答的精确性。RAG 特别适用于那些需要大量知识的任务。
简而言之,RAG 系统包括两个主要阶段:
RAG 与其他模型优化方法的比较
在大语言模型的优化过程中,除了RAG,微调(finetune)也很常用。
正因为需要包含检索以及后续大模型的使用,所以RAG和原来常规的深度学习研究不太一样,他不是一个深度模型,更像是一个系统,系统里面可以有多个组件,一般的结构可用下面这张图来表示。
原始 RAG (Naive RAG) 代表了早期研究方法,在 ChatGPT 广泛应用后迅速崭露头角。
原始 RAG 的流程包括传统的索引、检索和生成步骤。
这里有一版基础RAG项目,这里最大程度还原最基础RAG的结构,github地址:GitHub - ZBayes/basic_rag: basic framework for rag(retrieval augment generation)
核心就是检索和大模型两个模块,把问答内容输入到数据库中,给定query,可以直接去数据库中搜索,搜索完成后把查询结果和query拼接起来送给模型即可,就如下图所示。
指的是在离线状态下,从数据来源处获取数据并建立索引的过程。具体而言,构建数据索引包括以下步骤:
Naive RAG 系统在实际应用中主要面临以下三个方面的挑战:
然而现实情况可能远不如这个这么简单,例如数据源可能就不是问答对的形式,此时无法进行检索,需要分块或者预处理,例如检索效果不足需要调优等,此时就有了高级的RAG。
RAG 被证明能显著提升答案的准确性,并特别是在知识密集型任务上减少模型的错误输出。通过引用信息来源,用户可以核实答案的准确性,从而增强对模型输出的信任。
此外,RAG 有助于快速更新知识并引入特定领域的专业知识。
RAG 有效结合了大语言模型的参数化知识和非参数化的外部知识库,成为实施大语言模型的关键方法之一。
高级的RAG能很大程度优化原始RAG的问题,主要的优化点会集中在索引、向量模型优化、检索后处理等模块进行优化。
论文:Retrieval-Augmented Generation for Large Language Models: A Survey
链接:https://arxiv.org/abs/2312.10997
翻译:面向大语言模型的检索增强生成技术:综述 [译] | 宝玉的分享
文章里对RAG的升级路径进行了详细解释,其中重点从检索模块、生成模块、整体等角度对RAG目前的关键技术进行了讲解。
总结:
一般我们都会在RAG中加入向量检索,而其中的关键就是向量表征模型,也就是embedding嵌入,向量表征模型的准确与否,决定了这一路检索的准确性,因此会对向量表征模型做优化。
微调embedding:针对特定问题、特定领域或者是特定的检索对,用特定的向量表征一般都会有比较好的效果,因此在有一定训练数据下,很推荐微调以获取更高的上限。
准是检索的首要要求,但不是唯一,检索回来的结果过于冗长或者重复对最终的记过都有影响,因此,还可以通过后处理来进一步优化。
当前的思路主要集中在混合检索、递归检索和子查询、HyDE等方案。
文章的思想是:在开始检索之前,先用query让模型生成一次答案,然后把query和答案合并送给模型。
举个例子,例如用户输入的是“儿童防沉迷”,原来是直接把“儿童防沉迷”直接用于检索,输入检索库中进行召回,然而现在,我们会结合prompt,先输入给大模型,并得到大模型的结果:
输入: 什么是儿童防沉迷。 要求,用大约100字回复。 ------------------ 输出:(结果来自chatglm2) 儿童防沉迷是指避免儿童沉迷于网络、游戏、电子书等电子娱乐活动,保护儿童身心健康和防止未成年人受到网络游戏沉迷、网络信息诈骗等问题的影响。为了实现这一目标,家长和社会应该共同努力,对儿童进行网络安全教育,限制儿童使用电子产品的时间和内容,并营造良好的家庭氛围,鼓励儿童积极参与有益身心的活动,如运动、阅读、艺术等。 |
可以看到,相比原始query儿童防沉迷,还拓展了大量的相关信息,例如游戏、网络、未成年人等,这些词汇很直观地,能扩展更多概念解释,对提升召回肯定是有好处的。
改写完了,但是要放进去检索,更好地进行召回,还是有些技巧的,按照论文,对字面检索和向量检索,都有一些特定的设计。
工业界的方案和思路更加偏向应用。
我分为检索调优、prompt、后处理、微调这几个方面。
文档的处理在很大程度会影响最终的检索效果,而检索效果的好坏基本决定了最终大模型生成效果,检索一旦错了,最终生成的结果就没什么希望能好了。
一般常见的就是长文本了,因为检索效果的限制,以及最终大模型的长度限制,我们是需要对长文本进行分段的,最简单的分段方法,就是按token数分,块(chunk)的大小取决于所使用的embedding模型以及LLM的context length,如Bert的token数是512,gpt-3.5-turbo的max tokens是4096。
让query和doc之间尽可能逼近,这里有相当多的技巧:
我们搜集到的文档的形式并不固定而且变化多样。
最简单的应该就是问答对了,我们不需要做很多的预处理,就可以进行qq匹配,qq匹配因为两者在语义空间上非常接近,所以难度骤降,但实际上,我们要面对的可能是结构化的数据,例如各种商品的结构化信息,生产日期、产品类别、重量、产地等,也可能非结构化的文段,文本可长可短,短到几个字,长到一本很厚书、一串晦涩的法律、专利、医学材料,甚至有表格、图像甚至公式等目前技术仍旧不容易解析的结构,我们需要做的,就是把他们转化为“可以检索”的模式。
正因为问题的多样性,我们不能局限在向量化然后向量召回这一个方案里,我这里举几个不好做向量召回的例子:
结合传统的基于关键字的搜索(稀疏检索算法,如 tf-idf 或搜索行业标准 BM25)和向量搜索,并将其结果组合在一个检索结果中。
融合搜索通常能提供更优秀的检索结果,因为它结合了两种互补的搜索算法——既考虑了查询和存储文档之间的语义相似性,也考虑了关键词匹配。
类似前面提到的索引构建可以多样性,检索策略也可以多样性。
这点在推荐系统里表现的非常明显,开荒期基本结束后的推荐系统,基本都会有多种召回方式,即我们常说的“多路召回”,通过多个渠道来源召回物料,检索这块也是如此,我们可以从很多角度来划分不同的召回链路,提升召回的多样性和完整性。来说几个比较常见的分路方法。
方法有很多,各种方法都有各自的优势,根据具体场景可以进行灵活选择,增加召回链路的目标就是尽可能保证希望找到的那一条数据在这个召回池子里。
而在多路召回之后,我们就要面对新的问题——合并,合并在推荐系统中逐步被演化成“排序”,在检索中也是如此,召回的多了,合并是目标之一,但最终是要从中再筛选出TOPN的,此处就变成了一个排序任务。
一般而言,会划分为这两类方法:
注意,时刻关注项目迭代的节奏和现状。
一方面,方案的选型要把握住最近的关键问题聚焦解决,例如召回都没召回回来,或者压根没有标注数据,此时需要关注的就不可能是排序层的优化,一定是先确保召回池子里有,逐步构造一些用于模型的数据,才能开始考虑模型的迭代;
另一方面,短期的方案选型要为后续的长期目标做准备,例如多路召回是后续的预期形态,那短期的设计就要考虑把每个召回链路的逻辑设计好,例如可拓展性、并行性等,有多个向量召回链路,则需要把离线训练和在线推理的pipeline设计好。
在完成检索后,我们能拿到我们最需要的若干个文档,再把他们扔进大模型之前,我们是需要后处理的。举几个例子:
这里提到的是一个特定的产品形态——对话引擎,而多轮的关键,其实就在于对上下文的理解和使用,比较简单可以实践的方式这里推荐两个:
查询路由的概念,这个在多轮对话里,其实有点像DP(dialogue policy),即对话策略,这个模块主要决定机器的回复模式,例如拒答、追问、回答问题、索要评价等,简单的可以配合意图识别和规则,就能够完成。
当然复杂的,可以结合大模型实现,让大模型来推理对话策略。
能让大模型来决策,其实就已经是agent的范畴了,就RAG这块,其实很多位置都可以构造agent协助进行各种策略的选择:
RAG的最后一步,最直接的方案,就是把查询得到的文档,配合query以及各种辅助信息(意图实体、对话策略、历史对话)进行合并得到prompt,发送给LLM生成答案。
复杂的方案有:
这种方法主要是对 编码器(embedding模型) 和 LLM 进行微调。其中,编码器影响嵌入质量,从而影响上下文检索质量。LLM 负责使用提供的上下文来回答用户查询。
如今的一大优势是可以使用像 GPT-4 这样的高端 LLM 来生成高质量的数据集。但是必须清楚,使用小型合成数据集进微调基础模型,可能会降低基础模型的通用能力。
编码器微调
作者进行了一项测试,对 bge-large-en-v1.5 编码器进行微调,发现对于检索效果提升影响有限。因为针对搜索优化的最新 Transformer 编码器已经非常高效。
排序器微调
如果不完全信任基础编码器,可以使用交叉编码器对检索到的结果进行重排。
这个过程是这样的:你把查询和每个前 k 个检索到的文本块一起送入交叉编码器,中间用 SEP (分隔符) Token 分隔,并对它进行微调,使其对相关的文本块输出 1,对不相关的输出 0。一个这种微调过程的成功案例可以在这里找到,结果显示通过交叉编码器微调,成对比较得分提高了 4%。
LLM 微调
最近,OpenAI 开始提供 LLM 微调 API,LlamaIndex 有一个关于在 RAG 设置中微调 GPT-3.5-turbo 的教程。RAG 管道评估的 ragas 框架显示,忠实度指标增加了 5%,这意味着微调后的 GPT 3.5-turbo 模型比原始模型更好地利用了提供的上下文来生成答案。
模块化RAG是对高级RAG的一种升级,这里面集成了大量优化策略,并将这些策略进行重组,形成完整的模块独立完成特定功能,其实很多内容和上面提及的很接近,只是更加模块化。论文里有提及很多模块,这些模块都是可以进行单独优化的。
RAG本就是一个高度组织性的项目,在迭代过程中,是需要对这些模块进行优化和调整的,而往里面新增模块。
主要有两种形式:
这里原文中有提及self-RAG,即会引入了一个主动判断的模块,这个思路还挺有意思的。
论文:[2310.11511] Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection
讲解:推特爆火!超越ChatGPT和Llama2,新一代检索增强方法Self-RAG来了 - 知乎
翻译:SELF-RAG - 自我反思的检索增强生成:学习检索、生成和批评 - 知乎
如图所示,左边是普通RAG的操作方法,先对query进行检索,然后把检索结果TOP N和原始query一起放入大模型,让大模型输出结果;
而右边,作者训练了模型,用于判断query和检索到的模型之间的关系,判断是否需要进一步检索以及本身回复的质量。
本文中,作者把这种分析文章质量与进一步检索称为RAG系统对自身的反思。
相比一般的RAG,这里本质上其实是多做了四个判断:
在效果评估上,对于整个RAG系统,是有端到端的评估方案的,例如答案相关性、答案准确性、忠实度等,当然也可以用和文本生成类似的方案去评估,例如用BLEU、Rouge之类的评估和标准答案的相关性了。
但是,正因为RAG本身是一个系统,内部每个步骤也是可以评估的,例如:
社区中有一个常见问题:“随着大模型Context Length的增加,RAG(检索增强生成)是否会消亡?”这个问题源于对RAG所解决的问题理解不足。
RAG解决的是知识依赖问题
RAG旨在解决知识依赖问题,这与大模型的Context Length并无直接关联。知识依赖是指模型在生成回答或执行任务时对外部信息的依赖。
模型对信息反馈的及时性不足
无论是大模型还是小模型,都存在对信息反馈及时性不足的问题。新发布的模型可能对新知识不了解,因为它们没有学习到新知识。要学习新知识,需要经过严格的训练和评估,且实时更新的难度很大。
显存优势
Transformer结构的模型,Context Length增加必然需要更多GPU显存,RAG检索的方式能在低显存占用的情况下高效利用文档信息。
解决方案
结论
只要知识依赖和知识更新的问题没有得到解决,RAG就有其存在的价值和一席之地。RAG通过结合检索和生成的方式,能够有效地利用外部信息来提升模型的性能。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。