RAG(检索增强生成)的前世今生
作者: 那个曾经的少年回来了 来源: 那个曾经的少年回来了
RAG技术(Retrieval-Augmented Generation, 检索增强生成),通过整合外部数据的方式,有效地解决使用大语言模型时出现的幻觉、过时的知识、不透明及无法溯源的问题,提高了生成结果的准确性和可信度。
RAG技术发展阶段
RAG的发展历程包括预训练(pre-training)、微调(fine-tuning)及推理(inference)。
最初,RAG技术的诞生恰逢Transformer架构的兴起,最开始专注于给预训练(pre-training) 模型增加额外的知识来提高模型效果;
随后ChatGPT的出现体现了大语言模型强大的上下文学习(in-context learning, ICL)能力,RAG的研究也转向为给LLMs提供更丰富、及时的信息,从而能够回答出更复杂的知识密集型的推理(inference) 任务。
再往后,RAG也不仅限于推理阶段,转而走向更具挑战的微调(fine-tunin) 技术。
RAG技术概览
下图展示了RAG技术的典型应用:用户向 ChatGPT 提出有关最近广泛讨论的新闻的问题,由于缺乏最新的相关数据,因此无法做出正确的回答(灰色流程)。**
而RAG通过从外部数据获取和整合知识来弥补信息差距(收集与用户问题相关的新闻),这些文章与用户问题相结合形成了全面的上下文,使LLMs能够生成更为准确的回答。(蓝色流程)
RAG的流程包含三个步骤,1、索引(Indexing) ,将文档分割成多个数据块,编码成向量后存储在向量数据库;2、检索(Retrieval) ,根据语义相似性检索与问题最相关的前K个数据块;3、生成(Generation) ,将原始问题和检索返回的块一起提交给LLMs从而生成最终的回答。
RAG的发展分为三个阶段:Naive RAG、Advanced RAG、Modular RAG 。
Naive RAG
Naive RAG是最早的方法,遵循传统的索引、检索、生成,没有添加过多的技术优化,也被称为“检索-读取”框架。
索引,聚焦于将PDF、HTML、Word及Markdown等不同格式的原始数据统一转为纯文本的格式。同时分割成适当大小的、更易于理解的数据块。为后面的搜索召回做准备。
检索,收到查询请求后,RAG系统采用与索引步骤相同的编码模型,将查询语句转为向量表示,根据索引语料库中的块向量计算相似分数,返回最相似的前K个块。
生成,将用户问题和检索返回的数据块组合成一个prompt,利用LLMs的强大理解能力按照要求生成结果。如果是持续对话,则过去的对话历史都可以集成到prompt中,从而实现多轮对话的效果。
Naive RAG方案在检索步骤的缺点是精确度和召回率,容易出现错位或者不相关的数据块,丢失关键信息。
Advanced RAG
Advanced RAG通过提高检索质量来克服Naive RAG的局限,在检索步骤的前后做了优化,通过滑动窗口、细粒度分段、合并元数据来改进索引技术。
Pre-retrieval process(预检索过程),重点是优化索引结构和查询优化.
优化索引的目标是提高索引内容的质量,常见的策略如:增强数据粒度、优化索引机构、添加元数据、混合检索。
查询优化的目标是将用户的原始问题进行“改写”,从而让用户的问题更清晰、更适合检索出优质结果。常见的方法包括查询改写、查询扩展。
Modular RAG
相比于前两种方法,Modular RAG引入了额外的专门组件来增强检索和处理能力。检索模块适应特定场景,能够直接搜索数据源,比如搜索引擎、数据库、知识图谱。
RAG-Fusion采用多查询策略将用户的查询诉求扩展到了不同的视角,并利用向量搜索和重排技术来优化结果,解决传统搜索的局限性。**
内存模块利用LLM的内存来引导检索,创建一个无限内存池,不断迭代、自我增强更紧密地与数据分布对齐。
预测模块直接通过LLM生成上下文,确保相关性和准确性、减少冗余和噪声。任务适配器模块将RAG制定为下游任务,为zero-shot生成自动的检索语句,给few-shot查询生成特定任务的检索器。这种全面的方法检索了检索流程,提高检索到的信息的质量和相关性。
还有一些创新性的方法,如Rewrite-Retrieve-Read模型,利用LLM的能力重写模块和LLM反馈机制来优化检索查询,从而更新重写模型,提高任务效果。Generate-Read是一种利用LLM生成的内容替代传统检索,Recite-Read是一种强调从模型权重中检索,增强模型处理知识密集型任务的能力。混合检索整合了关键词、语义和向量检索,以满足多样化查询的诉求。
RAG和Fine-tuning(微调)
RAG经常与微调(Fine-tuning)、提示工程(prompt engineering)技术进行比较。如下图所示,从External Knowledge(外部知识)和Model Adaptation(模型适应)两个角度来说明这三种方法的差异。**
提示工程利用模型固有的能力,最小限度地需要外部知识和模型适应;RAG可以被看做是基于特定任务定制的内容做信息检索,适合精确的信息检索任务;而微调类似于内化(静态)的知识,适用于需要复制特定结构或风格的场景。
Retrieval(检索)
在RAG中做到高效检索涉及到几个关键问题:检索数据源、检索粒度、检索预处理,及选择的Embedding模型。
检索数据源
最初的检索数据源是纯文本,后来扩展到半结构化数据(PDF)和结构化数据(知识图谱、数据库)。最近的趋势还包括用LLMs自身生成的内容进行检索和增强。
半结构化数据一般是包含了文本和表格的数据,传统的RAG在处理半结构化数据会有两个问题。
一是文本分块过程会把本来是完整数据的表格分离,导致检索的过程中数据缺失。
二是将表格整合到数据中心会使得语义相似性检索变得复杂、不精确。
对于处理半结构化数据,可以利用LLMs的写SQL的能力,在数据库中执行Text-2-SQL查询语句;另一种办法是把表格转为文本数据,再进一步分析。
结构化数据通常是经过验证的、能够提供更精确的信息。比如知识图谱类的数据,能增强LLMs对于图的理解和问答能力,不过需要额外的工作来构建、验证和维护结构化的数据库。
LLMs生成的内容,可以经过挑选后进行有选择性的增强。有些方案中运用了LLM生成器替换了检索器,能够更好地与因果语言建模的预训练目标对齐,从而生成更准确的答案。这种方法强调了在RAG中扩展更多的数据源,提高模型的性能和任务效果。
检索粒度
理论上,粗粒度(更大的数据块)可以提供更多相关信息,但也会包含冗余内容而成为噪声,这会分散检索器和下游任务中的语言模型的注意力。
但细粒度的检索也存在问题,增加了检索的负担、不能保证语意完整和满足问题所需的知识。**
文本的粒度从细到粗,大致可以分为 标签、短语、句子、命题、数据块、文档。有些文章选择以命题作为检索单元,被认为是原子表达式,每个命题都包含一个独特的信息段落,并以简介、自包含的信息呈现。这种方法旨在提高检索的进度和相关性。
索引优化
索引阶段,文档被处理、分块,并转为Embedding存储到向量数据库中,索引构建的质量决定了在检索阶段能否获得正确的数据块。**
常见的分块策略是将文档分割成固定数量的标记块。较大的块包含更多的上下文,也会带来噪声、需要更长的处理时间和成本。较小的块无法完全传达必要的上下文,噪声少。
数据分块会引起句子内截断,促使优化递归分割和滑动窗口的方法,可以通过合并跨越多个检索过程的全局相关信息实现分层检索。
不过,上面的这些方法仍然无法在语义完整和上下文长度之间取得平衡。有个Small2Big方案已经被提出,其中句子(小)被用作检索单元,并且提供前后句子作为(大)上下文。
元数据组件
数据块可以通过页码、文件名、作者、分类及时间等元数据来丰富,为后续的过滤、检索做准备。在检索过程中给文档时间戳分配不同的权重可以实现时间感知的RAG检索,可以确保信息的及时性。**
人工构建元数据也是一种思路,比如给每个段落增加摘要、引入可能的假设性问题等。在检索时计算原始问题和假设问题之间的相似度,从而减少问题与答案之间的语义差距,提高效果。
索引结构化
把文档内容构建出层次结构,即:分层索引结构,可以加快数据的检索和处理。**
把文件以父子目录的关系排列,通过数据块链接到它们,把数据摘要存储在每个节点上,有助于快速遍历数据并协助RAG确定目标数据块。
利用层次结构构建知识图谱索引,有助于数据结构的保持一致性,阐述了不同概念和实体之间的联系,减少幻觉的可能性。同时将信息检索的过程转换为LLM可以理解的指令、提高检索准确性。比如:把文档的段落或结构设置为图谱的节点,段落间的语义相似性/词汇相似性/文档关系设置为边。这种关系的知识给到LLM能有效提高知识检索和推理的效果。
查询优化
Naive RAG的主要问题是直接依赖用户的原始提问作为检索的基础。
让用户提出精确和清晰的问题很难,有时候用户也不知道该如何提问,尤其是问题本身的复杂性也会导致语言组织不好、有歧义,有些模糊的缩写词在不同的场景意义不一样。比如,LLM指的是大语言模型(Large Language Model)还是法学硕士(Master of Laws)?
因此在查询步骤需要做相应的优化来减少歧义、提高精度。常见的方法包括查询扩展、查询转换、查询路由。
查询扩展
查询扩展可以采用多查询、子查询的方法来实现。
多查询,通过LLMs基于用户的问题生成多个相关的问题并行查询,查询的语句通过精心设计(比如参考用户查询的历史记录)。
子查询,本身是在问题拆解的过程中就会被引入,从而在组合时将原始问题结合起来让回答更准确。添加相关上下文的过程类似查询扩展,但可以通过从最少到最多的提示方法,把复杂的问题分解为一些列更简单的子问题。
验证链,在扩展后查询后经过LLM验证,减少幻觉、提高结果可靠性。
查询转换
本质上是根据转换后的查询语句,而非用户的原始查询来检索数据块。比如查询重写、生成查询。**
查询重写指的是利用用户的问题,加上LLM来重新改写查询语句,这些LLM一般是某个垂直领域下训练出来的,可以增加检索的召回率。
另一种查询转换的方法是使用LLM根据原始查询生成新的查询以供后续检索。这种方法需要在构建查询文档的时候把生成的问题也构建到数据块中。它侧重于Embedding答案之间的相似性,而非问题或者查询的Embedding相似性。
查询路由
根据查询语句来路由到不同的RAG管道,适用于不同场景的多功能RAG系统。
元数据路由器/过滤器,根据查询中的关键词,选出最匹配的数据块从而缩小搜索范围。
还有一种语义路由器,利用查询的语义信息选择合适的路由。
Embedding
在RAG中,检索是通过计算问题和数据块的Embedding的相似度(如余弦相似度)来实现的,其中Embedding的语义表示能力起关键作用。包括稀疏编码器(BM25)和密集检索器(BERT架构预训练语言模型)。最近出现的还有AngIE、Voyage、BGE等。**
在上下文与预训练语料库明显不同的情况下,比如高度专业化的学科中(医疗保健、法律实践等),则需要用该领域的数据集来微调Embedding模型、以减少这种差异性。除了补充领域知识之外,微调的另一个目的是对齐检索器和生成器。
Generation(生成)
检索后,并不能把检索到的信息直接丢给LLM来生成问题的回答。冗余信息会干扰LLM最终的生成结果,过长的上下文也会引起LLM“迷失在中间”问题。LLM往往只关注长文本的开头和结尾,而忘记了中间部分。
所以通常需要对检索到的内容做进一步处理。一般从两个角度调整:调整检索内容和调整LLM。
重新排序
对检索回来的结果重排序,以突出最相关的结果、有效地减少整体文档内容。既作为增强器又作为过滤器,为更精确的语言模型处理提供精细化的输入。重新排序可以使用基于规则的方法进行,这些方法依赖于预定义的度量标准,如多样性、相关性和 MRR,或者使用基于模型的方法。**
上下文选择/压缩
RAG 过程中的一个常见误解是,认为尽可能检索多个相关文档并将它们连接起来形成一个冗长的检索提示是有益的。然而,过多的上下文可能会引入更多噪音,降低LLM对关键信息的感知。
LLMLingua 利用小语言模型(SLMs)如 GPT-2 Small 或 LLaMA-7B,检测并移除不重要的标记,将其转化为人类难以理解但LLMs能够理解的形式。这种方法提供了一种直接而实用的提示压缩方法,消除了对LLMs的额外训练的需要,同时平衡了语言完整性和压缩比。
LLM微调
基于场景和数据特征的有针对性微调可以产生更好的结果。这也是使用本地部署LLMs的最大优势之一。当LLMs在特定领域缺乏数据时,可以通过微调向LLM提供额外的知识。Huggingface的微调数据也可以作为初始步骤使用。**
微调的另一个好处是能够调整模型的输入和输出。例如,它可以使LLM适应特定的数据格式,并按照指示生成特定风格的响应。对于涉及结构化数据的检索任务,SANTA框架实施了三部分的训练方案,以有效地包含结构和语义细微差别。初始阶段侧重于检索器,对比学习被利用来优化查询和文档嵌入。
通过强化学习将LLM的输出与人类或检索器的偏好进行对齐是一种潜在的方法。例如,手动注释最终生成的答案,然后通过强化学习提供反馈。除了与人类偏好对齐外,还可以与经过精细调整的模型和检索器的偏好对齐。当情况阻碍了对强大的专有模型或更大参数的开源模型的访问时,一种简单有效的方法是提炼更强大的模型(例如GPT-4)。
Augmentation(增强)
在RAG领域,标准做法涉及一次检索步骤,然后生成答案,但通常不足以解决需要多步推理的复杂问题,因为提供的信息是有限的。
许多研究已经针对这个问题优化了检索流程,如下图:
除了最常见的一次性检索之外,RAG还包括三种检索增强过程。
迭代检索 (左,ITERATIVE),涉及在检索和生成之间交替进行,允许在每一步从知识库中获得更丰富和更有针对性的上下文。
基于初始查询和迄今为止生成的文本,重复搜索知识库,为LLMs提供更全面的知识库。这种方法已被证明通过多次检索迭代提供额外的上下文参考,从而增强了后续答案生成的鲁棒性。然而,它可能受到语义不连续和无关信息的积累的影响。
递归检索 (中,RECURSIVE),涉及逐渐细化用户查询并将问题分解为子问题,然后通过检索和生成持续解决复杂问题。
该过程涉及根据先前搜索结果获得的结果迭代地优化搜索查询,旨在通过反馈循环逐渐收敛于最相关的信息,从而增强搜索体验。
为了解决特定的数据场景,递归检索和多跳检索技术被一起使用。递归检索涉及使用结构化索引以层次化方式处理和检索数据,这可能包括在执行基于摘要的检索之前对文档或长PDF的部分进行总结。随后,在文档内进行二次检索以细化搜索,体现了该过程的递归性质。相比之下,多跳检索旨在深入图结构化数据源,提取相互关联的信息
自适应检索 (右,ADAPTIVE),侧重于使RAG系统能够自主确定是否需要外部知识检索以及何时停止检索和生成,通常利用LLM生成的特殊标记进行控制。
让LLMs 主动确定检索的最佳时机和内容,从而提高了信息检索的效率和相关性。如:AutoGPT、Toolformer、WebGPT项目。
RAG的未来发展
RAG与长上下文
随着研究的深入,LLMs 的上下文不断扩展,目前,LLMs 可轻松处理超过 20w字的上下文。而Moonshot已经逐步开放200w字的上下文了。
这种能力意味着基于长文档的问答,以前依赖于RAG,现在可以直接将整个文档合并到提示中。
这也引发了关于当LLMs不受上下文限制时,RAG是否仍然必要的讨论。事实上,RAG仍然发挥着不可替代的作用。
一方面,一次性为LLMs提供大量上下文将显著影响其推理速度,而分块检索和按需输入可以显著提高操作效率。
另一方面,基于RAG的生成可以快速定位LLMs的原始参考资料,以帮助用户验证生成的答案。整个检索和推理过程是可观察的,而仅依赖长上下文的生成仍然是一个黑匣子。
相反,上下文的扩展为RAG的发展提供了新的机会,使其能够解决更复杂的问题和需要阅读大量材料才能回答的综合或摘要问题。在超长上下文的背景下开发新的RAG方法是未来研究的趋势之一。
RAG的鲁棒性
噪音或矛盾信息在检索过程中可能会对RAG的输出质量产生不利影响。这种情况在比喻上被称为“错误信息可能比没有信息更糟糕”。
改进RAG对这种对抗性或事实不确的输入的抵抗力是一个重要研究方向,并已成为一个关键的性能指标。Cuconasu等人分析了应该检索哪种类型的文档,评估了文档与提示的相关性、它们的位置以及上下文中包含的数量。
混和方法
将RAG与微调相结合也是一种前沿的研究方向。确定RAG和微调的最佳整合方式,无论是顺序、交替还是通过端到端联合训练,以及如何利用参数化和非参数化优势,都是值得探索的领域。
另一个趋势是将具有特定功能的SLM引入RAG,并通过RAG系统的结果进行微调。例如,CRAG训练了一个轻量级的检索评估器,用于评估查询的检索文档的整体质量,并根据置信水平触发不同的知识检索操作。
**RAG在生产环境的应用
RAG的实用性及工程上的对齐的诉求使得它在生产环境中广泛使用。提高检索效率,改进大型知识库中的文档召回,并确保数据安全——例如通过LLMs防止文档来源或元数据的无意泄露——是尚待解决的关键工程挑战。
RAG生态系统的发展受其技术堆栈的进展影响很大。像LangChain和LLamaIndex这样的关键工具随着ChatGPT的出现迅速传播,提供了广泛的与RAG相关的API,并成为LLMs领域中不可或缺的部分。
除了专注于人工智能的供应商外,传统软件和云服务提供商也在扩大其产品范围,包括以RAG为中心的服务。提供智能企业搜索服务,使用户能够使用内置连接器浏览各种内容存储库。
在 RAG 技术的发展中,存在明显的不同专业化方向的趋势,例如:1)定制化 - 调整 RAG 以满足特定要求。2)简化 - 使 RAG 更易于使用,以减少初始学习曲线。3)专业化 - 优化 RAG 以更好地服务生产环境。形成如下图的RAG生态环境。
多模态RAG
除了文本,将RAG应用在图像、音频、视频、代码等扩展从而催生出创新的多模态方案。针对图像、音频等数据的检索、生成,也是当前在研究的重点方向。
本文基于论文 Retrieval-Augmented Generation for Large Language Models: A Survey (https://arxiv.org/abs/2312.10997),加上自己的理解总结而成。
更多AI工具,参考Github-AiBard123,国内AiBard123