【读书笔记】Foundations-of-LLMs 检索增强生成

Posted by Masutangu on April 25, 2025

本文是《Foundations-of-LLMs》 第六章【检索增强生成】的笔记。

RAG 架构分类

本小节将RAG 架构分类两大类:黑盒增强架构白盒增强架构,如下图所示。其中,黑盒增强架构可根据是否对检索器进行微调分为两类:无微调检索器微调。类似的,白盒增强架构也可根据是否对检索器进行微调分为两类:仅微调大语言模型检索器与大语言模型协同微调(下文简称为协同微调)。

除了调整检索器和大语言模型,我们也可对其他功能模块(如知识库中的向量)进行调整。

黑盒增强架构

无微调

In-Context RALM 是该框架下的代表性方法。其直接将检索器检索到的文档前置到输入问题前作为上下文。In-Context RALM 包括检索和生成两个阶段。在检索阶段,输入的问题或部分句子作为查询从知识库中检索出相关文档。在生成阶段,这些检索到的文档被直接拼接到 Prompt 中的上下文部分,然后将 Prompt 输入给大语言模型。

检索器微调

REPLUG LSR 是检索器微调框架的代表性方法,其结构如下图所示。

使用大语言模型的困惑度分数作为监督信号来微调检索器,使其能更有效地检索出能够显著降低语言模型困惑度的文档。微调检索器的过程中采用 KL 散度损失函数来训练检索器,目的是将检索到的文档的分布与这些文档对语言模型性能提升的贡献分布进行对齐。此过程涉及两个关键的概率分布:

  • 检索器输出的文档的分布:检索器在接收到当前上下文后检索与之相关的文档,并形成一个文档概率分布。
  • 文档对语言模型的贡献分布:语言模型为每个被检索到的文档和原始上下文来生成预测,最终所有输出结果形成一个概率分布。在这个分布中,如果某个文档对语言模型生成准确预测特别关键,它会被赋予更高的概率权重。

在微调过程中,REPLUG LSR 将语言模型视为黑盒处理,仅通过模型的输出来指导检索器的训练。在微调过程中,REPLUG LSR 还采用了一种异步索引更新策略,在一定的训练步骤之后才更新知识库的向量编码。这种策略降低了索引更新的频率,减少了计算成本,使模型能够在连续训练过程中更好地适应新数据。

AAR 方法通入引入额外的小型语言模型,使用它的交叉注意力得分标注偏好文档,以此来微调检索器,使其能够在不微调目标语言模型的情况下增强其在不同任务上的表现。

白盒增强架构

根据是否对检索器进行微调分为两类:仅语言模型微调检索器和语言模型协同微调

仅微调语言模型

仅微调语言模型指的是检索器参数保持不变,大语言模型根据检索器提供的上下文信息,对自身参数进行微调。

RETRO 是代表性方法之一。该方法通过修改语言模型的结构,使其在微调过程中能够将从知识库中检索到的文本直接融入到语言模型中间状态中,从而实现外部知识对大语言模型的增强。RETRO 首先将知识库中的文本进行切块,然后用 BERT 对每个文本块生成嵌入向量。在微调模型时的自回归过程中,每当模型生成一段文本块后,从知识库中检索出与之最相似的嵌入向量。然后,这些嵌入向量和模型注意力层的输出一起被送入一个外部的 Transformer 编码器进行编码。得到的编码向量直接输入给模型的块交叉编码器的键(key)和值(value),以捕捉外部知识的关键信息。通过交叉编码,模型能够结合检索到的相关信息来生成新的文本块。

SELF-RAG 通过在微调语言模型时引入反思标记,使语言模型在生成过程中动态决定是否需要检索外部文本,并对生成结果进行自我批判和优化。这些方法不仅提高了生成内容的质量和事实准确性,还增强了模型的知识整合与应用能力。

检索器和语言模型协同微调

在检索器和语言模型协同微调的架构中,检索器和语言模型的参数更新同步进行

Atlas 是该架构的代表性工作。与 REPLUG LSR 类似,其在预训练和微调阶段使用 KL 散度损失函数来联合训练检索器和语言模型,以确保检索器输出的文档相关性分布与文档对语言模型的贡献分布相一致。不同之处在于,Atlas 在预训练和微调过程中,检索器和语言模型参数同步被更新,检索器学习向语言模型提供最相关的文档,而语言模型则学习如何利用这些文档来改善其对查询的响应。为了确保检索结果与模型最新状态保持同步,Atlas 同样需要定期更新语料库文档的向量编码,从而维持检索的准确性。

知识检索

检索器

检索器可分为判别式检索器生成式检索器两类。

判别式检索器

判别式检索器通过判别模型对查询和文档是否相关进行打分。判别式检索器通常分为两大类:稀疏检索器稠密检索器。稀疏检索器利用离散的、基于词频的文档编码向量进行检索,而稠密检索器则利用神经网络生成的连续的、稠密向量对文档进行检索。

稀疏检索器(Sparse Retriever)是指使用稀疏表示方法来匹配文本的模型。这类检索器通过统计文档中特定词项出现的统计特征来对文档进行编码,然后基于此编码计算查询与知识库中的文档的相似度来进行检索。典型的稀疏检索技术包括 TF-IDF 和 BM25 等,它们通过分析词项的分布和频率来评估文档与查询的相关性。

稠密检索器一般利用预训练语言模型对文本生成低维、密集的向量表示,通过计算向量间的相似度进行检索。按照所使用的模型结构的不同,稠密检索器大致可以分为两类:交叉编码类Cross-Encoder)、双编码器类(Bi-Encoder)。

交叉编码类“端到端”的给出查询和文档的相似度。将查询和文档拼接在一起,随后利用预训练语言模型作为编码器(例如 BERT)生成一个向量表示。接着,通过一个分类器处理这个向量,最终输出一个介于 0 和1 之间的数值,表示输入的查询和文档之间的相似程度。其优点在于模型结构简单,能够实现查询和文档之间的深度交互。由于交叉编码类模型需要进行高复杂度的交叉注意力操作,计算量大,因此不适合在大规模检索阶段使用。这种模型更适用于对少量候选文档进行更精确排序的阶段,可以显著提升检索结果的相关性。

双编码类模型分两个步骤,首先查询和文档首先各自通过独立的编码器生成各自的向量表示,接下来对这两个向量之间的相似度进行计算,以评估它们的相关性。这种方法的优势在于,它允许预先离线计算并存储所有文档的向量表示,在线检索时则可直接进行向量匹配。因此非常适合在工业环境中部署,具有极高的匹配效率。

为了缓解查询与文档在提取特征向量时缺乏交互的问题,可以在双编码器的基础上引入查询与文档的交互,以进一步提升双编码器的效果。ColBERT 是其中的代表性方法。其以查询和文档间的 Token 级的相似度为度量,然后通过对比学习对双编码器进行微调,以使双编码器编码的特征向量可以兼顾查询和文档。

查询的长度急剧增长,传统的检索方法可能难以有效的处理这些长查询。为解决此问题,可以采用 Poly-encoder。其模型架构沿用双编码器的形式,但是它使用 m 个向量来捕获长查询的多个特征,而不是像普通双编码器那样只用一个向量来表示整个查询。并且,这 m 个向量随后与文档的向量通过注意力机制进行交互,其中的注意力模块采用查询和文档间的对比学习进行训练。

生成式检索器

生成式检索器通过生成模型对输入查询直接生成相关文档的标识符。与判别式检索器不同,生成式检索器直接将知识库中的文档信息记忆在模型参数中。然后,在接收到查询请求时,能够直接生成相关文档的标识符(即 DocID),以完成检索。生成式检索器通常采用基于 Encoder-Decoder 架构的生成模型,如 T5、BART 等。

生成式检索器的训练过程通常分为两个阶段。在第一阶段,模型通过序列到序列的学习方法,学习如何将查询映射到相关的文档标识符。这一阶段主要通过最大似然估计(MLE)来优化模型,确保生成的文档标识符尽可能准确。在第二阶段,通过数据增强和排名优化进一步提高检索效率和准确性。数据增强主要通过生成伪查询或使用文档片段作为查询输入,以增加训练数据的多样性和覆盖面。排名优化则涉及使用特定的损失函数,如对比损失或排名损失,来调整模型生成文档标识符的顺序和相关性,从而更好地匹配查询的需求。

检索效率增强

相似度索引算法

在向量检索中,常用的索引技术主要分成三大类:基于空间划分的方法基于量化方法基于图的方法

基于空间划分的方法将搜索空间划分为多个区域来实现索引,主要包括基于树的索引方法和基于哈希的方法两类。常见的基于树的索引包括 KD 树和 Ball 树等。而基于哈希的方法包括局部敏感哈希(LSH)等。

基于图的方法通过构建一个邻近图,将向量检索转化为图的遍历问题。基于图的代表性方法有 NSW、IPNSW 和 HNSW 等。

基于乘积量化(Product Quantization,PQ)的方法通过将高维向量空间划分为多个子空间,并在每个子空间中进行聚类得到码本和码字,以此作为构建索引的基础。在某些需要精度更高的应用场景中,我们可以在 PQ 的基础上进一步进行精确排序,以得到精确的最近邻结果。此外,还有一些乘积量化的优化算法以及和其他索引相结合的算法,如OPQ 、IVFPQ 等。

检索结果重排

检索器可能检索到与查询相关性不高的文档。这些文档如果直接输入给大语言模型,可能会引发生成质量的下降。我们需要对检索到的文档进行重新排序,简称重排,然后从中选择出排序靠前的文档。重排方法主要分为两类:基于交叉编码的方法基于上下文学习的方法

基于交叉编码的重排方法

基于交叉编码的重排方法利用交叉编码器(Cross-Encoders)来评估文档与查询之间的语义相关性。MiniLM-L 是应用最为广泛的基于交叉编码的重排开源模型之一。该模型通过减少层数和隐层单元数来降低参数数量,同时采用知识蒸馏技术从大型、高性能的语言模型中继承学习,以此来提高模型性能。

基于上下文学习的重排方法

基于上下文学习的方法是指通过设计精巧的 Prompt,使用大语言模型来执行重排任务。RankGPT 是基于上下文学习的重排方法中的代表性方法。在重排任务中,输入文档长度有时会超过上下文窗口长度的限制。为了解决该问题,RankGPT 采用了滑动窗口技术来优化排序过程。通过分步处理的方法,RankGPT 能够有效地对整个文档集合进行排序,而不受限于单一窗口所能处理的文档数量。

生成增强

检索器得到相关信息后,将其传递给大语言模型以期增强模型的生成能力。利用这些信息进行生成增强是一个复杂的过程,不同的方式会显著影响 RAG 的性能。

何时增强

判断是否需要增强的核心在于判断大语言模型是否具有内部知识。方法可以分为两类:

  • 外部观测法:通过 Prompt 直接询问模型是否具备内部知识,或应用统计方法对是否具备内部知识进行估计,这种方法无需感知模型参数
  • 内部观测法:通过检测模型内部神经元的状态信息来判断模型是否存在内部知识,这种方法需要对模型参数进行侵入式的探测

外部观测法

询问

可以通过直接询问和多次询问两种询问方法来判断大语言模型是否具备内部知识。在直接询问时,我们可以编写 Prompt 直接询问大语言模型是否需要外部知识。然而,大语言模型很难做到“知之为知之”,其存在“过度自信”的问题:对于无法回答的问题,大语言模型经常认为自己不需要外部知识的帮助,因此这种判断方式的准确率较低。采用多次询问时,我们可以通过让大语言模型重复多次地回答同一个问题,然后根据其回答的一致性判断其是否具备内部知识。这种方式同样面临着模型因过度自信而“执拗”地一直给出相同的错误答案的情况。并且,多次询问还需要耗费大量的时间和计算资源,在实际使用中可行性较低。

观察训练数据

大语言模型所具备的内部知识来源于其训练数据。因此,如果模型的训练数据中不包含当前问题的相关信息,那么,模型自然也就未曾习得相应的知识。对于训练数据中出现频率很低的知识,模型对它们的学习程度可能也是比较低的,即知识在训练数据中的出现频率与模型对该知识的记忆程度是正相关的。可以通过判断训练数据中是否包含相应的知识来判断模型是否掌握了相应的知识。然而,这种方式存在一定的局限性。首先,由于大语言模型的训练数据规模已经达到了数万亿级别,因此这种统计的手段非常耗时。此外,对于许多商业大语言模型,例如 ChatGPT、GPT4 等,它们的训练数据并不是公开可获取的。

构造伪训练数据统计量

训练数据不可获取时,我们可以设计伪训练数统计量来拟合训练数据的相关情况。比如,由于模型对训练数据中低频出现的知识掌握不足,而对更“流行”(高频)的知识掌握更好,因此实体的流行度作可以作为伪训练数据统计量。代表性工作《When not to trust language models》 利用Wikipedia 的页面浏览量来衡量实体的流行度,浏览量越大,表明该实体越流行,也就更可能被大语言模型所记忆。可以通过设定一个流行度阈值来判别模型是否具备相应的内部知识。然而,这种流行度的定义依赖于数据形成时间,并且未必能精准拟合训练数据的分布,因此存在一定的局限性。

内部观测法

大语言模型在生成文本时,是对输入序列进行建模和预测,模型内部状态的变化反映了模型对当前上下文理解和下一步预测的确定性。如果模型表现出较高的内部不确定性,如注意力分布较为分散激活值变化较大等,就可能对当前上下文缺乏充分的理解,从而无法做出有把握的预测。

模型的内部知识检索主要发生在中间层的前馈网络中《Locating and Editing Factual Associations in GPT》),因此在处理包含或不包含内部知识的不同问题时,模型的中间层会展现出不同的动态变化。基于这一特性,我们可以训练分类器进行判别,这种方法被称为探针。Liang 等人 针对三种类型的内部隐藏状态设计了探针实验,分别是注意力层输出、MLP 层输出和隐层状态。对于每个输入问题,研究者利用训练好的探针,即线性分类器,来根据问题所对应的内部表示预测该问题是属于模型“已知”(即模型具备相关知识)还是“未知”(即模型缺乏相关知识)。结果显示,不同大语言模型在利用中间层的内部表示进行分类时,均能够实现较高的分类准确率。这表明中间层的内部隐藏状态能够有效地反映模型对问题的理解和相关知识储备。

何处增强

得益于大语言模型的上下文学习能力、注意力机制的可扩展性以及自回归生成能力,其输入端、中间层和输出端都可以进行知识融合操作。在输入端,可以将问题和检索到的外部知识拼接在 Prompt 中,然后输入给大语言模型;在中间层,可以采用交叉注意力将外部知识直接编码到模型的隐藏状态中;在输出端,可以利用外部知识对生成的文本进行后矫正

输入端增强

良好的 Prompt 设计和外部知识排序,可以使模型更好地理解、利用外部知识。在设计 Prompt 的过程中,可以运用 CoT 等 Prompt 技巧。输入端增强的方法直观且易于实现,但对大语言模型的长文本处理能力和上下文理解能力要求较高。

在中间层增强

在中间层增强增强的方法利用注意力机制的灵活性,先将检索到的外部知识转换为向量表示,然后将这些向量插入通过交叉注意力融合到模型的隐藏状态中。这种方法能够更深入地影响模型的内部表示,可能有助于模型更好地理解和利用外部知识。同时,由于向量表示通常比原始文本更为紧凑,这种方法可以减少对模型输入长度的依赖。然而,这种方法需要对模型的结构进行复杂的设计和调整,无法应用于黑盒模型。

输出端增强

输出端增强的方法利用检索到的外部知识对大语言模型生成的文本进行校准,是一种后处理的方法。模型首先在无外部知识的情况下生成一个初步回答,然后再利用检索到的外部知识来验证或校准这一答案。REFEED 框架是此类方法典型代表。这种方法的优点是可以确保生成的文本与外部知识保持一致,提高答案的准确性和可靠性。

多次增强

对于复杂问题和模糊问题,我们难以通过一次检索增强就确保生成正确,多次迭代检索增强在所难免。处理复杂问题时,常采用分解式增强的方案。该方案将复杂问题分解为多个子问题,子问题间进行迭代检索增强。处理模糊问题时,常采用渐进式增强的方案。该方案将问题的不断细化,分别对细化的问题进行检索增强。

分解式增强

DEMONSTRATE–SEARCH–PREDICT(DSP)是一种具有代表性的分解式增强框架。该框架主要包含以下三个模块:

  • DEMONSTRATE 模块:通过上下文学习的方法,将复杂问题分解为子问题
  • SEARCH 模块:对子问题进行迭代检索增强,为最终决策提供综合的外部知识
  • PREDICT 模块:根据 SEARCH 提供的综合外部知识生成最终回答

渐进式增强

TREE OF CLARIFICATIONS(TOC)是渐进式增强的代表性框架。该框架通过递归式检索来引导大语言模型在树状结构中探索给定模糊问题的多种澄清路径。这种渐进式的检索方法能够显著改善大语言模型对模糊问题的生成效果,但需要进行多轮检索并生成多个答案路径,整个系统的计算量会随着问题复杂度呈指数级增长。此外,多轮的检索与生成不仅会带来显著的时间延迟,多个推理路径还为推理带来不稳定性,容易引发错误。

降本增效

去除冗余文本

对检索出的原始文本的词句进行过滤,从中选择出部分有益于增强生成的部分。去除冗余文本的方法主要分为三类:Token 级别的方法,子文本级别的方法以及全文本级别的方法。

Token 级别

Token 级别的方法通过对 Token 进行评估,对文本中不必要的 Token 进行剔除。困惑度是判断 Token 重要性的重要指标。直观上说,如果一个 Token 的困惑度低,这意味着模型有很高的概率预测到这个 Token,表明该 Token 易于预测且较为普遍,可能是冗余的;反之,如果一个 Token 的困惑度高,则表明这个 Token 携带了更多的信息量。

LongLLMLingua 框架利用小模型评估 Token 的困惑度,然后基于困惑度删除冗余文本。其首先进行问题感知的粗粒度压缩,即在给定问题条件下通过计算文档中所有 Token 困惑度的均值来评估文档的重要性,困惑度越高表示文档信息量越大。随后,执行问题感知的细粒度压缩,即进一步计算文档中每个 Token 的困惑度并去除其中低困惑度的 Token。此外,论文还引入了文档重排序机制动态压缩比率以及子序列恢复机制,确保重要文档和文档中的重要信息被有效利用。

子文本级别

子文本级别的方法通过对子文本进行打分,对不必要的子文本成片删除。FIT-RAG 是子文本级别方法中的代表性方法。该方法中采用了预先训练的双标签子文档打分器,从两个维度评估文档的有用性:一是事实性,即文档是否包含查询的答案信息;二是模型的偏好程度,即文档是否易于模型理解。对于检索到的文档,首先利用滑动窗口将其分割成多个子文档,然后使用双标签子文档打分器对这些子文档分别进行评分。最后,删除掉评分较低的子文档,从而有效地去除冗余文本。

全文本级别

全文本级别的方法直接从整个文档中抽取出重要信息,以去除掉冗余信息。经典方法 PRCA 通过训练能够提炼重点内容的信息提取器对文本中的重要信息进行提取。该方法分为两个阶段:上下文提取阶段与奖励驱动阶段。在上下文提取阶段,以最小化压缩文本与原输入文档之间的差异为目标,对信息提取器进行监督学习训练,学习如何将输入文档精炼为信息丰富的压缩文本。在奖励驱动阶段,大语言模型作为奖励模型,其根据压缩文本生成的答案与真实答案之间的相似度作为奖励信号,通过强化学习对信息提取器进行优化。最终得到的信息提取器可以直接将输入文档转化为压缩文本,端到端地去除冗余文本。

复用计算结果

除了对冗余信息进行筛除,我们还可以对计算必需的中间结果进行复用,以优化 RAG 效率。可以将常用的重复文本的 KV-cache 进行复用,避免每次查询都对其进行计算,以降低存储成本。基于此,RAGCache 设计了一种 RAG 系统专用的多级动态缓存机制,由三个核心部分组成:KV 张量缓存库缓存检索器RAG 控制器。其中,KV 张量缓存库采用树结构来缓存所计算出的文档 KV 张量,其中每个树节点代表一个文档;缓存检索器则负责在缓存库中快速查找是否存在所需的缓存节点;而 RAG 控制器作为系统的策略中枢,负责制定核心的缓存策略,其采用前缀感知的贪婪双重尺度频率(PGDSF)替换策略。该策略综合考虑了文档节点的访问频率、大小、访问成本以及最近访问时间,使得频繁使用的文档能够被快速检索。重排策略则通过调整请求的处理顺序,优先处理那些能够更多利用缓存数据的请求,以减少重新计算的需求。这样的请求在队列中享有较高的优先级,从而优化了资源使用。最后,系统还引入了动态推测流水线策略,通过并行 KV 张量检索和模型推理的步骤,有效减少了端到端延迟。

综上,通过结合上述输入 Prompt 压缩KV-cache 机制,RAG 框架可以在保持高性能的同时,显著提升其效率。