






















Rag系统它通过结合信息检索和自然语言生成技术,显著提高了信息处理的效率和准确性。然而,随着应用的深入,Rag系统的局限性也逐渐显现。本文将深入探讨Rag系统的发展、存在的问题及其优化方案,希望能为相关领域的研究者和开发者提供参考和启示。

前段时间,风叔发表了《聊聊炙手可热的Rag:产生原因、基本原理与实施路径》,有读者反馈希望多讲讲Rag系统现存的问题和优化方案,今天风叔就来谈谈这个话题。
从2020年Meta AI 的研究人员提出检索增强生成(RAG)方法,Rag系统也在不断地优化和迭代。
总结来说,Rag的发展经历了三个发展阶段,从最初的Naive Rag(朴素Rag),再到Advance Rag(高级Rag),最后再演变为Modular Rag(模块化Rag)。
下面,风叔详细介绍下这三个阶段的Rag系统都遇到了哪些问题,以及这些问题是如何被解决的。
RAG发展初期,其核心框架由索引、检索和生成构成,这种范式被称作朴素RAG。朴素Rag的原理非常简单,包括以下三个步骤。

朴素RAG是一个非常简单的框架,也很易于理解,但是在实际应用中自然而然地出现了以下挑战。
要解决上面的问题,需要在检索前和检索后做一些优化,于是就产生了高级RAG。
高级RAG相比于朴素RAG,增加了检索前、检索中和检索后的优化策略,用于解决索引、检索和生成的问题。

下图是更直观的对比,可以看到相比朴素Rag,高级Rag主要优化了黑框中的三个环节。

检索前主要有两个事项,建立索引和处理查询。
1)建立索引(Indexing)
在建立索引的环节,为了解决核心关键词被无效信息淹没以及内容分割受语义影响较大的问题,高级Rag引入了索引降噪、知识切分和元数据。
2)处理查询(Query)
在处理查询的环节,为了解决用户真实意图识别不准确的问题,高级Rag引入了Query改写的方法,但是对语义相似度的计算,仍然沿用了Embedding模型向量计算的方法。
Query改写:Query改写就是把用户原始的问题转换成适合知识库检索的问题,从而提高检索的精准程度。Query改写的方法主要有Query分解和Query扩展,Query分解是将一个问题分解为多个子问题,Query扩展则是将一个问题转化成多种不同的问法。
检索阶段的目标是召回知识库中最相关知识,在朴素Rag中,检索完全基于向量搜索,通过计算查询与索引数据之间的语义相似性,从而获取最相关的内容块,但是存在查询Query和文档块之间的语义相似度并非总是高度一致的问题。
嵌入模型微调:相比朴素Rag,高级Rag仍然沿用了使用Embedding模型计算相似度的方式,但是对嵌入模型做了微调,将嵌入模型定制为特定领域的上下文,特别是对于一些专业术语浓度比较高的场景。
在朴素Rag中,会将所有检索到的块直接输入到大模型,导致冗余信息过载,从而干扰大模型对关键信息的识别。在高级Rag中,针对这一问题做了相关优化。
尽管高级RAG有所改进,但是仍然与实际应用与需求之间存在差距。比如数据源的质量问题,“Garbage in Garbage out”,如果本身原始数据或文档的质量就很差,最终生成的结果也不会好。
再比如对于结构化数据的处理,随着应用场景越来越丰富,不再局限于单一的非结构化文本数据源类型,而是拓展至涵盖诸如表格之类的半结构化数据,以及像数据库、知识图谱这样的结构化数据。即便是高级Rag,也没法有效捕捉实体之间的复杂关系和层次结构,比如分析一本书的主旨,或者分析某篇长论文的概念之间的关系。
随着 RAG 技术的发展,客户的期望值和需求持续演变,应用的设置也变得更为复杂。在这样的背景下,高级Rag又进一步演变为模块化Rag。
模块化RAG并不是突然出现的,三个范式之间是继承与发展的关系,高级RAG是模块化RAG的一种特例形式,而朴素RAG则是高级RAG的一种特例。
所以,模块化Rag其实仍然是一种Advance Rag,但是模块划分更清晰,对于系统的管理也更加直观。如下图所示,模块化Rag的框架仍然和高级Rag类似,包括索引、检索前、检索中、检索后和生成,同时增加了一个编排环节,一共是六大环节。
同时,对每个环节的能力做了模块化分割,比如索引环节包括了块优化(chunk optimization)、结构组织(structural organization),比如预检索环节包括了查询转化(Query Transformation)、查询扩展(Query Expansion)、查询构建(Query Construction)等等。

模块化Rag基本上涵盖了Rag系统的方方面面,下面风叔就围绕模块化Rag的每个模块,详细阐述每个模块遇到的问题和解决方案。
在早期的Rag中,索引环节仍然面临着三个主要难题。首先,内容表述不完整,内容块的语义信息受分割方式影响,致使在较长的语境中,重要信息被丢失或被掩盖。
其次,块相似性搜索不准确,随着数据量增多,检索中的噪声增大,导致频繁与错误数据匹配,使得检索系统脆弱且不可靠。
最后,参考轨迹不明晰,检索到的内容块可能来自任何文档,没有引用痕迹,可能出现来自多个不同文档的块,尽管语义相似,但包含的却是完全不同主题的内容。
针对索引环节的问题,模块化Rag将其区分成了两个领域,块优化和结构组织,从而从两个不同的方向来解决索引的问题。
1)块优化(chunk optimizaition)
在内容分块的时候,分块大小对索引结果会有很大的影响。较大的块能捕捉更多的上下文,但也会产生更多噪声,需要更长的处理时间和更高的成本;而较小的块噪声更小,但可能无法完整传达必要的上下文。
块优化仍然维持了原有的内容分块的处理方式,主要有三种优化方案。
2) 结构组织
结构组织顾名思义,即改变索引的组织结构,从而提升RAG 系统对于相关数据的检索和处理的速度和准确性。主要有以下几种结构组织优化方式。
在朴素Rag中,往往直接使用原始query进行检索,可能会存在三个问题。
第一,原始query的措辞不当,尤其是涉及到很多专业词汇时,query可能存在概念使用错误的问题;
第二,往往知识库内的数据无法直接回答,需要组合知识才能找到答案;
第三,当query涉及比较多的细节时,由于检索效率有限,大模型往往无法进行高质量的回答。
在高级Rag中,提出了Query改写的解决思路,模块化Rag对于这一思路做了细化,主要从三个方向进行优化,查询扩展、查询转换和查询构建。
1)查询扩展(Query Expansion)
查询扩展就是将单个查询拓展为多个查询,这样可以丰富查询内容,为潜在的Query内容缺失提供更多上下文,从而确保生成答案的最佳相关性。
多查询(Multi-Query):借助提示工程通过大型语言模型来扩展查询,将原始Query扩展成多个相似的Query,然后并行执行。
目前有一种叫Rag-fusion的有效方案,首先对用户的原始query进行扩充,即使用 LLM 模型对用户的初始查询,进行改写生成多个查询;然后对每个生成的查询进行基于向量的搜索,形成多路搜索召回;接着应用倒数排名融合算法,根据文档在多个查询中的相关性重新排列文档,生成最终输出。

子查询:通过分解和规划复杂问题,将原始Query分解成为多个子问题。比如原始Query的问题是“请详细且全面的介绍Rag“,这个问题就可以拆解为几个子问题,”Rag的概念是什么?“,”为什么会产生Rag?“,”Rag的原理是怎样的?“,”Rag有哪些使用场景“等等。
2) 查询转换(Query Transformation)
查询转换是将用户的原始查询转换成一种新的查询内容后,再进行检索和生成,相比前面讲的查询扩展,并没有增加查询的数量。
3) 查询构建(Query Construction)
和查询扩展与查询转化不一样,查询构建主要是为了将自然语言的Query,转化为某种特定机器或软件能理解的语言。因为随着大模型在各行各业的渗透,除文本数据外,诸如表格和图形数据等越来越多的结构化数据正被融入 RAG 系统。
比如在一些ChatBI的场景下,就需要将用户的Query内容,转化为SQL语句,进行数据库查询,这就是Text-to-SQL。
再比如工业设计场景下,可能需要将用户的Query转化为设计指令,或者设备控制指令,这就是Text-to-Cypher。
在检索环节,模块化Rag主要设置了两个优化方向,检索器选择和检索器微调。
1) 检索器选择(RetriverSelection)
检索器本质上是一种计算Query和内容块相似性的算子,这种算子最原始的形态就是基于Embedding模型的向量相似性,但可以通过转化算子的方式进行优化。
可以构建这两种检索器,然后通过编排模块,在特定Query的时候采用最合适的检索器
2)检索器微调(RetriverFine-tune)
在上下文可能与预训练语料库有差异的情况下,尤其是在存在大量专有术语的高度专业化领域,需要对检索器进行微调。
在朴素Rag中,系统会将所有检索到的块直接输入到 LLM生成回答,导致出现中间内容丢失、噪声占比过高、上下文长度限制等问题。
高级Rag针对这个问题,提出了提示压缩和重新排序的解决思路,模块化Rag也同样继承了这类方法,并将其分成了三个模块,重排序、压缩和选择。
1)重排序(Rerank)
对于检索到的内容块,使用专门的排序模型,重新计算上下文的相关性得分。这些排序模型会考虑更多的特征,如查询意图、词汇的多重语义、用户的历史行为和上下文信息等,比如Cohere模型。
2) 压缩(Compression)
对于检索到的内容块,不要直接输入大模型,而是先删除无关内容并突出重要上下文,从而减少整体提示长度,降低冗余信息对大模型的干扰。
3) 选择(Selection)
与压缩文档内容不同,选择是直接移除无关的文档块。通过识别并剔除输入上下文中的冗余内容,可以精炼输入,从而提升语言模型的推理效率。有一种有效的选择方法叫做LLM-Critique,是在生成最终答案前,通过LLM批评机制,过滤掉相关性不高的文档。
在朴素Rag和高级Rag的生成环节,可能会出现以下问题:第一,当系统忽略了以特定格式(例如表格或列表)提取信息的指令时,输出可能会出现格式错误;第二,输出错误或者输出不完整,比如对于一些比较类问题的处理往往不尽人意,以及可能出现的幻觉问题;第三,可能会输出一些不太符合人类/社会偏好,政治不正确的回答。
对于这类问题,模块化Rag将解决思路分成了两个方向,生成器微调和验证。
1) 生成器微调(Generator Fine-tune)
2) 验证(Verification)
编排模块,是模块化Rag和高级Rag相比最大的不同。因为有了编排模块,模块化Rag就可以在关键节点进行决策,并依据先前的结果动态选择后续步骤,实现处理流程的自适应。比如对于特定的Query,应该选择哪个知识库、选择哪种检索器、适配器和生成器等等。
按照功能的不同,模块化Rag将编排环节分成了路由、调度和融合三个模块。
1)路由(Routing)
路由的作用,是为每个Query选择最合适的处理管道,以及依据来自模型的输入或补充的元数据,来确定将启用哪些模块。比如在索引环节引入多重索引技术后,就需要使用多级路由机制,根据Query引导至最合适的父级索引。
2)调度(Scheduling)
调度模块在模块化 RAG 中发挥着关键作用,尤其是在需要相对复杂规划和反思的场景下,何时需要递归、何时需要迭代、何时需要反馈、何时停止循环,都是由调度模块来控制的。
3)融合(Fusion)
随着RAG进程的发展,已经超越了单一的线性流程,经常需要扩大检索范围或通过探索多条流水线来增加多样性。融合模块的作用不仅仅是合并答案,还要确保最终输出内容丰富,并且能够反映出问题的多维度特性。
LLM融合:先对每个分支的答案进行总结,提取关键信息,然后再将其输入到LLM中,以确保即使在长度受限的情况下也能保留最重要的内容。
互反排名融合:将多个检索结果的排名合并成一个统一的列表,然后用加权平均方法来提高整体的预测性能和排名精度。
本篇文章重点介绍了Rag技术的发展历程、每个阶段面临的短板和解决方案。Rag系统上手很容易,但是要做好,还是很不容易的。所有的理论知识,都不如大家在实际项目中去摸索和实践。
作者:风叔,微信公众号:风叔云
本文由@风叔 原创发布于人人都是产品经理,未经作者许可,禁止转载。
题图来自Unsplash,基于CC0协议。
该文观点仅代表作者本人,人人都是产品经理平台仅提供信息存储空间服务。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。