RAG(检索增强生成)是大模型应用的重要方向,它大幅缓解了大模型幻觉、信息更新不及时、专业域或私有域知识匮乏等问题,显著提升了大模型在知识库问答、网页搜索、客服等领域的可信赖度。但我们发现,在实际落地中,RAG 仍存在不少问题,如:文档解析结构丢失、大模型生成幻觉、复杂问题无法解答等等。
本文中,阿里云高级算法专家欧明栋分享了阿里云为什么选择 RAG 作为解决方案,以及在实际应用中如何通过文档结构化、大模型微调和 Agent 技术等手段,提升 RAG 的效果和性能。同时,他还介绍了 RAG 在电商、内容、企业知识库和教育搜题等场景中的实际应用,为同行提供了宝贵的实践参考。
12 月 13-14 日,作为全年系列大会的收官之站,2024 AICon 全球人工智能开发与应用大会将在北京举办!本次大会将继续聚焦人工智能的前沿技术、实践应用和未来趋势,比如大模型训练与推理、AI agent、RAG、多模态大模型等等...... 精彩议题正陆续上线,欢迎访问链接查看详情:https://aicon.infoq.cn/202412/beijing/
以下内容源自欧明栋在 2024 AICon 全球人工智能开发与应用大会·上海站的演讲(经 InfoQ 进行不改变原意的编辑整理):
今天想跟大家分享阿里云在过去一年多的时间里,如何利用大模型优化 RAG 的实践。
RAG 主要用在知识问答领域,前期我们考虑了三种主流的解决方案。
第一种方案是直接使用大模型回答问题。这种方法简单直接,输入一个问题,模型就会给出答案。然而,这种方法可能会遇到幻觉问题,因为模型的预训练数据中可能不包含足够的领域知识和实时信息,就会导致答案不准确。例如,我们在阿里云文档上测试 GPT-4 时,发现准确率不到 30%。
第二种方案是对大模型进行微调。这种方法可以减少幻觉问题,因为模型会集成一些领域知识。但这种方法也有其挑战,比如领域数据可能不足,或者预训练效果不佳,需要进一步的领域知识调整,这会增加成本。此外,微调后的模型需要单独部署,虽然有技术如 LoRA 可以减少成本,但总体上成本仍然较高。
第三种方案,也就是我们采用的 RAG 方法,它不改变大模型本身,而是通过检索领域知识,然后结合问题和检索到的知识,用大模型生成答案。这种方法的优点在于,它使用的是原始知识,因此幻觉问题较少。同时,由于它基于检索,可以实时更新信息,提供更多的实时数据。此外,由于它不是直接生成答案,而是基于搜索结果,所以可以提供生成答案的依据,解决了可溯源的问题。在成本方面,我们发现大模型直答和 RAG 的成本相对较低,主要成本集中在模型推理上。
在 RAG 架构中,我们的流程始于用户上传文档集合。上传后,我们首先对文档进行解析,然后进行切片处理。切片的目的是为了与后续的向量模型或索引兼容。目前,向量模型在处理较短文本时效果较好,尽管它们也能处理长文本,但在语义搜索的相似度和区分度上可能不够精确,因此需要通过检索和切片来优化。由于大模型支持的上下文长度有限,我们需要将文档切割成更小的切片,以便大模型能够进行有效总结。这一过程是离线的,最终我们会建立一个基于语义切片的索引库,通常采用向量和文本的混合索引方式。
当用户在线提出问题时,我们会对查询进行改写。查询改写主要分为两个方面:首先,在多轮对话中,我们需要考虑历史信息来进行查询改写,以形成一个语义完整的查询,然后进行搜索;其次,对于复杂的查询,我们会进行改写和拆解,以便更准确地搜索到相关信息。在改写后的查询基础上,我们会找到一些相近的文档切片,然后利用大语言模型来生成答案。这个过程确保了我们能够为用户提供准确和相关的回答。
虽然 RAG 架构能够解决大部分简单问题,但在处理复杂场景或文档时,会遇到一些挑战。
首先,幻觉问题依然存在。这可能是因为文档在切片过程中出现不完整或解析错误,导致模型在生成答案时出现幻觉。此外,即使在 RAG 场景下,大模型本身也可能产生幻觉,这种幻觉与直接生成的幻觉不同,它是基于检索结果之外的信息进行回答。
其次,拒答现象也较为常见。这主要是因为检索结果不完整或未能检索到相关内容,导致模型无法给出答案。
第三,回答不完整的问题。这可能是因为文档切片本身不完整,或者召回过程中不完整。在处理复杂问题时,如果答案较长,比如步骤类问题,模型可能会遗漏关键信息。
第四,回答内容与问题不相关。这可能是大模型的一个普遍问题,模型倾向于给出较长的答案,而这些答案虽然不是错误的,但可能与问题不相关。
最后,响应速度问题。在服务客户时,我们发现如果需要达到较好的效果,可能需要使用 72B 参数以上的模型,这会导致回答的反应速度变慢。
总结来说,为了使 RAG 架构达到较好的效果,我们需要关注四个关键点:
文档解析的准确性:文档解析必须准确无误。因为如果输入数据有误,那么输出的结果肯定也会出错。
切片的语义完整性:文档切片需要保持语义的完整性。这意味着切片后的内容应该能够代表原文档的意义,以便模型能够理解并正确处理。
信息召回的完整性:信息召回过程需要确保召回的信息是完整的。
大模型的总结推理准确率:大模型在总结和推理时的准确率必须高。
在大模型应用的优化方面,我想分享我们所做的一些工作。首先,在文档解析方面,我们进行了文档层级结构的抽取,目的是将文档结构化,这样不仅可以提高切片的效率,还能帮助大模型更好地理解文档内容。
其次,为了提高大模型回答的质量,我们对模型进行了微调。我们选择的是一个相对较小的模型,这样不仅能够保证较快的处理速度,而且在效果上也能与更大参数量的模型相媲美。
最后,当检索到的信息不完整,或者需要回答的问题比较复杂时,我们会采用 Agent 技术对问题进行拆解。通过这种方式,我们可以更有效地回答问题,确保即使在信息不完整或问题复杂的情况下,也能给出满意的答案。
在讨论系统优化时,我们提到的优化点都是系统模块的一部分。目前,这个系统由多个独立模块组成,可以自由组合以满足不同的需求。整个 RAG 系统包括以下几个关键部分:
数据层:数据层支持多种数据格式和数据源,这是系统的基础。
离线服务:在离线处理方面,我们包括了向量化文本切片和数据提取。这部分有多种可选的链路,有的效率较高,有的可能效果较好但速度较慢。
在线引擎:搜索模块是另一个重要部分,我们支持自研的大模型以及第三方开源和闭源的大型模型。
搜索组件:Query 理解非常关键,如果能够准确理解用户的查询,那么检索到正确的文档,回答的质量基本上就有 80% 的保证。我们在 Query 理解方面也采取了多种策略来处理不同的问题。
组件编排:系统可以支持阿里云的 SDK,以及一些目前非常流行的开源 SDK,如 LlamaIndex 等。
在处理文档结构化的问题时,我们的初衷是为了解决文档切片的问题。我们面临的挑战是,许多数据,如 PDF 文件,甚至是纯文本输入,很难直接通过规则分析出其语义层级。这会导致在进行语义切片时,切片内的语义不完整。
我们看下图的两个例子。第一个例子是,当用户询问如何修改云盘的 UUID 时,搜索回来的结果可能是“修改云盘的 UUID 步骤如下”,但接下来的步骤可能被切到了下一个切片。这样,模型只看到了“如下”,而模型本身倾向于补充文本,因为它的预训练就是做文本补充。因此,它可能会根据它自己的知识生成答案,这样的回答通常都是错误的。第二个例子是,切片可能只包含了某个步骤的一部分,模型在回答时也只回答了这部分内容,而遗漏了剩余的步骤。
在语义层级抽取模型的开发中,我们的目标是利用大模型强大的语义理解能力来抽取文档的语义层级。大模型已经在大量文档上进行了训练,因此具备了理解文档标题、列项等不同层级的语义的能力。通过这种方式,我们希望能够提取出文档的层级结构。
这样做的好处有两个:首先,它可以使切片更加完整,避免了之前提到的切片导致的语义不完整的问题;其次,它还可以用于基于语义层级的内容摘要。许多用户的问题具有全局性,他们可能不是询问某个具体的知识点,而是询问一个更广泛的话题,如政策文件包含哪些内容。这类问题可能涉及几千字的内容,通过传统的切片方式很难完整地总结。
为了实现这一目标,我们首先收集了一些公开的数据集,这些数据集中包含了 PDF 文件的层级信息。我们收集的数据质量相对较高,并根据业务需求进行了一些数据增强。有了这些增强数据后,我们采用了两阶段的 SFT 加上 DPO 的方法来训练模型。
模型训练后准确率仍然不是非常高,无法完全准确地抽取整个语义层级,但我们在后续处理中采取了一些策略。例如,我们会通过递归的方式来处理特别长的文档,因为模型训练时不会处理特别长的上下文,长上下文的处理速度会比较慢。因此,我们需要对较长的文档进行切分,然后再进行处理。
在进行数据增强时,我们主要采取了三种方式:
层级合并:首先,我们将客户的 PDF 或 Word 数据转换成 Markdown 格式。在转换过程中,我们会根据一些规则,比如字体和字号,来识别并创建粗体标题。然而,我们发现许多客户的数据中,不同层级的标题可能使用了相同的字号,这就需要我们在数据中进行层级的合并和构造,以模拟客户的实际数据。
噪声混入:有时客户的数据中,某些并非标题的文字被错误地标记为标题。为了处理这种情况,我们也会在数据中引入一些假的标题,以增加模型的鲁棒性。
纯文本构造:对于完全由纯文本组成的客户数据,我们还需要构造一些纯文本输入,以便模型能够学习如何处理没有明确层级结构的文本。
在准备好数据后,我们采用标准的 SFT 和 DPO 方法进行模型训练。输入数据是我们初步解析出的 Markdown 格式,而输出则是标题的层级结构。在 DPO 方面,我们使用的是 Step DPO,即只关注第一步解析的结果。这是因为如果第一步解析出现错误,那么后续的解析往往也会不准确,所以我们专注于第一步解析错误的部分。
在语义层级切片的应用方面,我们采取了一种结构化的方法来处理文档。例如,如果一个文档包含段落 1、2、3、4,我们会将其切成四个独立的切片,每个切片都会附带其标题的路径。这样,每个段落不仅可以独立处理,还可以生成摘要,从而有效回答一些较长的问题。此外,整个文档的结构允许我们回溯并生成摘要,以提供更全面的答案。
随着模型能处理的上下文长度越来越长,我们面临一个问题:是否还需要进行切片?理论上可以直接将整个文档输入到大模型中,让它直接生成答案,而无需进行切片。但经过我们的测试,长文本处理仍存在一些问题。首先,处理长文本会增加计算复杂度,导致耗时和成本增加。这是因为输入上下文的长度增加,计算复杂度呈平方增长,从而显著增加了处理时间。其次,更重要的是信息丢失的问题。我们测试了 GPT-4 128K 版本,发现当输入长度达到 30 多千字时,模型开始遗漏信息,导致回答不完整。文档中的噪声数据也使得模型难以精确提取信息。我们目前的策略是适当增加切片的长度,而不是完全放弃切片。我们仍在探索更好的结合长文本处理和切片的方法,以提高效率和准确性。
我们目前的工作重点是大模型的微调以及 Agent 的探索。我们的主要出发点是提高回答的质量。首先,我们关注幻觉问题。在 RAG 环境下,即使是 GPT-4 这样的大模型,也存在大约 7% 的幻觉率。对于更小的模型,如 14B 或 7B,幻觉率通常在 20% 以上。幻觉的一个例子是,当用户询问如何清除过期的二级分区时,模型可能会混淆相关但不正确的回答。另一个例子是回答不完整,比如在解释 RDS 创建数据库的方法时,模型可能只回答了部分版本,遗漏了其他版本。这些问题可以通过意图澄清来改善,但即便如此,模型在细节上仍可能遗漏信息。
为了解决这些问题,我们主要通过微调模型来提高回答质量。我们认为幻觉的来源主要是模型的逻辑推理模式与人的推理模式没有完全对齐,而不是知识缺乏。
微调过程中最大的挑战是如何评估和生成数据。为此,我们建立了一个 RAG 回答的评估链路,类似于后来发布的 RAGAS。这个评估链路主要基于检索结果、问题和回答这三元组来评估效果。我们的评估标准包括三个方面:
幻觉:分为编造(回答内容不在检索结果中)和混淆(回答包含了相关但不能回答问题的内容)。
完整性:回答是否包含了所有关键点。
相关性:回答内容是否与问题相关。
目前,我们主要通过大模型自身进行评估。工作流程大致是:首先让大模型进行一次评估,然后进行反思(reflection),接着自我完善(self-refine),并迭代这个过程。最终的效果显示,仅使用大模型的准确率可以达到 95% 左右,这比单纯人工的效果还要好。如果基于大模型的评估结果再由人工进行修正,效果会更好。如果以人工修正的结果为 100%,那么大模型的效果也能接近这个水平。
在大模型微调的过程中,我们遵循了一个比较标准的链路。以下是我们微调过程的详细步骤:
数据来源:我们首先收集了一些公开的数据集,同时,我们也根据文档合成了一些新的问题,以生成自己的数据集。
数据构造:我们特别关注拒答的数据。我们发现大模型倾向于强行回答一些问题,这往往会导致幻觉的产生。我们还扩展了数据集的领域多样性,包括多人对话的场景。
指令构造:在指令方面,我们主要关注控制幻觉的发生。同时,我们也关注引用溯源的问题。目前,大模型在引用溯源方面的表现并不完整,有时不会生成引用溯源。
样本筛选:我们关注副文本的审核风格生成,制定了一些规则,并使用模型评测来筛选样本。
模型训练:我们使用 SFT 和 DPO 的经典方法来训练模型。
我们最近在千问 1.5 上进行了一些实验,得到了一些令人鼓舞的结果。我们使用了基于 Qwen1.5-14B 的模型,并对其进行了 SFT 和 DPO 的处理。从实验结果来看,在 RAG 的应用场景中,经过微调的 14B 模型在回答问题方面的表现几乎可以与 72B 的模型相媲美。此外,我们还观察到,经过 SFT 和 DPO 处理的模型在幻觉率方面有显著的降低。
模型总结的效果很大程度上取决于输入数据的完整性。在我们的客户场景中,很多问题都是相当复杂的,需要通过多步推理和多篇文档的信息聚合才能得出答案。例如这个问题:“西班牙获得欧洲杯次数最多的球员是谁?”直接搜索可能只能找到“西班牙获得了哪几届欧洲杯”的信息,但要找到获得次数最多的球员则需要更深入的分析和聚合多篇文档中的数据。这种情况下,模型可能无法直接给出答案。另一个例子:“黎曼的生肖是什么?”搜索结果可能只包含关于黎曼的一些基本信息,如生日,但要确定他的生肖则需要额外的计算和推理。
Agentic RAG
目前,我们在模型探索方面还处于相对初级的阶段。我们尝试在搜索服务后接入了一个 规划 Agent,这个 Agent 的作用是先评估当前的搜索结果是否足够回答问题。如果搜索结果足够,Agent 会直接进行总结。如果结果不足,Agent 会再次执行搜索,然后再次尝试总结。例如,要回答“西班牙获得欧洲杯次数最多的球员是谁”的问题,Agent 会分两步进行搜索:
第一步,Agent 会搜索出西班牙获得欧洲杯的年份。
第二步,它会找到每个年份下欧洲杯获奖的球员名单。
通过这两步搜索,Agent 可以总结出获得欧洲杯次数最多的球员,例如伊涅斯塔、哈维、卡西利亚斯等,他们都是获得了两次欧洲杯的球员。
对于“黎曼的生肖是什么”的问题,Agent 也会采取类似的两步搜索策略:
第一步,Agent 会搜索出黎曼的出生日期。
第二步,它会搜索出黎曼出生年份对应的生肖。
最初我们尝试直接基于 REAct 或者 Function Call 将问题输入模型,但不提供任何搜索结果作为参考。这种方法导致模型倾向于将问题拆解得过于细致,从而增加了搜索轮数,有时候甚至会导致回答方向出现偏差。从效率角度来看,我们观察到在测试集中,这种策略平均需要 1.7 次搜索。
为了改进这一点,我们尝试了一个更简单的方法:首先用原始问题执行一次搜索,然后再决定是否需要进一步搜索。通过添加这第一步的直接搜索,我们发现搜索次数从 1.7 次降低到了 1.2 次,这显著提高了回答的效率。效果也有所提升,主要是因为减少了搜索轮次,从而降低了出现错误的概率。我们发现,当搜索轮次较多时,模型在推理过程中更容易出错。
目前我们也面临一些挑战。首先,处理 时延高,因为模型需要进行推理,如果需要多步搜索,还要进行多步总结,这会增加总体耗时。其次,成本高,因为涉及到多次调用大模型。最大的问题是 推理本身的准确率不高。我们注意到,有时在进行几步推理之后,模型可能甚至忘记了最初的问题。
我们应用的场景主要分为四类:电商场景、内容场景、企业知识库和教育搜题。
电商场景:在电商领域,我们主要处理售前和售后服务等相关问题。
内容场景:在内容领域,我们主要进行搜索结果的总结。
企业知识库:在企业内部,我们处理的是问题的咨询。
教育搜题:在教育领域,我们进行题目搜索并总结答案。
RAG 客户场景都是基于我们的 AI 搜索开发平台构建的,该平台包括内容解析、内容切分、向量表示等模块,可以单独或组合使用。以营养咨询为例,我们的处理流程如下:如果客户上传了一个 PDF 文件,我们会调用 PDF 解析 API,并使用结构化模型抽取 PDF 的语义层级结构,将其转换成 Markdown 文档。然后,我们会对文档进行切片。切片后,我们会为文档生成 embedding,包括文本的和混合索引。完成以上步骤后,我们就已经构建好了离线检索的结构。
在线服务方面,当用户提出一个问题,比如“如何搭配食物才能满足高温作业的需求”,我们的系统会这样处理:系统会先检索到一些相关的切片。然后,系统会做一个初步的总结。模型会进一步推理,检查结果中是否缺少信息。如果分析结果显示缺少某些具体信息,比如具体的蔬菜水果名单,模型会产生一个新的问题进行搜索。收到相关数据后,模型会再次进行总结。如果 planner 认为问题已经可以完整回答,最后会生成一个完整的回答。
欧明栋,阿里云高级算法专家。多年搜索推荐算法实践经验,曾负责闲鱼推荐、阿里云智能搜索推荐算法;目前负责 AI 搜索 RAG 相关算法研发,产品上线已一年多,具体算法方向包括 RAG 场景下大模型优化、Agent 搭建及文档理解等;发表过多篇人工智能相关论文,入选 AI2000 最具影响力学者提名。
Flutter 被分叉!团队缩水至 50 人,bug 堆积如山,前谷歌员工出手找出路
2024 年收官之作:12 月 13 日 -14 日,AICon 全球人工智能开发与应用大会将在北京举办。从 RAG、Agent、多模态模型、AI Native 开发、具身智能,到 AI 智驾、性能优化与资源统筹等大热的 AI 大模型话题,60+ 资深专家共聚一堂,深度剖析相关落地实践案例,共话前沿技术趋势。大会火热报名中,详情可联系票务经理 13269078023 咨询。