RAG并不是AI Agent落地的第一步,只是刚好最近在研究,就趁热打铁先写这部分的内容,后续再调整编号。
RAG也可以是独立于Agent的命题,即使不做AI Agent,在做知识问答系统等“提问-检索-回答”的系统时,也都可以迁移使用。
认知
什么是RAG
RAG,全称是Retrieval Augmented Generation,也就是检索增强生成,它结合了检索(retrieval)和生成(generate)两大技术,旨在在处理复杂的查询和生成任务时提供更加准确的回答。
RAG的发展基于信息检索(information retrieval, IR)和自然语言处理(natural language processing, NLP)领域的深入研究,前者专注于从大规模数据集中找到与用户查询相关的信息,后者的目标则是让计算机能够理解、解释和生成人类语言的文本或口语信息。
why RAG
LLM作为chatbot和agent类应用的一个支持部分,其技术本质在提供响应的同时也带来了不可预测性。并且,LLM的训练数据是截至过去某个时间的静态知识。这些都会使其输出错误的答案。
具体可分为以下几点:
- 在没有答案的情况下提供虚假信息。
- 当用户需要特定的当前响应时,提供过时或通用的信息。
- 从非权威来源生成响应。
- 由于术语混淆,当同一个术语在多个来源中谈论不同的事情时,会被混用,进而产生不准确的响应。
而RAG可以在一些方面对LLM的不足进行弥补。
此外,AI Agent的设计中,RAG的应用域不只是知识,还有记忆(从长期记忆中检索,就像是人类的“回想”)。
RAG的局限
- RAG 依赖于知识外挂。如果检索到的信息不正确,RAG 就会生成不准确的结果。
- RAG 的检索部分涉及在大型知识库或网络上进行搜索,这从计算量方面来看,不仅费用高昂,而且速度慢,尽管相比于微调,速度还是快一些,费用也要低一些。
- 要将检索和生成部分无缝集成到一起,这需要进行精心设计和优化,而设计和优化可能会在训练和部署方面造成潜在难题。
- 当处理敏感数据时,从外部来源检索信息可能带来隐私问题。由于需要遵守隐私和合规要求,这也可能会限制 RAG 能够访问的来源。然而,这能通过文档级访问权限加以解决;文档级访问权限指您可以向特定角色赋予访问和安全许可。
- RAG 的基础是基于事实的准确性。它可能难以生成富有想象力或虚构性质的内容,这限制了它在创意内容生成领域的使用。
范式
这一部分将讨论RAG落地的路径。
RAG的构成
关于RAG的实现有两份不错的参考资料,一份是Langchain在2023年开始更新的Langchain/RAG from Scratch,它拆解了RAG流程,并在流程的不同节点进行展开,讨论如何构造和优化;另一份是同济和复旦在24年3月出的一份大语言模型RAG的综述(Retrieval-Augmented Generation for Large Language Models: A Survey),讨论了RAG所需要解决的问题、范式的演进、效果评价方式,总结了RAG生态系统的结构,并展望了未来的趋势。
- RAG from Scratch
Langchain教程中的overview

- Retrieval-Augmented Generation for Large Language Models: A Survey
RAG的演进:naive RAG - Advanced RAG - Modular RAG

RAG生态系统

以下结合这两份材料以及材料中提到的关联论文来讨论RAG的实现范式。
朴素的RAG (Naive RAG)
基础的RAG也即最初形态:向生成过程引入外部知识,引入的过程分为三步,知识嵌入、检索和生成:
- 知识嵌入:解析并将知识文本切分为若干chunk,使用embedding模型对chunk结果进行向量化,构建索引,存储到向量数据库或vectorstore。
- 检索:基于用户的提问,生成查询,使用同样的embedding模型进行向量化,并与知识进行匹配(匹配的本质是向量间的远近),返回匹配度最高的K个结果所在的chunk。
- 生成:将匹配检索的结果与问题、上下文、prompt给到LLM,使LLM基于这些内容生成回答。
朴素的RAG在实际应用时存在以下问题:
- 检索阶段,检索内容直接使用用户的提问,因此用户的提问直接影响检索的结果;检索结果依据向量距离排名,而向量距离不等同于语义,相近并不等同于符合度高;受知识库本身数据数量、质量的影响,稠密空间的匹配时间较久,而稀疏空间的匹配结果较差
- 生成阶段,当检索的内容与上下文不符,或模型已有的知识不符时,可能会产生幻觉,从而生成错误或有偏差的回答
- garbage in garbage out,当以上因素叠加,也即提问不够好,匹配不准确,匹配的空间较稀疏时,生成的结果自然更差,更不用说这个过程还很依赖LLM本身的归纳总结能力
进阶的RAG (Advanced RAG)
朴素的RAG无法在复杂的场景下或是较差的知识库条件下有好的表现,才有更进一步的进阶版RAG,也就是在检索过程更进一步精进。此时,IR、NLP以及深度学习领域的诸多技术得到了更深的应用。
我们先暂停回想一下自己是如何发现和解决问题的:提出问题,查询资料(这个过程可能会有越来越多的问题),归纳总结,反推验证,不断重复,直至觉得满意,最后得出结论。熟练之后有些行为发生得如此自然而细微以至于我们意识不到自己在做的事具体是什么目的。
- 提出问题:该怎样表述自己的问题?该怎样对问题进行拆解或抽象以便于寻找答案?对于不断出现的问题,如何理解它们之间的关系?
- 查询资料:有哪些工具可以用来检索?以怎样的视角、带着怎样的问题去搜索和筛选资料?检索时应该怎样对问题进行重新表述以求能够比较全面地获得需要的资料?
- 归纳总结:以怎样的逻辑进行信息提取?如何保证信息提取过程的深入、准确?
- 得出结论:如何基于信息、思考得出最终的结论?如何推敲结论的正确性和完备性?
尝试通过计算机实现这一人类几乎毫不费力的过程时,会遇到以下核心问题:
- 如何解析、理解和表征用户输入?
- 如何解析、理解和组织信息集?
- 如何将用户输入与信息集中的信息匹配起来,更重要的是,如何在具有语义深度的层面实现匹配?
- 如何评价整个过程的准确性和完整性?
而这些正是IR和NLP的研究内容。可以说,进阶版的RAG其实就是这些相关领域的技术的迁移应用。
现在再来看为了优化检索的效果,在检索前、中、后分别可以有哪些有趣的尝试:
- 检索前:此阶段主要关注对于用户输入和信息集的处理从而能在准确度或消耗上有更好的表现
- 重构查询:核心在于“定义出符合用户意图并且适合用于检索的问题”
- multi-query:由于向量数据库的匹配基于空间距离,因此单词的使用可能会对结果产生重大影响。多路查询,也即对原始问题以“提升向量匹配效果”为目标进行改写,然后并行地在数据库中进行检索,并对最终的结果取并集。MultiQueryRetriever
- RAG-fusion:与multi-query的出发点类似,RAG-fusion也是通过对原始问题进行改写,并行地检索来突破原始问题对检索结果的影响,不同的是,RAG-fusion对检索结果的聚合方式不是取并集,而是对不同查询的各个结果,进行权重赋予,之后以倒排的逻辑对检索的文档进行排序,这个过程同时给原始问题一定的权重,从而使得重心不偏移的同时得到有深度的回答。Forget RAG, the Future is RAG-Fusion
- Decomposition:如果说改写问题是在同一水平面上对问题进行扩展以期获得一定的表现上的提升,decomposition(拆解)就是尝试将一个大的问题拆分为多个小的问题,然后对多个小的问题进行分别的查询、总结,最终得到对原始问题的回答。(查询的过程可以是递归的也可以是并行的)。这样拆解的思路更适用于本身具有一定复杂性的问题,对于那些由于很抽象或要件缺失而带来的难以回答或查询的问题,就不是很适用。
- Step-back:与拆解的“由一个问题到若干子问题”相反,step-back则是尝试将问题进行抽象化重构,从而使得查询和回答都能够在更高的层面进行,以此来使得LLM在检索相关资料时不至于迷失在问题的细节中,抓住核心逻辑,再做检索和回答。很适合对话细节较多且零散的场景。
- HyDE:与前面的从问题着手不同,HyDE(Hypothetical Document Embeddings)从问题的答案着手。传统的稀疏召回(sparse retrieval)无法实现优质的召回,零样本的稠密匹配(dense retrieval)则预训练成本高昂(数据集、计算资源),而HyDE则利用了LLM的能力,将检索召回拆解成了NLU(自然语言理解)和NLG(自然语言生成)任务:先调用LLM,针对提出的问题生成一个假的document,再将这份假的doc嵌入到向量空间与真实的document进行匹配。这样的拆解,很巧妙地利用了LLM的能力,把“找能开锁的钥匙”的问题,转换为了“找像某把钥匙的钥匙”的问题。这个方法无论在稀疏还是稠密的空间都适用,而且应该尤其适用于知识库空间极大的场景。Precise Zero-Shot Dense Retrieval without Relevance Labels
- 引入查询路由:目的在于“找到合适的可以回答问题的资源和思维逻辑”
- 定位应该查询的资源:当数据存储在不同的数据库或知识库中时,需要增加一定的逻辑,使得LLM能够根据问题,选择合适的数据源进行检索。也就需要前置地对知识库结构本身进行有效划分。
- 切换能够得到高质量回答的思维:与人类的固执不同,大模型的思维逻辑可以快速地通过prompt进行切换,可以在不同的任务环节切换自己的“思考帽”。这类路由的实现方式是:在生产节点之前,引入话题判断节点,通过语义的理解,确定话题,然后根据话题切换LLM的prompt,从而使得后续的回答更加专业。
- 优化索引:目的在于“为检索提供更好的被匹配对象和匹配路径”
- 优化chunk过程:chunk是构建索引的第一步,原始文本经过chunk被处理成一个个document,这些document也即后续被匹配和检索的document。chunk的过程需要设定的内容主要包括chunksize和overlap,前者是一个document有多大,后者是document之间的重合大小,此外还有断句符号、忽略内容等。在很多产品中,chunk都有默认配置,甚至不可见,但这并不意味着一套参数可以四处通用:chunksize过大,召回后很容易引入过多无关信息,同时造成token浪费,chunksize过小,很可能拉长匹配时间或是返回多而零散的结果。实际项目中,对于知识文本,需要有一定的机制来判断合适的参数,并能够对结果有有效评价。(一个有趣的chunksize选取可视化项目:blackinkkkxi-RAG_langchain)
- 以“意义”为指导:文本切分的一个难点是chunksize的选取,因为人类写作习惯的差异性,论点不会均匀分布在文本中,有时几千字只为说明一件事,有时又一段文本包含多个关键论点。很自然地,我们会想,有没有办法动态地基于语义动态地选择chunksize,或者在原有的文本上基于“意义”做一些功夫。优秀尝试包括多重表征和RAPTOR。简单来说,就是在基础的chunk基础上,对文档进行含义提取,并基于含义进行聚类,这样的提取、聚类可以叠加若干层,而基于这样的索引结构,在检索时也可以选择从粗到细的定位。(需要注意这种树状的结构与向量数据库本身的hnsw索引有本质的区别)
- 选择合适的Embedding模型:目的在于“提升匹配的效果,或节约匹配的消耗”
- 作为转码器的Embedding模型对于匹配的重要性不言而喻。一个经过大规模语料训练的、能够充分理解文本的Embedding模型相较于规模小的模型,能够发挥更好的作用。
- 预训练的Embedding模型:选择模型时,除了从参数、训练数据等维度来比较和选择优秀的模型,一些经过特殊结构设计的微调模型能够带来额外的灵活性和匹配消耗上的优势。例如ColBERT(Contextualized late interaction over BERT),Jina-ColBERT。以ColBERT为例,它解耦了对查询和文档的Embedding过程,使设计者可以选择不同的模型来进行词嵌入;此外,ColBERT以token而非整个查询或文档生成向量,这就使得模型可以在不执行交叉注意力计算的情况下,通过计算最大相似度来评估查询和文档之间的相关性,也因此,ColBERT不仅能解决嵌入、匹配,还可以单独用来对结果进行重排(re-rank)。
- 重构查询:核心在于“定义出符合用户意图并且适合用于检索的问题”
- 检索中:此阶段主要关注如何优化检索/匹配本身的效果。
- 优化查询手段:基于问题和知识库的数据结构,选择合适的检索手段
- Text2SQL/Text2Cypher:我们所积累的数据有结构化和非结构化之分,对于非结构化的数据,能够通过前面的重写查询的各种方法提升召回效果,而对于结构化的数据,以对应的查询语句进行查询显然更加高效,精确度也更高。因此,在一些项目中,可以按照业务场景和数据源结构(结构化数据的比例)引入SQL等查询语言。这个过程会引入其他风险,例如模型幻觉导致的无效查询,以及大规模数据泄露等。实际使用的时候需要谨慎。langchain-query construction
- 元数据过滤:除了数据内容本身,还可以用数据的数据来进行筛选,例如按照发布时间、字数、时长、来源等进行粗筛。当元数据比较完善时比较适用,而且尤其适用于对资料时效性要求较高的场景。
- 优化查询手段:基于问题和知识库的数据结构,选择合适的检索手段
- 检索后:此阶段主要关注如何对结果进行评价和筛选从而得到最适合用于生成最后的答案的材料
- 结果重排:重排机制是基于生成模型本身的得分进行文档的重排序。对于每个检索到的文档,RAG的生成组件会尝试生成一个答案,并基于生成答案的概率为每个文档赋予一个评分。这个评分反映了文档用于生成正确答案的潜在质量和相关性。重排之后,选择质量和相关性较高的文档,进入生成阶段。
- 重启检索:对结果进行评价,如果不符合要求,则在新的数据源中进行重新检索。
总结一下,进阶的RAG,就是面对层出不穷的场景和问题,将RAG过程一步步地拆解、细化,分析每一步的细分步骤、选择和结果,寻找合适的办法来解决或优化,几乎可以说有无尽的方案来“雕花”且它们之中没有绝对占优的。可以大胆尝试不同方案的组合,同时要考虑数据条件和业务链路复杂度。
模块化的RAG(Modular RAG)
以工程化的视角看来,在经历了进阶的RAG阶段,很自然地会想到,将链路上的不同环节的工具独立出来自成模块,之后可以按场景按需取用和组合应用,这就是模块化的RAG,它更具适应性和灵活性。
- 模块:在常见的检索、读取、重写、重排之外,还有以下新的模块
- 搜索:除了信息集之外,允许LLM通过生成查询语句对数据库、知识图谱等数据源进行检索。
- 路由:为查询选择最佳路径,无论是涉及信息源的切换、合并还是信息的总结。
- 记忆:通过记忆来引导LLM进行自我增强的检索
- 预测:通过使用LLM来基于问题生成可能的上下文,来限制噪声的产生,从而使得答案更加收敛
- 融合:通过多路查询扩充查询内容和匹配结果,之后再通过重排等方式筛选融合得到有效信息
- 任务适配器:自动化地进行prompt切换、调优,样例生成,来适配RAG的下游任务
- 模式:
- 朴素的RAG:检索->生成
- 进阶的RAG:重写->检索->重排->生成
- 自适应:Demonstrate-Search-Predict (DSP)、Retrieve-Read-Retrieve-Read(RRR)、Self-RAG等框架,在模块之间引入了协同机制,使得整个RAG系统具备依据任务复杂度和结果进行自适应调整的能力
RAG效果的评估
步骤
RAG+LLM流程的实现评估,可划分为以下几步:
- 准备测试数据集:让熟悉业务实际/领域的专家,或者使用高阶的LLM来辅助,准备用于测试的数据集(包含Q&A),确保测试数据集符合标准。
- 定义成功指标:依据目标,定义衡量成功的指标。诸如langchain和ragas这样的框架有定义一些指标,例如忠实度(faithfulness)、上下文召回率(context recall)、上下文精准度(context precision)、答案相似度(answer similarity)等。
- 创建自动化测试pipeline:定义自动化流程,以此来推进整个RAG工程的快速迭代优化。
指标体系
RAG的检索可以视为一种分类任务,也即以“与问题相关”为判断依据,将chunk分为“有关”与“无关”两类。而对于分类问题,预测结果与真实情况的组合有以下四种:
- 真阴性(True Negative, TN):分类为负,实际也为负,即分类正确
- 真阳性(True Positive, TP):分类为正,实际也为正,即分类正确
- 假阴性(False Negative, FN):分类为负,实际为正,即分类错误
- 假阳性(False Positive, FP):分类为正,实际为负,即分类错误
评价分类效果有以下常见指标:
- 精确率(precision):分类正确的正样本数占全部被分类为正的样本数的比率。 precision = TP / (TP + FP)
- 召回率(recall):分类正确的正样本数占全部实际为正的样本数的比率。recall = TP / (TP + FN)
- 正确率(accuracy):准确率和召回率互相影响,理想状态下肯定追求两个都高,但是实际情况是两者相互“制约”:追求准确率高,则召回率就低;追求召回率高,则通常会影响准确率。若两者都低,则一般是出了某种问题。accuracy = (TP + TN) / (TP+ FP + TN + FN)
- 调和均值(F1 Score)精准率和召回率是此消彼长的,即精准率高了,召回率就下降,在一些场景下要兼顾精准率和召回率,就有 F1 score。F1值是来综合评估精确率和召回率,当精确率和召回率都高时,F1也会高。2/F = 1/P + 1/R
评价RAG的效果,我们既可以独立地看检索和生成单元的效果,也可以选择直接用输入和输出来进行端到端地评估:
逐组件评估
RAG由检索和生成组合而成,因此,评价RAG效果时,可分别从检索和生成两个角度进行。
- 检索
- 上下文精确率(context precision):使用input与检索得到的结果进行比较,判断与input更相关的chunk是否排名更靠前。
- 上下文召回率(context recall):比较检索的结果与“期待/标准答案”的一致性,判断是否检索到了所有与答案相关的chunk。
- 上下文相关度(context relevancy):比较检索结果与input的关联度。
- 生成
- 忠实度(faithfulness):比较最终输出与检索的结果的关联度。值在0到1之间,越大越好。
- 回答关联度(answer relevancy):比较最终输出与输入的关联度。值“多数时候在0到1之间”,越大越好。
端到端评估
- 回答语义相似度(answer semantic similarity):比较回答与标准答案的语义相似度
- 回答正确率(answer correctness):比较回答与基本事实的相似度,同时考虑语义相似度和事实相似度
除了以上的指标之外,不同的评估框架可能会有自己的指标,可以依据使用场景和数据情况,进行选择和设计。
参考
关联Repo
run-llama/rags
RAGflow
RAGatouille
Mintplex-Labs/anything-llm
Langchain-RAG from Scratch
blackinkkkxi-RAG_langchain
RAGAS
关联论文
Retrieval-Augmented Generation for Large Language Models: A Survey
From Local to Global: A Graph RAG Approach to Query-Focused Summarization
Interleaving Retrieval with Chain-of-Thought Reasoning for Knowledge-Intensive Multi-Step Questions
TAKE A STEP BACK: EVOKING REASONING VIA ABSTRACTION IN LARGE LANGUAGE MODELS
RAPTOR: RECURSIVE ABSTRACTIVE PROCESSING FOR TREE-ORGANIZED RETRIEVAL
Dense X Retrieval: What Retrieval Granularity Should We Use?
Precise Zero-Shot Dense Retrieval without Relevance Labels
Generate rather than Retrieve: Large Language Models are Strong Context Generators
其他
深度文本检索模型:DPR, PolyEncoders, DCBERT, ColBERT
ColBERT 杀死向量数据库?
漫谈基于深度学习的信息检索(Neural IR) - Maple小七的文章 - 知乎
Evaluating RAG Performance: A Comprehensive Guide
Evaluating RAG pipelines with Ragas + LangSmith
How to effectively evaluate your RAG + LLM applications