
2W8000字揭秘RAG:从基础到高级的逆袭,彻底重塑大模型! 精华
RAG增强技术分类
来源:https://arxiv.org/abs/2402.19473
最近一项关于检索增强生成(RAG)的调查总结了三种最新发展的范式:
- 基础RAG
- 高级RAG
- 模块化RAG
A representative instance of the RAG process applied to question answering. It mainly consists of 3 steps. 1) Indexing. Documents are split into chunks, encoded into vectors, and stored in a vector database. 2) Retrieval. Retrieve the Top k chunks most relevant to the question based on semantic similarity. 3) Generation. Input the original question and the retrieved chunks together into LLM to generate the final answer. 来源 https://arxiv.org/abs/2312.10997
RAG过程应用于问答的一个典型示例。它主要包括3个步骤:
- 索引构建:文档被分割成块,编码为向量,并存储在向量数据库中。
- 检索:根据语义相似性检索与问题最相关的前k个文本块。
- 生成:将原始问题和检索到的文本块一起输入到大语言模型中,生成最终答案。
1. Native RAG
标准的RAG过程包括将文本分割成块,使用Transformer编码器模型将这些片段嵌入为向量,为这些向量建立索引,然后为大语言模型构建一个提示。这个提示会指示模型根据用户的查询,在搜索阶段收集的上下文中生成响应。
在运行时,使用相同的编码器模型将用户的查询向量化,使用这个向量在索引中进行搜索,确定前k个结果,从数据库中检索相应的文本块,并将它们作为大语言模型提示的上下文输入。
以下是RAG如何让ChatGPT提升的一个示例。
RAG对ChatGPT的提升示例:解决训练数据范围之外的问题并生成正确结果。
来源:https://arxiv.org/abs/2404.10981
现在,让我们来看看基础RAG存在的问题。
1.1 基础RAG的问题
基础RAG存在问题(红色虚线框所示)。
如上图所示,基础RAG在上述所有三个步骤中都存在问题(红色虚线框),有很大的优化空间。
1.1.1 索引构建
- 信息提取不完整:它无法有效地处理非结构化文件(如PDF)中图像和表格里的有用信息。
- 分块策略单一:分块过程采用 “一刀切 ”的策略,没有根据不同文件类型的特点选择最优策略。这导致每个文本块包含的语义信息不完整,并且没有考虑到重要细节,如文本中已有的标题。
- 索引结构优化不足:导致检索功能效率低下。
- 嵌入模型语义表示能力弱。
1.1.2 检索
- 召回上下文相关性不足、准确性低。
- 召回率低:无法检索到所有相关段落,从而阻碍了大语言模型生成全面答案的能力。
- 检索不准确:查询可能不准确,或者嵌入模型的语义表示能力较弱,导致无法检索到有价值的信息。
- 检索算法有限:它没有结合不同类型的检索方法或算法,如将关键词检索、语义检索和向量检索相结合。
- 信息冗余:多个检索到的上下文包含相似信息时,会导致生成的答案中出现重复内容。
1.1.3 生成
- 整合失败:可能无法有效地将检索到的上下文与当前的生成任务相结合,导致输出不一致。
- 过度依赖风险:在生成过程中过度依赖增强信息会带来很高的风险,这可能导致输出只是简单地重复检索到的内容,而没有提供有价值的信息。
- 大语言模型生成错误:大语言模型可能会生成错误、不相关、有害或有偏见的回应。
请注意,这些问题的原因可能是多方面的。例如,如果给用户的最终回复包含不相关的内容,可能不只是大语言模型的问题。根本原因可能是从PDF中提取文档不准确,或者嵌入模型无法准确捕捉语义,等等。
2. 迈向高级RAG
基础RAG与高级RAG的区别
随着基础RAG的局限性日益明显,人们开始致力于开发更复杂的系统。高级RAG模型采用更复杂的检索技术,更好地整合检索到的信息,并且通常能够迭代地优化检索和生成过程。
高级RAG的关键特征:
- 先进的检索算法:例如语义搜索、上下文理解。
- 增强的检索数据整合:通常带有上下文和相关性加权。
- 迭代优化能力:能够提高准确性和相关性。
- 反馈循环和学习机制:用于持续改进。
高级RAG范式包含一系列旨在解决基础RAG已知局限性的技术。RAG的基本工作流程始于创建一个包含外部数据源的索引。这个索引是通过检索器模型根据特定查询检索相关信息的基础。最后一步是生成器模型,它将检索到的信息与查询相结合,产生所需的输出。
RAG范式组织了该领域的研究,为提高大语言模型的性能提供了一个简单而强大的框架。RAG的核心是其搜索机制,这对生成高质量的结果至关重要。因此,从检索的角度来看,这个范式可以分为四个主要阶段:检索前、检索、检索后和生成。
统一的RAG框架及其基本工作流程和范式。
来源:https://arxiv.org/abs/2404.10981
2.1 检索前优化
检索前优化主要集中在数据索引优化和查询优化上。数据索引优化技术旨在以有助于提高检索效率的方式存储数据,例如:
- 索引构建:这个过程从索引开始,建立一个有组织的系统,以便能够快速准确地检索信息。索引的具体方式取决于任务和数据类型。例如,句子级索引有助于问答系统精确地定位答案,而文档级索引则更适合用于总结文档,以理解其主要概念和思想。
- 查询处理:索引构建完成后,进行查询处理,调整用户查询,使其与索引数据更好地匹配。这包括查询重写,即重新编写查询,使其更符合用户的意图;查询扩展,即通过同义词或相关术语扩展查询,以获取更多相关结果;以及查询规范化,即解决拼写或术语上的差异,以实现一致的查询匹配。
- 数据修改:这对于提高检索效率也至关重要。这一步包括预处理技术,如去除不相关或冗余的信息,以提高结果的质量;以及用元数据等额外信息丰富数据,以提高检索内容的相关性和多样性。
句子窗口检索
2.2 检索优化
检索阶段的目标是识别最相关的上下文。通常,检索是基于向量搜索进行的,向量搜索计算查询和索引数据之间的语义相似性。因此,大多数检索优化技术都围绕着嵌入模型展开:
- 搜索与排序:检索阶段是搜索和排序的结合。它专注于从数据集中选择文档并对其进行优先级排序,以提高生成模型输出的质量。这个阶段使用搜索算法在索引数据中导航,找到与用户查询匹配的文档。在确定相关文档后,开始对这些文档进行初步排序,根据它们与查询的相关性进行排序。
- 微调嵌入模型:根据特定领域的上下文定制嵌入模型,特别是对于术语不断演变或包含罕见术语的领域。例如,BAAI/bge-small-en是一个可以微调的高性能嵌入模型。
- 动态嵌入:能够适应单词使用的上下文,与静态嵌入不同,静态嵌入为每个单词使用单个向量。例如,OpenAI的embeddings-ada-02是一个复杂的动态嵌入模型,能够捕捉上下文理解。
- 除了向量搜索,还有其他检索技术:例如混合搜索,它通常是指将向量搜索与基于关键词的搜索相结合的概念。如果我们的检索需要精确的关键词匹配,这种检索技术会很有帮助。
2.3 检索后优化
检索后阶段用于优化最初检索到的文档,以提高文本生成的质量。这个阶段包括重新排序和过滤,每个步骤都旨在为最终的生成任务优化文档选择。
- 提示压缩:通过去除不相关的内容并突出重要的上下文来缩短提示的总长度。
- 重新排序:在重新排序步骤中,对之前检索到的文档进行重新评估、评分和重新组织。目的是更准确地突出与查询最相关的文档,降低不太相关文档的重要性。这一步骤包括纳入额外的指标和外部知识来源,以提高精度。在这种情况下,由于候选文档数量有限,可以有效地使用准确性较高但效率较低的预训练模型。
- 过滤:旨在去除不符合指定质量或相关性标准的文档。这可以通过多种方法实现,例如设定一个最低相关性得分阈值,排除相关性低于特定水平的文档。此外,使用来自用户的反馈或先前的相关性评估有助于调整过滤过程,确保只有最相关的文档被保留用于文本生成。
重新排序
3. 高级RAG技术
高级RAG架构的一些关键组件。
示意图中的绿色元素是我们将进一步讨论的核心RAG技术,蓝色元素是文本。并非所有的高级RAG理念都能在一个示意图中轻松呈现,例如,各种扩展上下文的方法就被省略了——我们将在后续内容中深入探讨。
让我们来讨论这些技术。
4. 检索前技术
4.1 PDF解析
对于RAG来说,从文档中提取信息是不可避免的。确保从源文档中有效提取内容对于提高最终输出的质量至关重要。
不要低估这个过程。在实施RAG时,解析过程中信息提取不佳会导致对PDF文件中所含信息的理解和利用受限。
PDF解析过程在RAG中的位置如下图所示:
PDF解析过程(红色框)在RAG中的位置
在实际工作中,非结构化数据比结构化数据丰富得多。如果这些大量的数据无法被解析,它们的巨大价值就无法实现。
在非结构化数据中,PDF文档占了大部分。有效地处理PDF文档也可以极大地帮助管理其他类型的非结构化文档。
本文主要介绍解析PDF文件的方法,提供了有效解析PDF文档并尽可能多地提取有用信息的算法和建议。
4.1.1 解析PDF的挑战
PDF文档是典型的非结构化文档,然而,从PDF文档中提取信息是一个具有挑战性的过程。
与其说PDF是一种数据格式,不如更准确地将其描述为一组打印指令。一个PDF文件由一系列指令组成,这些指令告诉PDF阅读器或打印机在屏幕或纸张上的何处以及如何显示符号。这与HTML和docx等文件格式形成对比,后者使用诸如<p>
、<w:p>
、<table>
和<w:tbl>
等标签来组织不同的逻辑结构,如下图所示:
Html与PDF的对比
解析PDF文档的挑战在于准确提取整个页面的布局,并将内容(包括表格、标题、段落和图像)转换为文档的文本表示形式。这个过程涉及处理文本提取中的不准确之处、图像识别以及表格中行列关系的混淆。
4.1.2 如何解析PDF文档
一般来说,解析PDF有三种方法:
- 基于规则的方法:根据文档的组织特征确定每个部分的样式和内容。然而,这种方法的通用性不是很强,因为PDF的类型和布局繁多,无法用预定义的规则涵盖所有情况。
- 基于深度学习模型的方法:比如结合目标检测和OCR模型的流行解决方案。
- 基于多模态大模型解析复杂结构或提取PDF关键信息的方法。
4.1.3 基于规则的方法
最具代表性的工具之一是pypdf,它是一种广泛使用的基于规则的解析器,是LangChain和LlamaIndex中解析PDF文件的标准方法。
下面尝试使用pypdf解析《Attention Is All You Need》论文的第6页。原始页面如下图所示:
《Attention Is All You Need》论文的原始第6页
代码如下:
import PyPDF2
filename = "1706.03762.pdf"
pdf_file = open(filename, 'rb')
reader = PyPDF2.PdfReader(pdf_file)
page_num = 5
page = reader.pages[page_num]
text = page.extract_text()
print('--------------------------------------------------')
print(text)
pdf_file.close()
执行结果如下(为简洁起见,省略了其余部分):
(py) $ pip list | grep pypdf
pypdf 3.17.4
pypdfium2 4.26.0
(py) pypdf_test.py
Table 1: Maximum path lengths, per-layer complexity and minimum number of sequential operations
for different layer types. nis the sequence length, dis the representation dimension, kis the kernel
size of convolutions and rthe size of the neighborhood in restricted self-attention.
Layer Type Complexity per Layer Sequential Maximum Path Length
Operations
Self-Attention O(n2·d) O(1) O(1)
Recurrent O(n·d2) O(n) O(n)
Convolutional O(k·n·d2) O(1) O(logk(n))
Self-Attention (restricted) O(r·n·d) O(1) O(n/r)
3.5 Positional Encoding
Since our model contains no recurrence and no convolution, in order for the model to make use of the
order of the sequence, we must inject some information about the relative or absolute position of the
tokens in the sequence. To this end, we add "positional encodings" to the input embeddings at the
bottoms of the encoder and decoder stacks. The positional encodings have the same dimension dmodel
as the embeddings, so that the two can be summed. There are many choices of positional encodings,
learned and fixed [9].
In this work, we use sine and cosine functions of different frequencies:
PE(pos,2i)=sin(pos/100002i/d model)
PE(pos,2i+1)=cos(pos/100002i/d model)
where posis the position and iis the dimension. That is, each dimension of the positional encoding
corresponds to a sinusoid. The wavelengths form a geometric progression from 2πto10000·2π. We
chose this function because we hypothesized it would allow the model to easily learn to attend by
relative positions, since for any fixed offset k,PEpos+kcan be represented as a linear function of
PEpos.
...
...
...
根据PyPDF的检测结果可以发现,它将PDF中的字符序列序列化为一个长序列,没有保留结构信息。换句话说,它将文档的每一行都视为由换行符“\n”分隔的序列,这使得它无法准确识别段落或表格。
这个限制是基于规则的方法的固有特征。
4.1.4 基于深度学习模型的方法
这种方法的优点是能够准确识别整个文档的布局,包括表格和段落,甚至可以理解表格内部的结构。这意味着它可以将文档划分为定义明确、完整的信息单元,同时保留预期的含义和结构。
然而,它也有一些局限性。目标检测和OCR阶段可能很耗时,因此建议使用GPU或其他加速设备,并采用多进程和多线程进行处理。
这种方法涉及目标检测和OCR模型,我测试了几个有代表性的开源框架:
- Unstructured:它已集成到langchain中。启用infer_table_structure=True的hi_res策略的表格识别效果很好,但fast策略表现不佳,因为它不使用目标检测模型,会误识别许多图像和表格。
- Layout-parser:如果需要识别复杂结构的PDF,建议使用最大的模型以获得更高的准确性,尽管它可能会稍微慢一些。此外,Layout-parser的模型在过去两年似乎没有更新。
- PP-StructureV2:使用各种模型组合进行文档分析,性能高于平均水平。其架构如下图所示:
所提出的PP-StructureV2框架。它包含两个子系统:布局信息提取和关键信息提取。
4.2 上下文丰富
这里的理念是检索较小的文本块以提升搜索质量,但为大语言模型增添周围的上下文信息,以便其进行推理。
有两种选择:一种是通过检索到的较小文本块周围的句子来扩展上下文;另一种是将文档递归地分割成多个较大的父文本块,每个父文本块包含较小的子文本块。
4.2.1 句子窗口检索
在这种方案中,文档中的每个句子都被单独嵌入,这使得查询与上下文的余弦距离搜索具有很高的准确性。
在获取到最相关的单个句子后,为了更好地对找到的上下文进行推理,我们在检索到的句子前后扩展k个句子的上下文窗口,然后将这个扩展后的上下文发送给大语言模型。
绿色部分是在索引中搜索时找到的句子嵌入,整个黑色加绿色的段落被输入到大语言模型中,以在对提供的查询进行推理时扩大其上下文。
4.2.2 自动合并检索器(又名父文档检索器)
这个思路与句子窗口检索器非常相似——搜索更细粒度的信息,然后在将上下文输入到大语言模型进行推理之前扩展上下文窗口。文档被分割成较小的子文本块,这些子文本块引用较大的父文本块。
文档被分割成一个文本块层次结构,然后将最小的叶文本块发送到索引中。在检索时,我们检索k个叶文本块,如果有n个文本块引用同一个父文本块,我们就用这个父文本块替换它们,并将其发送给大语言模型以生成答案。
在检索时先获取较小的文本块,然后,如果在前k个检索到的文本块中有超过n个文本块链接到同一个父节点(较大的文本块),我们就用这个父节点替换输入到大语言模型的上下文——这就像是自动将几个检索到的文本块合并成一个较大的父文本块,因此得名。需要注意的是——搜索仅在子节点索引内进行。
4.3 查询改写
在检索增强生成(RAG)中,我们经常会遇到用户原始查询的问题,比如措辞不准确或缺乏语义信息。例如,像 “2020年NBA冠军是洛杉矶湖人队!告诉我什么是Langchain框架?” 这样的查询,如果直接进行搜索,大语言模型可能会给出错误或无法回答的响应。
因此,使用户查询的语义空间与文档的语义空间保持一致至关重要。查询改写技术可以有效地解决这个问题。它在RAG中的作用如下图所示:
查询改写
从位置角度来看,查询改写是一种检索前的方法。请注意,此图大致展示了查询改写在RAG中的位置。在接下来的部分中,我们将看到一些算法可能会改进这个过程。
查询改写是使查询和文档语义对齐的关键技术。例如:
- 假设文档嵌入(HyDE):通过假设文档使查询和文档的语义空间对齐。
- 改写-检索-读取:提出了一种与传统检索和读取顺序不同的框架,侧重于查询改写。
- 回溯提示法(Step-Back Prompting):允许大语言模型基于高级概念进行抽象推理和检索。
- Query2Doc:使用大语言模型的一些提示生成伪文档,然后将它们与原始查询合并以构建新的查询。
- ITER-RETGEN:提出了一种将前一次生成的结果与前一个查询相结合的方法。然后检索相关文档并生成新的结果。这个过程会重复多次以获得最终结果。
让我们深入了解这些方法的细节。
4.3.1 假设文档嵌入(HyDE)
论文《Precise Zero-Shot Dense Retrieval without Relevance Labels》提出了一种基于假设文档嵌入(HyDE)的方法,主要过程如下图所示:
HyDE模型
文档片段已展示。HyDE可用于所有类型的查询,且无需更改底层的GPT-3和Contriever/mContriever模型。来源:《Precise Zero-Shot Dense Retrieval without Relevance Labels》。
总之,虽然HyDE引入了一种新的查询改写方法,但它确实存在一些局限性。它不依赖于查询嵌入的相似性,而是强调一个文档与另一个文档的相似性。然而,如果语言模型对该主题不够熟悉,它可能并不总能产生最佳结果,有可能导致错误增加。
4.3.2 改写-检索-读取
这个想法来自论文《Query Rewriting for Retrieval-Augmented Large Language Models》。它认为,原始查询,特别是在现实场景中,可能并不总是最适合大语言模型进行检索的。
因此,该论文建议我们首先使用大语言模型改写查询。然后再进行检索和答案生成,而不是直接从原始查询中检索内容并生成答案,如图4(b)所示:
从左到右,(a)标准的检索-读取方法,(b)将大语言模型用作查询改写器的改写-检索-读取流程,(c)带有可训练改写器的流程
图4:从左到右,(a)标准的检索-读取方法,(b)将大语言模型用作查询改写器的改写-检索-读取流程,(c)带有可训练改写器的流程。来源:《Query Rewriting for Retrieval-Augmented Large Language Models》。
为了说明查询改写如何影响上下文检索和预测性能,考虑这个例子:“2020年NBA冠军是洛杉矶湖人队!告诉我什么是Langchain框架?” 这个查询通过改写得到了准确处理。
4.3.3 回溯提示法(Step-Back Prompting)
回溯提示法(STEP-BACK PROMPTING)是一种简单的提示技术,它使大语言模型能够进行抽象,从包含特定细节的实例中提取高级概念和基本原理。其思路是将 “回溯问题” 定义为从原始问题派生出来的更抽象的问题。
例如,如果一个查询包含大量细节,大语言模型很难检索到相关事实来解决任务。如下图第一个例子所示,对于物理问题 “如果理想气体的温度升高2倍,体积增大8倍,压力P会发生什么变化?” 大语言模型在直接推理这个问题时,可能会偏离理想气体定律的第一原理。
回溯提示法的示例
回溯提示法的示例,包含由概念和原理引导的抽象和推理两个步骤。顶部:MMLU高中物理的一个例子,通过抽象检索到理想气体定律的第一原理。底部:TimeQA的一个例子,教育历史的高级概念是抽象的结果。左边:PaLM-2L无法回答原始问题。思维链提示法在中间推理步骤中遇到错误(红色突出显示)。右边:PaLM-2L通过回溯提示法成功回答了问题。来源:《TAKE A STEP BACK: EVOKING REASONING VIA ABSTRACTION IN LARGE LANGUAGE MODELS》。
从这种抽象中得出的推理有助于防止在图5(左)中所示的中间步骤(思维链)中出现错误。
总之,回溯提示法涉及两个基本步骤:
- 抽象:最初,我们促使大语言模型提出一个关于高级概念或原理的宽泛问题,而不是直接回答查询。然后我们检索关于该概念或原理的相关事实。
- 推理:大语言模型可以根据这些关于高级概念或原理的事实推导出原始问题的答案。我们将此称为抽象推理。
4.3.4 Query2doc
论文《Query2doc: Query Expansion with Large Language Models》介绍了Query2doc。它使用大语言模型的一些提示生成伪文档,然后将它们与原始查询相结合,创建一个新的查询,如下图所示:
Query2doc少样本提示法
在密集检索中,新的查询q+是原始查询q和伪文档d’ 的简单连接,用[SEP]分隔:q+ = concat(q, [SEP], d’)。
Query2doc认为,HyDE隐含地假设了真实文档和伪文档用不同的词表达相同的语义,但这对于某些查询可能并不成立。
Query2doc和HyDE的另一个区别是,Query2doc训练了一个有监督的密集检索器,如论文中所述。
目前,在Langchain或LlamaIndex中尚未发现Query2doc的复现。
4.3.5 ITER-RETGEN
ITER-RETGEN方法使用生成的内容来指导检索。它在 “检索-读取-检索-读取” 流程中迭代地实现 “检索增强生成” 和 “生成增强检索”。
ITER-RETGEN迭代检索和生成
ITER-RETGEN迭代检索和生成。在每次迭代中,ITER-RETGEN利用前一次迭代的模型输出作为特定上下文,帮助检索更相关的知识,这可能有助于改进模型生成(例如,在图中纠正赫西·霍根的身高)。为简洁起见,我们在图中仅展示两次迭代。实线箭头将查询与检索到的知识连接起来,虚线箭头表示检索增强生成。来源:《Enhancing Retrieval-Augmented Large Language Models with Iterative Retrieval-Generation Synergy》。
如上图所示,对于给定的问题q和检索语料库D = {d}(其中d代表一个段落),ITER-RETGEN连续执行T次检索生成迭代。
在每次迭代t中,我们首先使用前一次迭代的生成结果yt-1,将其与q相结合,并检索前k个段落。接下来,我们促使大语言模型M生成一个输出yt,该输出将检索到的段落(表示为Dyt-1||q)和q纳入提示中。因此,每次迭代可以表述如下:
最后一个输出yt将作为最终响应产生。
与Query2doc类似,目前在Langchain或LlamaIndex中尚未发现其复现。
4.4 语义分块
解析文档后,我们可以获得结构化或半结构化数据。现在的主要任务是将它们分解为较小的块,以提取详细特征,然后嵌入这些特征来表示它们的语义。它在RAG中的位置如下图所示:
最常用的分块方法是基于规则的,采用固定块大小或相邻块重叠等技术。对于多层次文档,我们可以使用Langchain提供的RecursiveCharacterTextSplitter,它允许定义多层次分隔符。
然而,在实际应用中,由于预定义规则(块大小或重叠部分的大小)较为僵化,基于规则的分块方法很容易导致诸如检索上下文不完整或块大小过大包含噪声等问题。
因此,对于分块来说,最理想的方法显然是基于语义进行分块。语义分块旨在确保每个块包含尽可能多的语义独立信息。
本文将探索语义分块的方法,解释其原理和应用。我们将介绍三种类型的方法:
- 基于嵌入的方法
- 基于模型的方法
- 基于大语言模型的方法
4.4.1 基于嵌入的方法
LlamaIndex和Langchain都提供了基于嵌入的语义分块器。其算法思路大致相同。
4.4.2 基于模型的方法
4.4.2.1 朴素BERT
回想一下BERT的预训练过程。设计了一个二元分类任务——下一句预测(NSP),来教会模型两个句子之间的关系。在这里,两个句子同时输入到BERT中,模型预测第二个句子是否跟随第一个句子。
我们可以应用这个原理来设计一种简单的分块方法。对于一个文档,将其拆分为句子。然后,使用滑动窗口将两个相邻句子输入到BERT模型中进行NSP判断,如图3所示:
如果预测分数低于预设阈值,则表明两个句子之间的语义关系较弱。这可以作为一个文本分割点,如图中句子2和句子3之间所示。
这种方法的优点是可以直接使用,无需训练或微调。
然而,这种方法在确定文本分割点时只考虑了前后句子,忽略了更远片段的信息。此外,这种方法的预测效率相对较低。
4.4.2.2 跨段注意力(Cross Segment Attention)
论文《Text Segmentation by Cross Segment Attention》提出了三种关于跨段注意力的模型,如图4所示:
跨段注意力模型
在跨段BERT模型(左)中,我们将潜在分割点周围的局部上下文(左边k个标记和右边k个标记)输入到模型中。在BERT+双向长短期记忆网络(Bi-LSTM)模型(中)中,我们首先使用BERT模型对每个句子进行编码,然后将句子表示输入到Bi-LSTM中。在分层BERT模型(右)中,我们首先使用BERT对每个句子进行编码,然后将输出的句子表示输入到另一个基于Transformer的模型中。来源:《Text Segmentation by Cross Segment Attention》。
上图(a)展示了跨段BERT模型,它将文本分割定义为一个逐句分类任务。潜在分割点的上下文(两侧的k个标记)被输入到模型中。对应于[CLS]的隐藏状态被传递到softmax分类器,以对潜在分割点的分割进行决策。
该论文还提出了另外两个模型。一个使用BERT模型获取每个句子的向量表示。然后将多个连续句子的这些向量表示输入到Bi-LSTM(图(b))或另一个BERT(图(c))中,以预测每个句子是否是文本分割边界。
当时,这三个模型取得了最先进的结果,如下图所示:
文本分割和语篇分割的测试集结果
图5:文本分割和语篇分割的测试集结果。来源:《Text Segmentation by Cross Segment Attention》。
4.4.2.3 SeqModel
跨段模型独立地对每个句子进行向量化,没有考虑任何更广泛的上下文信息。论文《Sequence Model with Self-Adaptive Sliding Window for Efficient Spoken Document Segmentation》中提出的SeqModel对其进行了进一步改进。
SeqModel使用BERT同时对几个句子进行编码,在计算句子向量之前对更长的上下文内的依赖关系进行建模。然后它预测每个句子之后是否发生文本分割。此外,该模型利用自适应滑动窗口方法在不牺牲准确性的情况下提高推理速度。SeqModel的示意图如下所示:
SeqModel架构和自适应滑动窗口推理方法 来源:《Sequence Model with Self-Adaptive Sliding Window for Efficient Spoken Document Segmentation》
4.4.3 基于大语言模型的方法
论文《Dense X Retrieval: What Retrieval Granularity Should We Use?》引入了一种新的检索单元——命题。命题被定义为文本中的原子表达式,每个命题封装一个独特的事实,并以简洁、自包含的自然语言格式呈现。
那么我们如何获得这个所谓的命题呢?在论文中,它是通过构建提示并与大语言模型交互来实现的。
LlamaIndex和Langchain都实现了相关算法,下面以LlamaIndex为例进行演示。
一般来说,这种使用大语言模型构建命题的分块方法实现了更精细的分块。它与原始节点形成了从小(命题)到大(原始文本块)的索引结构,从而为语义分块提供了一种新思路。
然而,这类方法依赖大语言模型,成本相对较高。
如果条件允许,可以持续采用并关注基于大语言模型的方法。
4.5 数据修改
检索增强双指令调优(Retrieval Augmented Dual Instruction Tuning,RA-DIT)和背诵增强生成(RECITation-augmented gEneration,RECITE)强调通过内部数据修改进行增强。
RA-DIT区分了用于大语言模型的微调数据集和检索器的数据集,旨在增强大语言模型的上下文理解能力,以及检索器与查询的匹配能力。
另一方面,RECITE利用段落提示和合成的问题 - 段落对,来增加生成的背诵内容和回复的多样性及相关性。这种方法试图拓宽模型的知识库并提高其回复的准确性。
用于改进零样本评估的通用提示检索(Universal Prompt Retrieval for Improving Zero-Shot Evaluation,UPRISE)和“生成而非检索”(Generate rather than Retrieve,GENREAD)则致力于优化外部数据。
UPRISE将原始任务数据转换为结构化格式,并优化提示选择,以提高检索结果。
相比之下,GENREAD采用的基于聚类的提示方法,会根据问题生成文档并进行聚类,以消除不相关数据,同时用多样化的上下文信息丰富输入内容。这项技术旨在通过为生成模型提供更丰富的信息,来提升其性能。
此外,KnowledGPT致力于通过实体链接,用结构化、语义丰富的信息扩充原始文本数据。这种扩充过程不仅使数据结构更紧密、更易于查询,还提高了模型的检索效率。它利用精确的链接知识,增强模型的理解能力和生成相关回复的能力,从而提升其整体性能。
4.6 查询路由
查询路由是指大语言模型根据用户查询做出决策,决定下一步操作的过程。这些操作通常包括总结信息、根据某些数据索引进行搜索,或者尝试多种不同路径,然后将它们的输出合成为一个答案。
查询路由器还用于选择索引,或者更广泛地说,选择数据存储位置,以确定将用户查询发送到何处。比如,我们可能有多种数据来源,例如经典的向量存储、图数据库或关系数据库;又或者我们有索引层级结构,对于多文档存储,一个典型的例子是拥有一个摘要索引和另一个文档块向量索引。
定义查询路由器包括设置它可以做出的选择。
路由选项的选择是通过调用大语言模型来完成的,模型以预定义的格式返回结果,这些结果用于将查询路由到指定的索引。如果涉及复杂的行为,查询会被路由到子链,甚至如下面多文档代理方案所示,被路由到其他智能体。
LlamaIndex和LangChain都支持查询路由功能。
5. 检索技术
5.1 融合检索/混合搜索
这是一个相对成熟的思路,即结合基于关键词的传统搜索(如像tf-idf这样的稀疏检索算法,或者搜索行业标准的BM25算法)和现代语义搜索或向量搜索的优势,并将其融合在一个检索结果中。
这里唯一的技巧是如何恰当地结合具有不同相似度分数的检索结果。这个问题通常借助逆序排名融合(Reciprocal Rank Fusion)算法来解决,该算法会对检索结果重新排序,以生成最终输出。
在LangChain中,这一功能在Ensemble Retriever类中实现。通过组合我们定义的一系列检索器(例如,一个faiss向量索引和一个基于BM25的检索器),并使用RRF算法进行重新排序。
LlamaIndex中实现的方式也非常相似。
混合搜索通常能提供更好的检索结果,因为它结合了两种互补的搜索算法,同时考虑了查询与存储文档之间的语义相似性和关键词匹配情况。
6. 检索后技术
6.1 提示压缩
RAG过程可能会遇到两个问题:
- 大语言模型通常存在上下文长度限制。因此,输入文本越长,处理过程就越耗时且成本越高。
- 检索到的上下文可能并不总是有用的。有可能一个较大文本块中只有一小部分与答案相关。在某些情况下,可能需要组合多个文本块才能回答特定问题。即使经过重新排序,这个问题仍然存在。
针对大语言模型的提示压缩是解决这些问题的一种方法。本质上,其目标是保留提示中的关键信息,使输入的令牌更有价值。这种方法可以提高模型的性能并降低成本,如下图右下角所示。
值得注意的是,如上图中紫色虚线所示,一些压缩器也可以直接应用于检索到的上下文。
总体而言,提示压缩方法主要可分为四类:
- 基于信息熵的方法,如Selective Context、LLMLingua、LongLLMLingua。这些方法使用一个小型语言模型来计算原始提示中每个令牌的自信息或困惑度,然后删除困惑度较低的令牌。
- 基于软提示调整的方法,如AutoCompressor和GIST。这些方法需要对大语言模型的参数进行微调,以使其适用于特定领域,但不能直接应用于黑盒大语言模型。
- 先从大语言模型进行数据蒸馏,然后训练模型生成更具解释性的文本摘要。这些摘要可以在不同语言模型之间转移使用,并应用于不需要梯度更新的黑盒大语言模型。代表性方法有LLMLingua - 2和RECOMP。
- 基于令牌合并或令牌修剪的方法,如ToMe和AdapLeR。这些方法通常需要在推理过程中对模型进行微调或生成中间结果。
鉴于第四类方法最初是为像ViT或BERT这样的较小模型提出的,本文将介绍前三类方法中代表性算法的原理。
6.1.1 选择性上下文(Selective Context)
下图展示了大语言模型在无需完整上下文或完整对话历史的情况下,也能响应用户查询。即使省略了相关信息,大语言模型仍然可以生成预期的回复。这可能归因于大语言模型能够从上下文线索以及预训练期间获得的先验知识中推断出缺失信息。
因此,通过过滤掉信息含量较低的内容来优化上下文长度,同时又不影响性能是可行的。这就是选择性上下文的核心思路。
选择性上下文使用一个小型语言模型(SLM)来确定给定上下文中词汇单元(如句子、短语或令牌)的自信息,然后利用这些自信息来评估它们的信息价值。通过有选择地保留自信息较高的内容,选择性上下文为大语言模型提供了更简洁高效的上下文表示,同时不会影响其在不同任务上的性能。
6.1.2 LLMLingua
LLMLingua指出,选择性上下文常常忽略了压缩内容之间的相互联系,以及大语言模型与用于提示压缩的小型语言模型之间的相关性。LLMLingua正是针对这些问题而设计的。
具体来说,如下图所示,LLMLingua使用一个预算控制器,为原始提示的各个组成部分(如指令、示例和问题)动态分配不同的压缩率。它还进行粗粒度的示例级压缩,以在高压缩率下仍能保持语义完整性。此外,LLMLingua引入了一种令牌级迭代算法,用于细粒度的提示压缩。
与选择性上下文相比,LLMLingua可以更有效地保留提示中的关键信息,同时考虑令牌之间的条件依赖关系。它可以将提示压缩20倍。
6.1.3 指令调整(Instruction Tuning)
(LLMLingua方法的框架图)展示了指令调整也是LLMLingua中的关键步骤。其目的是最小化用于压缩提示的小型语言模型与大语言模型之间的分布差异。
6.1.4 LongLLMLingua
LLMLingua的问题在于,它在压缩过程中没有考虑用户问题,这可能会保留不相关的信息。
LongLLMLingua旨在通过将用户问题纳入压缩过程来解决这个问题。
如上图所示,LongLLMLingua提出了四个新组件,以增强大语言模型对关键信息的感知:
- 问题感知的粗粒度和细粒度压缩
- 文档重新排序机制
- 动态压缩率
- 子序列恢复算法
6.1.5 AutoCompressor
与前面提到的方法不同,AutoCompressor是一种基于软提示的方法。
它通过扩展词汇表,并利用“摘要令牌”和“摘要向量”巧妙地对现有模型进行微调,以压缩上下文信息。
AutoCompressor通过递归生成摘要向量来处理长文档,这些摘要向量作为软提示传递给后续的所有文本段。
上图展示了AutoCompressor的架构,其操作步骤如下:
- 扩展词汇表:这一步骤包括向模型的现有词汇表中添加“摘要令牌”。这些令牌使模型能够将大量信息压缩成较小的向量。
- 分割文档:待处理的文档被分割成小的文本段,每个文本段都附加有摘要令牌。这些令牌还携带前序文本段的摘要信息,形成摘要积累。
- 微调训练:使用无监督训练方法,利用“下一个单词预测”任务对模型进行微调。该任务的目标是根据当前令牌之前的令牌和当前文本段之前的摘要向量,预测下一个单词。
- 反向传播:AutoCompressor对每个文本段使用时间反向传播(BPTT)和梯度检查点技术,以最小化计算图的大小。对整个文档进行反向传播,使模型能够学习完整上下文的关联。
6.1.6 LLMLingua-2
LLMLingua - 2指出,基于像LLaMa - 7B这样的因果语言模型的信息熵来删除令牌或词汇单元进行提示压缩,存在两个问题:
- 用于确定信息熵的小型语言模型与提示压缩的目标不一致。
- 它仅利用单向上下文,这可能无法涵盖提示压缩所需的所有信息。
这些问题的核心在于,信息熵可能并非压缩的最佳度量方式。
LLMLingua - 2的总体架构如下图所示:
为了解决问题1,LLMLingua - 2引入了数据蒸馏过程。这个过程从大语言模型中提取知识,以在不丢失关键信息的情况下压缩提示。同时,它构建了一个提取式文本压缩数据集。在这个数据集上进行训练有助于使小型语言模型有效地与提示压缩目标对齐。
为了解决问题2,LLMLingua - 2将提示压缩视为一个令牌分类问题。这种方法确保了压缩后的提示与原始提示的保真度。它使用Transformer编码器作为基础架构,从完整的双向上下文中捕获提示压缩所需的所有信息。
6.1.7 RECOMP(检索、压缩、前置,Retrieve, COMpress, Prepend)
RECOMP引入了两种经过训练的压缩器:提取式压缩器和抽象式压缩器。提取式压缩器从检索到的文档中选择有用的句子,而抽象式压缩器则结合多个文档的信息来生成摘要。
在本文讨论的方法中,LongLLMLingua可能是一个更优的选择,我们已经在研究项目中实现了它。此外,LLMLingua - 2也可以尝试,它在速度和内存使用方面具有优势。
6.2 重新排序
重新排序在检索增强生成(RAG)过程中起着至关重要的作用。在基础的RAG方法中,可能会检索到大量的上下文,但并非所有这些上下文都与问题相关。重新排序可以对文档进行重新排序和筛选,将相关的文档置于前列,从而提高RAG的有效性。
6.2.1 重新排序介绍
在RAG的重新排序中,任务是评估这些上下文的相关性,并将最有可能提供准确和相关答案的上下文(红色框标记的部分)排在前面。
如下图所示,重新排序的任务就像一个智能过滤器。当检索器从索引集合中检索出多个上下文时,这些上下文与用户查询的相关性可能各不相同。有些上下文可能非常相关(用红色框突出显示),而其他上下文可能只是略微相关,甚至不相关(分别用绿色和蓝色框突出显示)。
重新排序的任务是评估这些上下文的相关性,并优先考虑那些最有可能提供准确和相关答案的上下文。这使得大语言模型在生成答案时,能够优先处理排名靠前的上下文,从而提高回复的准确性和质量。
简单来说,重新排序就像是在开卷考试中,帮助我们从一堆学习资料中选择最相关的参考内容,以便更高效、准确地回答问题。
本文描述的重新排序方法主要可分为以下两类:
- 重新排序模型:这些模型考虑文档与查询之间的交互特征,以更准确地评估它们的相关性。
- 大语言模型:大语言模型的出现为重新排序开辟了新的可能性。通过深入理解整个文档和查询,大语言模型能够更全面地捕捉语义信息。
6.2.2 使用重新排序模型作为重新排序器
与嵌入模型不同,重新排序模型将查询和上下文作为输入,直接输出相似度分数,而不是嵌入向量。需要注意的是,重新排序模型是使用交叉熵损失进行优化的,这使得相关性分数不受特定范围的限制,甚至可以是负数。
目前,可用的重新排序模型并不多。一种选择是Cohere提供的在线模型,可以通过API访问。也有一些开源模型,如bge-reranker-base和bge-reranker-large等。
使用命中率(Hit Rate)和平均倒数排名(Mean Reciprocal Rank,MRR)指标进行评估的结果如下图所示:
从这个评估结果中,我们可以看出:
- 无论使用哪种嵌入模型,重新排序都显示出更高的命中率和MRR,这表明重新排序的显著作用。
- 目前,最好的重新排序模型是Cohere的模型,但它是付费服务。开源的bge-reranker-large模型与Cohere的模型能力相似。
- 嵌入模型和重新排序模型的组合也会产生影响,因此开发人员在实际过程中可能需要尝试不同的组合。
6.2.3 使用大语言模型作为重新排序器
现有的涉及大语言模型的重新排序方法大致可分为三类:使用重新排序任务微调大语言模型、使用提示让大语言模型进行重新排序,以及在训练过程中使用大语言模型进行数据增强。
使用提示让大语言模型进行重新排序的方法成本较低。下面以已集成到LlamaIndex中的RankGPT为例进行演示。
RankGPT的思路是使用大语言模型(如ChatGPT或GPT-4等其他大语言模型)进行零样本列表式段落重新排序。它应用排列生成方法和滑动窗口策略,高效地对段落进行重新排序。
如下面的图所示,论文提出了三种可行的方法。
前两种方法是常规方法,即给每个文档打分,然后根据这个分数对所有段落进行排序。
第三种方法,即排列生成,是本文提出的。具体来说,该模型不依赖外部分数,而是直接对所有候选段落进行端到端的排序。换句话说,它直接利用大语言模型的语义理解能力,对所有候选段落进行相关性排名。
然而,通常候选文档的数量非常大,而大语言模型的输入是有限的。因此,通常无法一次性输入所有文本。
因此,如上图所示,引入了滑动窗口方法,该方法遵循冒泡排序的思路。每次仅对前4个文本进行排序,然后移动窗口,对后续4个文本进行排序。遍历整个文本后,我们可以得到性能最佳的前几个文本。
6.3 过滤
知识链(Chain-of-Knowledge,COK)提出了渐进式推理修正技术,旨在利用检索到的知识迭代优化推理依据。这个方法构成了一个持续优化的过程,显著提高了内容生成中所用信息的相关性和质量。
Self-RAG引入了自我反思机制,以有效地过滤掉不相关的内容。通过使用批判令牌,这种方法评估检索到的段落的相关性、支持度和实用性,确保只有高质量的信息被整合到内容生成过程中。
此外,带令牌过滤的解码器融合(Fusion-in-Decoder with Token Filtering,FiD-TF)(上图)和RECOMP致力于从检索到的文档中去除不相关或冗余的令牌和信息。FiD-TF采用动态机制来识别和消除不必要的令牌,提高信息处理效率。而RECOMP则将文档压缩成简洁的摘要,专注于为生成过程选择最相关的内容。这些方法通过确保仅使用相关和有用的信息,简化了内容生成工作流程,从而提高了生成内容的整体质量和相关性。
6.4 Self-RAG
让我们考虑一个常见的场景:参加开卷考试。我们通常有两种策略:
- 方法1:对于熟悉的题目,快速作答;对于不熟悉的题目,打开参考书查找,快速找到相关部分,在脑海中整理和总结,然后在试卷上作答。
- 方法2:对于每一道题目,都查阅书籍。找到相关章节,在脑海中整理和总结,然后在试卷上写下答案。
显然,方法1是更优的选择。方法2可能会耗费时间,还可能引入不相关或错误的信息,这可能会导致困惑和错误,即使是在我们原本熟悉的领域。
然而,方法2是经典RAG过程的体现,而方法1代表了Self-RAG过程,本文将进一步探讨Self-RAG。
下图展示了RAG和Self-RAG主要过程的对比:
Self-RAG由三个步骤组成:
- 按需检索:当模型需要检索时,例如查询 “美国各州的名字是怎么来的?”(上图右上角),模型的输出将包含一个 [Retrieve] 令牌。这表明需要检索与该查询相关的内容。相反,当被要求写 “写一篇关于你最棒的暑假的文章”(上图右下角)时,模型会选择直接生成答案,而无需检索。
- 并行生成:模型使用提示和检索到的内容来生成输出。在这个过程中,有三种反思令牌会表明检索到的内容的相关性。
- 评估与选择:对步骤2中生成的内容进行评估,并选择最佳的部分作为输出。
6.5 校正检索增强生成(Corrective RAG)
让我们考虑一个常见的场景:参加开卷考试。通常,我们有三种策略:
- 方法1:对于熟悉的题目快速作答。对于不熟悉的题目,查阅参考书。快速定位相关部分,在脑海中组织和总结,然后在试卷上写下答案。
- 方法2:对于每一个题目,都查阅书籍。找到相关部分,在脑海中总结,然后在试卷上写下答案。
- 方法3:对于每一个题目,查阅书籍并确定相关部分。在形成答案之前,将收集到的信息分为三类:正确、错误和模糊。分别处理每一类信息。然后,基于这些处理后的信息,在脑海中编辑和总结。最后在试卷上写下答案。
方法1涉及Self-RAG,而方法2是经典的RAG过程。
最后,本文将介绍方法3,即校正检索增强生成(Corrective Retrieval Augmented Generation,CRAG)。
6.5.1 CRAG的动机
这些例子表明,低质量的检索器容易引入大量不相关的信息,这会阻碍生成器获取准确的知识,并可能误导它们。
上图说明,大多数传统的RAG方法没有考虑文档与问题的相关性,只是简单地合并检索到的文档。这可能会引入不相关的信息,从而阻碍模型获取准确的知识,并可能误导它,导致产生幻觉的问题。
此外,大多数传统的RAG方法将整个检索到的文档作为输入。然而,这些检索到的文档中很大一部分文本通常对生成来说并非必要,不应该同等地参与到RAG中。
6.5.2 CRAG的关键思想
CRAG设计了一个轻量级的检索评估器,用于评估针对特定查询检索到的文档的整体质量。它还使用网络搜索作为补充工具来改进检索结果。
CRAG是即插即用的,可以与各种基于RAG的方法无缝集成。其整体架构如下图所示:
CRAG在RAG中的位置
如图所示,CRAG通过引入一个检索评估器来评估检索到的文档与查询之间的关系,从而增强了传统的RAG。
可能有3种判断结果:
- 如果判断为“正确”,这意味着检索到的文档包含查询所需的必要内容,那么使用知识精炼算法来重写检索到的文档。
- 如果检索到的文档“错误”,这意味着查询和检索到的文档不相关。因此,我们不能将该文档发送给大语言模型。在CRAG中,会使用网络搜索引擎来检索外部知识。
- 对于“模糊”的情况,这意味着检索到的文档可能接近但不足以提供答案。在这种情况下,需要通过网络搜索获取更多信息。所以会同时使用知识精炼算法和搜索引擎。
最后,经过处理的信息会被转发给大语言模型以生成回复。下图正式描述了这个过程:
注意,网络搜索不会直接使用用户输入的查询进行搜索。相反,它会构建一个提示,并以少样本的方式呈现给GPT-3.5 Turbo,以获得用于搜索的查询。
6.5.3 检索评估器的改进
检索评估器可以看作是一个评分分类模型。这个模型用于确定查询和文档之间的相关性,类似于RAG中的重排序模型。
通过整合更多符合现实场景的特征,可以改进这种相关性判断模型。例如,科学论文问答RAG包含许多专业术语,而旅游领域的RAG往往有更口语化的用户查询。
通过在检索评估器的训练数据中添加场景特征,它可以更好地评估检索到的文档的相关性。其他特征,如用户意图和编辑距离,也可以被纳入,如下图所示:
此外,考虑到T5-Large获得的结果,轻量级模型似乎也能够取得不错的效果。这为CRAG在小型团队或公司中的应用带来了希望。
6.5.4 检索评估器的分数和阈值
如前所述,不同类型的数据阈值不同。此外,我们可以发现,模糊和错误的阈值基本在 -0.9左右,这表明大多数检索到的知识与查询相关。完全丢弃这些检索到的知识并仅仅依赖网络搜索可能并不可取。
6.6 RAG融合
RAG融合首先使用大语言模型生成多个衍生查询。这一步拓宽了对初始用户输入的理解,确保从各个角度全面探索查询主题。接下来,向量搜索为原始查询和衍生查询识别相关文档,汇编各种相关信息。
在文档检索之后,逆序排名融合(RRF)算法根据相关性对文档进行重新排序。然后将这些文档组合起来,形成一个全面且相关的信息源。
在最后阶段,这个组合数据集和所有查询由一个大语言模型进行处理。该模型综合这些输入,生成一个表达清晰且与上下文相关的回复。通过这种系统的方法,RAG融合提高了回复的准确性和全面性,显著提升了对用户查询的回答质量。
7. 生成技术
7.1 增强
“演示-搜索-预测”(Demonstrate-Search-Predict,DSP)引入了一个框架,旨在生成多个检索查询,以总结和回答问题,该框架利用从不同段落聚合的信息。这个框架采用“多重搜索组合”(CombSUM)来计算不同检索列表中段落的累积概率得分,便于从多个来源汇编全面的回复。
“可插拔奖励驱动上下文适配器”(Pluggable Reward-Driven Contextual Adapter,PRCA)概述了一个奖励驱动阶段,在这个阶段,根据生成器的反馈来优化提炼后的上下文。利用强化学习,这个阶段根据提供相关上下文所获得的奖励来调整PRCA的参数。目的是微调提取的上下文,以满足生成器的特定要求,从而优化生成过程。
“检索并插入”(REtrieve and PLUG,REPLUG)提出了一种在黑盒大语言模型进行最终预测之前,将检索到的文档添加到输入上下文前面的方法。它引入了一种集成策略来并行编码检索到的文档,克服了大语言模型上下文长度的限制,并通过分配更多计算资源来提高准确性。这种方法通过确保大语言模型能够访问更广泛的相关信息来改进生成过程。
RECITE实现了一种自一致性技术,该技术涉及独立生成多个复述内容,并采用多数投票系统来确定最合适的答案。这种方法旨在提高答案的可靠性和准确性,从而提高输出的质量和可信度。
7.2 定制
参数知识引导(Parametric Knowledge Guiding,PKG)框架是一种定制大语言模型输出的方法。通过使用预训练模型在内部生成背景知识,PKG无需传统的外部检索过程。这种方法直接将特定领域或任务的知识集成到生成步骤中,显著增强了大语言模型根据给定上下文或要求生成回复的能力。
Self-RAG提供了一种策略,在可定制的解码算法中融入反思令牌。这种技术允许根据特定任务动态调整模型的检索和生成行为,有助于生成更通用的回复。根据需求,这种方法可以针对准确性或创造性进行调整,在生成满足不同需求的输出时提供灵活性。
“子图检索增强生成”(SUbgraph Retrieval-augmented GEneration,SURGE)通过应用图文本对比学习实现定制。这种方法确保生成的对话回复与检索到的子图中包含的知识紧密对齐,产生特定、相关且深深植根于对话上下文的回复。通过保持检索到的知识与生成的文本之间的一致性,SURGE能够生成准确反映子图详细知识的输出,提高回复的相关性和特定性。
8. 聊天引擎
构建一个优秀的RAG系统,使其能够针对单个查询多次有效工作,下一个重要的部分是聊天逻辑,这需要考虑对话上下文,就像大语言模型出现之前的经典聊天机器人那样。
这是支持后续问题、指代消解或与先前对话上下文相关的任意用户命令所必需的。它通过查询压缩技术来解决,该技术会同时考虑聊天上下文和用户查询。
一如既往,实现上述上下文压缩有几种方法:
- 一种流行且相对简单的是ContextChatEngine,它首先检索与用户查询相关的上下文,然后将其与内存缓冲区中的聊天历史一起发送给大语言模型,以便大语言模型在生成下一个答案时能够了解先前的上下文。
- 稍微复杂一点的是CondensePlusContextMode,在每次交互中,聊天历史和最后一条消息会被浓缩成一个新的查询,然后这个查询会进入索引,检索到的上下文会与原始用户消息一起传递给大语言模型以生成答案。
值得注意的是,LlamaIndex中还支持基于OpenAI智能体的聊天引擎,提供了更灵活的聊天模式,Langchain也支持OpenAI的功能API。
9. RAG中的智能体
智能体(Langchain和LlamaIndex都支持)几乎在第一个大语言模型API发布时就出现了,其核心思想是为具备推理能力的大语言模型提供一组工具和一个待完成的任务。这些工具可能包括一些确定性函数,比如任何代码函数、外部API,甚至其他智能体。这种大语言模型链式调用的想法正是LangChain名称的由来。
智能体本身是一个庞大的领域,在RAG概述中不可能对这个主题进行深入探讨。所以我将继续以基于智能体的多文档检索为例,并简要介绍一下OpenAI Assistants,因为它是一个相对较新的事物,在最近的OpenAI开发者大会上作为GPTs推出,并且在下面描述的RAG系统中发挥作用。
OpenAI Assistants基本上实现了许多围绕大语言模型所需的工具,这些工具我们之前在开源项目中才能看到,比如聊天历史记录、知识存储、文档上传接口,也许最重要的是函数调用API。后者提供了将自然语言转换为对外部工具的API调用或数据库查询的能力。
在LlamaIndex中有一个OpenAIAgent类,它将这种先进的逻辑与ChatEngine和QueryEngine类相结合,提供基于知识和感知上下文的聊天功能,以及在一次对话轮次中进行多个OpenAI函数调用的能力,这真正带来了智能体的智能行为。
让我们来看一下多文档智能体方案,这是一个相当复杂的设置,涉及为每个文档初始化一个智能体(OpenAIAgent),该智能体能够进行文档总结和经典的问答操作,还有一个顶级智能体,负责将查询路由到文档智能体并进行最终答案的合成。
每个文档智能体有两个工具,一个向量存储索引和一个摘要索引,它会根据路由过来的查询决定使用哪一个。
对于顶级智能体来说,所有文档智能体都算是工具。
说明多文档智能体的方案,涉及查询路由和智能体行为模式
这个方案展示了一个先进的RAG架构,其中每个相关智能体都要做出很多路由决策。这种方法的好处是能够比较不同文档及其摘要中描述的不同解决方案或实体,同时具备经典的单文档总结和问答机制,这基本上涵盖了最常见的与文档集合聊天的用例。
从图中可以猜到,这种复杂方案的缺点是速度有点慢,因为智能体内部与大语言模型有多次来回迭代。需要注意的是,在RAG流程中,调用大语言模型始终是耗时最长的操作,而搜索在设计上已经针对速度进行了优化。
10. 编码器和大语言模型微调
这种方法涉及微调RAG流程中涉及的两个深度学习模型中的一些参数,一个是负责嵌入质量,进而影响上下文检索质量的Transformer编码器;另一个是负责充分利用提供的上下文来回答用户查询的大语言模型(幸运的是,后者是很好的少样本学习器)。
如今一个很大的优势是可以使用像GPT-4这样的高端大语言模型来生成高质量的合成数据集。
但我们应该始终意识到,采用专业研究团队在经过仔细收集、清理和验证的大型数据集上训练的开源模型,并使用小型合成数据集进行快速微调,可能会降低模型的整体能力。
10.1 编码器微调
我对编码器微调这种方法也持一定的怀疑态度,因为针对搜索优化的最新Transformer编码器已经相当高效。
所以我在LlamaIndex的笔记本设置中测试了bge-large-en-v1.5(撰写本文时在MTEB排行榜上排名前4)微调后的性能提升,结果显示检索质量提高了2%。虽然提升幅度不大,但知道有这个选择还是不错的,特别是如果我们正在为特定领域的数据集构建RAG。
10.2 排序器微调
如果我们不完全信任基础编码器,另一个不错的传统选择是使用交叉编码器对检索结果进行重新排序。
它的工作方式如下:我们将查询和检索到的前k个文本块分别通过SEP标记分隔后传递给交叉编码器,并对其进行微调,使其对相关文本块输出1,对不相关的输出0。
这里可以找到这种微调过程的一个很好的示例,结果显示通过交叉编码器微调,成对得分提高了4%。
10.3 大语言模型微调
最近OpenAI开始提供大语言模型微调API,LlamaIndex有一个关于在RAG设置中微调GPT-3.5-turbo的教程,目的是从GPT-4中“提取”一些知识。其思路是获取一个文档,使用GPT-3.5-turbo生成一些问题,然后使用GPT-4根据文档内容为这些问题生成答案(构建一个由GPT-4驱动的RAG流程),接着在这个问答对数据集上微调GPT-3.5-turbo。用于评估RAG流程的Ragas框架显示,在忠实度指标上提高了5%,这意味着微调后的GPT-3.5-turbo模型在生成答案时比原始模型更好地利用了提供的上下文。
Meta AI Research最近的论文《检索增强双指令调整》(Retrieval Augmented Dual Instruction Tuning,RA-DIT)展示了一种更复杂的方法,提出了一种在查询、上下文和答案三元组上同时微调大语言模型和检索器(论文中是双编码器)的技术。有关实现细节,请参考这个指南。
这项技术用于通过微调API微调OpenAI的大语言模型和Llama2开源模型(在论文中),在知识密集型任务指标上提高了约5%(与使用RAG的Llama2 65B相比),在常识推理任务上也有几个百分点的提升。
11. 评估
有几种评估检索增强生成(RAG)系统性能的框架,它们都采用了一些独立的指标,如整体答案相关性、答案有据性、忠实度和检索上下文相关性。
不同RAG评估框架的比较
上一节提到的Ragas框架,将忠实度和答案相关性作为生成答案的质量指标,并使用经典的上下文精度和召回率来评估RAG方案中的检索部分。
这里可以找到一个简单的检索器评估流程示例,该示例在编码器微调部分有应用。
OpenAI的烹饪书中展示了一种更先进的方法,它不仅考虑命中率,还考虑平均倒数排名(一种常见的搜索引擎指标),以及生成答案的指标,如忠实度和相关性。
LangChain有一个相当先进的评估框架LangSmith,在其中可以实现自定义评估器,并且它还可以监控RAG流程中的运行轨迹,从而让我们的系统更加透明。
如果我们使用LlamaIndex进行构建,有一个rag_evaluator
llama pack,它提供了一个快速工具,可使用公共数据集评估我们的RAG流程。
本文转载自柏企科技圈,作者:柏企
