RAG,也就是检索增强生成,已经证明是个挺管用的招儿,能让大型语言模型(LLM)的回答更靠谱,还能搞定它们有时候会“幻觉”的问题。简单来说,RAG就是给LLM们提供了一些上下文,帮它们生成更准确、更符合上下文的回答。这些上下文可以来自各种地方,比如你的内部文件、向量数据库、CSV文件、JSON文件等等。
RAG里头有好多东西要一起工作。这些包括处理查询、切分上下文、检索上下文、重新排列上下文,还有LLM自己来生成回答。每个部分都会影响到RAG最后生成的回答质量。但是,要在每个部分找到最好的方法组合,让RAG的性能最优化,这事儿挺难的。
这篇文章里,我们会聊聊RAG里面常用的一些技术,评价一下每个成分的最佳做法,然后根据这篇论文《Searching for Best Practices in Retrieval-Augmented Generation》找出能带来最优化RAG生成回答的最佳组合。那咱们就从RAG的各个部分开始讲起。
就像之前说的,RAG是个挺给力的方法,能帮LLM解决幻觉问题,这问题通常发生在我们问的问题超出了它们训练数据的范围,或者需要专业知识的时候。比如,如果我们问LLM一些关于我们内部数据的问题,可能会得到个不靠谱的答案。RAG通过提供能帮助回答我们问题的相关上下文来解决这个问题。
RAG是由一系列组成工作流程的部分构成的。典型的RAG部分包括:
-
查询分类: 判断我们的查询是不是需要检索上下文,还是可以直接让LLM处理。
-
上下文检索: 找到和我们查询最相关的前k个候选上下文。
-
上下文重排: 对从检索部分拿到的前k个候选进行排序,从最相似的一个开始。
-
上下文重新打包: 把最相关的上下文整理成更有结构的格式,这样生成回答的时候更好用。
-
上下文摘要: 从相关的上下文中提取出关键信息,这样能改善生成的回答。
-
响应生成: 根据查询和相关的上下文生成回答。
图 - RAG组件
虽然RAG的这些组件在生成回答时很有帮助,但在我们真正用上RAG之前,还得考虑其他一些事儿。
首先,我们得把那些上下文文档转换成向量嵌入,这样它们才能在RAG里发挥作用。所以,挑一个最合适的嵌入模型和策略来表示我们的文档,这事儿特别关键。
一个嵌入就是输入文档的语义丰富表示。但如果作为上下文的文档太长,可能会让LLM在生成回答时犯迷糊。解决这问题的常见方法是用分块方法,把文档分成几个小块,然后每个小块都转换成嵌入。选个好的分块方法和大小很重要,因为太小的块可能信息不够,帮不上忙。
图 - RAG工作流程
接下来,我们得想想怎么存这些嵌入。如果你不需要处理太多嵌入,直接存本地内存就行。但通常我们会处理成千上万甚至百万级别的嵌入,这时候就需要用向量数据库,比如Milvus,来存它们。选对向量数据库对我们RAG的成功很关键。
最后,我们还得考虑LLM本身。如果需要的话,我们可以对LLM进行微调,让它更符合我们的特定需求。不过微调成本挺高的,大多数情况下也没必要,尤其是如果我们用的是一个参数很多的高性能LLM。
接下来,我们会聊聊RAG每个部分的最佳实践。然后,我们会探索这些最佳实践的组合,并推荐几种既保持性能又高效的RAG部署策略。
就像之前提到的,RAG在确保LLM生成准确和上下文相关回答时特别有用,尤其是我们需要从内部数据中获取专业知识的时候。不过,RAG也会让生成回答的时间变长。事实上,不是所有查询都需要检索过程,很多查询LLM自己就能处理。所以,如果查询不需要检索,跳过上下文检索这一步会更有好处。
我们可以搞一个查询分类模型来决定是否需要检索上下文,然后再进行回答生成。这种分类模型通常是一个监督模型,比如BERT,主要任务是预测查询是否需要检索。和其他监督模型一样,我们得先训练它才能用。为了训练这个模型,我们需要准备一个数据集,里面包含示例提示和它们是否需要检索的二元标签。
图 - 查询分类数据集示例
论文里头,他们用的是BERT-base-multilingual这个模型来做查询分类。训练数据包含了15种不同类型的提示,比如翻译、摘要、重写、上下文学习等等。这些提示有两种标签:“sufficient”表示提示里头的信息足够了,不需要再检索;“insufficient”则表示信息不全,需要专业知识,得检索一下。用这个方法,模型在准确率和F1分数上都达到了95%。
这个查询分类的步骤能帮我们省不少事儿,它能让RAG过程更高效,避免对那些LLM自己就能处理的查询进行不必要的检索。它就像个过滤器,确保只有真正需要额外上下文的查询才被送到更费时间的检索过程。
图 - 查询分类结果
分块就是把长文档切成小段的过程,这对给LLM提供更细的上下文很有帮助。分块方法有好几种,比如基于令牌的和基于句子的。基于句子的分块在简单性和语义保留之间通常能取得不错的平衡。选分块方法的时候,我们得注意分块的大小,因为太小的块可能给不了LLM啥有用的上下文。
图 - 把长文档切成小段
为了找到最合适的分块大小,他们对Lyft 2021的文档做了评估。选了文档的前60页作为语料库,然后切成了不同大小的块。接着用LLM基于这60页生成了170个查询。用来生成嵌入的模型是text-embedding-ada-002,而用来生成基于所选查询的响应的LLM是Zephyr 7B。
为了评估模型在不同分块大小下的表现,他们用了GPT-3.5 Turbo。他们用了两个指标来评价响应的质量:忠实度和相关性。忠实度是看响应是不是幻觉的,或者是不是和检索到的上下文匹配;相关性则是看检索到的上下文和响应是不是和查询匹配。
图 - 不同分块大小比较
实验结果告诉我们,最大分块大小设为512个令牌是让LLM生成高度相关回答的最好选择。短一点的分块大小,比如256个令牌,表现也不错,而且还能提高RAG应用的整体运行速度。可以用一些高级的分块技术,比如Small2big
和滑动窗口,来结合不同分块大小的优势。
Small2big
这种分块方法挺聪明的,先用小尺寸的块去匹配查询,然后用包含这些小块信息的大一些的块作为LLM的最终上下文。滑动窗口方法则是在块之间留一些令牌重叠,这样可以保持上下文信息不丢失。
图 - 不同分块技术比较
实验还发现,用175个令牌的小分块和512个令牌的大分块,再加上20个令牌的块重叠,这两种分块技术都能提高LLM回答的忠实度和相关性分数。
接下来,找到最好的嵌入模型来表示每个块作为向量嵌入也特别重要。为了这个目的,他们在namespace-Pt/msmarco上做了测试。结果显示,LLM Embedder和bge-large-en模型表现最好。但是LLM Embedder比bge-large-en小了三倍,所以它被选为实验的默认嵌入模型。
图 - 不同嵌入模型在namespace-Pt/msmarco上的结果
向量数据库在RAG应用里扮演着特别重要的角色,尤其是在存储和检索相关上下文方面。在常见的现实世界RAG应用中,我们得处理一大堆文档,这意味着得存一大堆上下文嵌入。在这种情况下,把嵌入存在本地内存里是不够的,计算在一大堆嵌入里头检索相关上下文会花很长时间。
向量数据库就是用来解决这些问题的。有了向量数据库,我们可以存几百万甚至几十亿的向量嵌入,而且能瞬间完成上下文检索。在选择最好的向量数据库时,我们得考虑几个因素,比如支持的索引类型、能不能支持十亿级别的向量、是否支持混合搜索、有没有云原生能力。
按照这些标准,Milvus作为最好的开源向量数据库脱颖而出,和其他竞争对手比如Weaviate、Chroma、Faiss、Qdrant等相比,Milvus更胜一筹。
图 - 各种向量数据库比较
Milvus在索引类型支持方面做得挺全面的,提供了好几种索引方法来满足不同的需求。比如,有简单的平面索引(FLAT),还有专门用来加速检索过程的倒排文件索引(inverted file index, IVF-FLAT)和 (Hierarchical Navigable Small World, HNSW)
)。如果你想要压缩存储上下文需要的内存,还可以在嵌入索引的过程中用到产品量化(PQ)。
Milvus还支持混合搜索方法,这让我们能在上下文检索过程中结合两种不同的方法。比如,我们可以同时用密集嵌入和稀疏嵌入来检索相关上下文,这样能提高检索到的上下文与查询的相关性,进而提升LLM生成的响应质量。如果需要的话,我们还可以结合密集嵌入和元数据过滤。
检索组件的主要任务是为给定的查询找到最相关的前k个上下文。不过,这个组件可能会受到查询本身的重大影响,因为原始查询通常写得不够好或者表达不清楚,缺少RAG应用检索相关上下文需要的语义信息。
解决这个问题的几个常用技术包括:
-
查询重写: 让LLM重写原始查询,提高其清晰度和语义信息。
-
查询分解: 把原始查询拆分成子查询,然后基于这些子查询执行检索。
-
伪文档生成: 根据原始查询生成假设性的或合成的文档,然后用这些假设性文档去检索数据库中的类似文档。这种方法最著名的实现就是假设性文档嵌入,也就是HyDE(Hypothetical Document Embeddings)。
实验显示,结合HyDE和混合搜索在TREC DL19/20上取得了最好的结果,比单独使用查询重写和查询分解效果要好。实验中提到的混合搜索结合了LLM Embedder来获得密集嵌入,并结合BM25来获得稀疏嵌入。
HyDe + hybrid search
的工作流程是这样的:首先,我们用HyDE生成回答查询的假设性文档。然后,这个假设性文档和原始查询连接起来,接着分别用LLM Embedder和BM25把它们转换成密集和稀疏嵌入。这样,我们就能更有效地检索到与查询最相关的上下文了。
图 - 不同检索方法结果
尽管结合HyDE和hybrid search
取得了最佳结果,但它也带来了更高的计算成本。基于对几个NLP数据集的进一步测试,hybrid search
和仅使用密集嵌入的结果与HyDE + hybrid search
相当,但延迟几乎降低了10倍。因此,建议使用hybrid search
。
由于我们使用hybrid search
,检索到的上下文基于来自密集和稀疏嵌入的向量搜索。因此,还有趣的是,根据这个方程,检查密集和稀疏嵌入之间的权重值对整体相关性分数的影响:
图 - hybrid search
不同alpha值结果
实验表明,权重值为0.3在TREC DL19/20上获得了最佳的整体相关性分数。
重排和重新打包技术
重排技术的核心目标是重新排序从检索方法中得到的最相关的前k个上下文,确保最相似的上下文排在列表的最前面。重排上下文主要有两种方法:
-
DLM重排: 这种方法用深度学习模型来进行重排。模型训练时,输入是原始查询和上下文的配对,输出是二元标签,比如“真”表示这对查询和上下文是相关的,“假”则表示不相关。然后,根据模型预测查询和上下文配对为“真”的概率来对上下文进行排序。
-
TILDE重排: 这种方法依据原始查询中每个词的概率来进行重排。在推理阶段,我们可以使用仅基于查询概率的组件(TILDE-QL)来进行更快的重排,或者使用TILDE-QL和文档概率组件(TILDE-DL)的组合,虽然这样计算成本会更高,但能改善重排结果。
图 - 不同重排方法结果
在MS MARCO Passage排名数据集上的实验显示,使用Llama 27B模型的DLM重排方法提供了最好的重排性能。但是,由于这是一个大型模型,使用它会有明显的计算成本。因此,推荐使用Mono T5来进行DLM重排,因为它在性能和计算成本之间取得了平衡。
重排阶段结束后,我们还得考虑如何把重排后的上下文呈现给我们的LLM:是按降序(“正向”)还是升序(“反向”)。根据本文的实验,发现使用“反向”配置能生成质量最好的响应。推测是因为将更相关的上下文放在更接近查询的位置,可能会让LLM产生更准确和连贯的响应。
面对从前面几个组件检索到的长上下文时,我们可能希望让它们更紧凑,去掉冗余信息。为了实现这个目标,通常会采用摘要方法。
上下文摘要技术主要有两种:提取式和抽象式。
提取式摘要是把输入文档切分成小段落,然后根据重要性进行排序。而抽象方法则是生成一个只包含重要信息的新上下文摘要。
图 - 不同摘要方法比较
基于NQ、TriviaQA和HotpotQA三个不同数据集的实验显示,与其他抽象和提取方法相比,使用Recomp的抽象摘要方法表现最佳。
现在我们知道了每个RAG成分的最佳方法,我们可以在更多数据集上测试前面提到的所有方法。结果表明,每个成分都对我们RAG应用的整体性能有所贡献。以下是根据五个不同数据集的结果总结,每个成分中的每种方法:
图 - 寻找最佳RAG实践结果
查询分类组件在提升响应准确性和减少整体运行时间上发挥了重要作用。这个步骤帮助我们判断一个查询是否需要进行上下文检索,或者是否可以由LLM直接处理,从而提高了系统的效率。
检索组件对于确保我们能够获得与查询相关的上下文候选非常关键。对于这个组件,推荐使用像Milvus这样可扩展且性能高的向量数据库。此外,建议采用混合搜索或仅密集嵌入搜索,这些方法在全面匹配上下文和计算效率之间取得了平衡。
重排组件通过重新排序从检索组件获得的前k个上下文,确保我们能够得到最相关的上下文。鉴于其在性能和计算成本之间的平衡,推荐使用Mono T5模型进行重排。这一步进一步细化了上下文的选择,优先考虑与查询最相关的上下文。
在重新打包上下文时,建议采用“反向”方法。这种方法将最相关的上下文放在离查询最近的位置,可能会使LLM生成更准确和连贯的响应。
最后,在上下文摘要方面,使用Recomp的抽象方法表现最佳。这种技术有助于压缩长上下文,同时保留关键信息,使LLM更容易处理并生成相关响应。
在大多数情况下,LLM微调并不是必需的,特别是如果你使用的是一个参数众多的高性能LLM。然而,如果你由于硬件限制只能使用较小的LLM,可能需要对它们进行微调,以使它们在生成与你用例相关的响应时更加健壮。在微调LLM之前,需要考虑你将用作训练数据的数据。
在数据准备阶段,可以收集以提示和上下文作为一对输入,以生成的文本作为输出的训练数据。实验表明,在训练期间混合使用相关和随机选择的上下文数据将获得最佳性能。背后的直觉是,在微调期间混合相关和随机上下文可以提高LLM的鲁棒性。
本文探讨了从查询分类到上下文摘要的各个RAG组件,并讨论并强调了每个组件中的最优方法。这些优化的组件协同工作,提高了RAG系统的整体性能,提升了生成响应的质量和相关性,同时保持了计算效率。通过在每个组件中实施这些最佳实践,我们可以创建一个更强大有效的RAG系统,能够处理广泛的查询和任务。
参考论文:Searching for Best Practices in Retrieval-Augmented Generation, https://arxiv.org/pdf/2407.01219
标签:检索,RAG,嵌入,查询,构建,LLM,上下文 From: https://blog.csdn.net/qianggezhishen/article/details/143849550