RAG的上限在哪里?边界在哪里?

  随着大模型的火热,RAG也重出江湖,成为AI产品中最火热的成员之一。特别是2024年到现在,越来越多的RAG产品出现在gitlib 上。

  世人皆知RAG,唯独不知RAG的能力边界。

  RAG用一句话:入门(demo跑通整个流程)像1一样容易,出神入化(能够达到生产级别的要求)真的还挺难。

  RAG相关的工作,做了一年又余。随着时间变化,愈来愈觉得,RAG需要特别多的知识才能真的把它做好。而我在不断的补这些知识,这是一条挺难的路。(我自己把它单做“蜀道难”的登山路)

  这篇文章,我想聊聊和RAG相关的技术,以及对应技术的边界。 技术也是有上限的,有些技术只能到这里。就像汽车的速度大概很难有飞机的速度(大概是这个意思)。

一、RAG 有多个方向

例如AI搜索,借助互联网搜索引擎,来做RAG。

本篇文章探讨的问题,主要是在知识库文档问答方向的RAG。

二、RAG的几条线

        简单来讲,RAG的链路大概是:文档解析-> 文档分割(chunch) -> 文档存储(BM25 和向量存储)-> 检索召回-> 模型回答。 这是一条比较简单的路线。可以做成一个demo。

        稍微复杂一点,能够提升效果的RAG的链路大概是:文档解析-> 文档分割(chunch) -> 文档存储(BM25 和向量存储)-> 检索召回 -> 粗排 -> 精排 -> 重排 -> prompt工程(PE)-> 模型回答。 这条路线,在召回层面做了优化。能够一定程度上提升RAG的效果。

        再复杂一点,还能提升效果的RAG的链路大概是:文档解析-> 文档分割(chunch) -> 文档存储(BM25 和向量存储)-> query理解 -> 意图识别 -> query rewrite -> 检索召回 -> 粗排 -> 精排 -> 重排 -> prompt工程(PE)-> 模型回答。 这是一条比较简单的路线。加了 意图和query理解后,一方面会变得更加智能,另外一方面会提升召回的效果,这都会提升RAG的效果。

        到此为止,应该是当前是市面上主流的打法了(很多开源的RAG产品中,不一定有上述的链路完整)。

三、RAG的边界问题

        随着客户的需求变多,很多时候能够感觉到RAG的无力感。甚至一些非RAG的问题,也想用RAG来解决。

        为什么会有无力感?这一年依赖,我们的RAG已经非常多的在客户的生产环境落地。客户会好不保留的骂着“这东西真难用”。我们也是在顶着这些谩骂,不断的思考,不断的优化。加入一些新的解决方案。

        我认为的单纯的RAG是什么?它应该是单纯的辅助模型的能力,帮助模型去做处理模型不知道的问题。但是RAG在实际落地的过程中,客户通常想要的RAG是远超模型的能力的。希望RAG特别聪明。

3.1 文档切分带来的边界问题

        从上边整理的链路中,在文档分割阶段,文档只是被分割成了一个小小的片段,可能片段的长度都不超过1024的长度。从数据的组织方式来看,RAG实际上更擅长的是回答文档中已有的问题,并且这个问题最好只是出现在切分后的某个片段中。这是从底层的处理逻辑,来看RAG的能力边界。底层的数据结构和数据组织方式,已经大概决定了RAG的能力上限。

        想要扩展RAG的能力,是需要在数据切分的过程中,加入更多的数据处理过程。例如数据分层,记录文档的片段是属于那个标题,记录片段的上一个片段和下一个片段,给片段生成摘要,给片段生成QA,等等

3.2  从召回方式来看待RAG的能力边界问题

        最常见也是最主流的召回方式是BM25召回,和基于向量的语义召回。这两种方式只是最简单最常见的检索召回的方式。召回的任务是,把引擎中有的内容,尽可能的拿出来。把引擎中和原始query问题最相关的内容拿出来。BM25是基于关键词的相关性匹配算法,这个算法朴实无华,非常简单(粗糙),基于词频和逆文档率来计算一个分数。而向量是基于模型,进行embedding,得到一个向量。同样把query也进行embedding的操作,最后计算两个embedding的consin的距离,这就是语义相似度。同样也是朴实无华。基于向量的召回,实际上能力上限取决于做embedding的模型的能力,而模型不是万能的,一些特定领域的知识可能并没有训练过,遇到这些知识,模型无法很好的把这些映射到语义空间中,所以最后的效果自然而然的不好。根据我们的生产经验和大量的测试,得到的数据是:BM25是和向量互补的,两者缺一不可,并没有谁比谁优秀。

        召回是有天花板的,做到90以上再提升就非常困难了。召回的能力不仅取决于召回的算法,也取决于数据的质量,如果原始文档脏乱差,召回是非常困难的。召回的天花板问题,大家应该很好理解。就像谷歌也无法做到100%的召回,很多时候,谷歌的召回的内容也可能不是我们想要的。在谷歌的召回过程中,已经加入了非常多的召回策略,非常多的额外的处理,也不过如此。所以应该看到RAG在召回阶段的能力边界。

        召回的过程中,它就是会出现,这个内容在引擎中存在,但是在实际的检索过程中,它并没有被召回。而这通常有两个原因:一是文档的内容太花哨,二是query太花哨。

        到这里,希望能够明白,此时的Bm25的召回也向量的召回,都是非常直接的召回。因为这个过程计算的是query和片段的相似度,它无法在过程中进行思考。更无法回答总结性的query,还有关联性的问题。例如:这篇文章在讲什么?拿着这个query去和片段做相似度匹配,相似度匹配算法做的再好,又能召回什么呢?在来一个例子:公司2023年和2024年相比,哪一年更赚钱?如果所给的文档片段中,确实有一个片段在说 公司2023年和2024财务问题,那有可能回答出来。假如上传的是两篇公司的财报,这个问题在文档中没有提到,那就无法回答了。

        针对上述的问题,不得不提knowledge graph。应该有新的召回方式,加入新的数据组织方式,对于计算这些关系的问题,应该构建在知识图谱中。

3.3 排序的边界问题

        这里的排序,包括粗排,精排,重排。这个过程的目标是把真正的答案放在前边。因为模型的窗口问题。我们无法把非常多的数据喂给模型。这受限于模型的自身能力(8k,32k,128k,kimi的更长的窗口)。其次是成本问题(很多时候也可能是最主要的问题),把太多的内容喂给模型,都是要花token的,token就是钱。

        排序并不总是好的。很可能会存在的问题是重要的内容在经过排序后,跑到了后边,最后丢失了。当然了这可以提升排序算法的能力。

四、聊聊RAG都需要哪些技术

        或者换个说法,哪些技术才能把RAG做的更好。以下内容只是我现在的认知里能够看到的,仅代表我自己意见。   RAG 是一个非常综合的方向,想要做好它,需要蛮多的知识。偏向算法一些。

         知识工程。整理文档的能力,解析文档的能力,知识梳理的能力,知识挖掘的能力。就像RAGFlow 的readme中所说的“rubbish in rubbish out”。文档解析是做好RAG的第一座大山,为什么这样说?据我所知,有专门做文档解析的公司,例如庖丁科技(100人+)。文档解释的重要性不言而喻,就像上述的链路中所列的那样,因为它在第一个环节,如果它的能力差,会直接影响到召回。(对于召回说,它的任务是尽可能的在有的语料中找到最相关的)如果解析的不好,丢失了内容,那么召回只能在空气中做(最终召回一个不相关的,甚至是错误的内容)。这个环节丢的内容,很难在下边的环节中找补回来。

        存储引擎,检索和召回。这里需要做过检索和召回。这里在我看来最起码应该会elasticsearch搜索引擎这个能力。这里可以做最简单的召回。但是这真的不够,还差的很多,只有这些遇到做多的问题是,内容在引擎中存在,但是没有检索到。检索层面是很难做到100%召回的,即使是google也不行。这里有必要说一下,BM25的关键词召回和基于模型的embedding的语义召回都是有必要的。两者不是谁超越谁,而是互补的!

        NLP,算法基础。想要大幅度的提升RAG的效果,召回绝对称的上是第二座大山。对于RAG来说,如果没有召回,则无法把正确的内容送给模型去回答。想要做好RAG,最好是做过搜索引擎中的算法工作。诸如:意图识别,query理解,query改写,粗排,精排。

        此外,我们的进步是需求推动的。感觉完全是由项目在推动我们去做一些工作。除了上述提到的一些技术外。针对不同的场景,我们可能还会加入非常多的召回策略。特定的召回策略,往往针对特定的问题会有奇效。

五、一些有意思且非常有用的探索

5.1 HyDE

        HyDE是靠模型生成假设性答案,然后拿着答案作为新的query,去做检索。在解决法律领域中的场景问答问题中(用户的输出是一个长尾的query,一大堆的事实性描述信息来描述一个犯罪的过程,最后问这触犯了哪些法律),HyDE解决了90%以上的badcase。

       这里写过一篇文章:Query Rewrite —— 基于大模型的query扩展改写,HyDE 生成假设性答案(论文)_大模型做query分析-CSDN博客 

5.2 query拆解CoT

       对于复杂的query问题,RAG最终很难给出一个正确的答案,或者说很难给出一个完整的答案。复杂的query,有时候是多问多跳的问题,需要一步一步的拆解,才能进行回答。在回答之前,堆问题进行CoT(思维链)拆解,然后最终的正确的答案。

       这里写过一篇文章:

Query Rewrite —— 基于大模型的query扩展改写(基于思维链),召回提升3%_如何使用大模型做 原始query扩展-CSDN博客

5.3 预先生成QA

        提前生成QA,能够解决一些特殊的query,诸如:这篇文章主要在讲什么?xxx都有哪些步骤?我们能从其中学到什么?我们可以在文档入库的时候,就根据内容生成摘要。这里只是提一个思路,至于要生成哪些QA,是有非常多的想象空间的。

        这里我的想法是,最好是能够针对全篇内容的每一句话,生成原子性的问题。

         这里写过一篇文章:

密集检索:我们应该使用什么样的检索粒度?(如何提升召回率)_基于字符串长度和基于段落的切片需要搭配检索策略才能提升召回率-CSDN博客

5.4 意图识别

        对于给定的query,实际上,应该知道这个问题,究竟该模型直接回答,还是应该去走知识库检索。至少应该过滤掉不该检索的问题。

        这里需要意图识别,但是真的做不到意图识别是100%准确的。实际上还是要需要一个校验器。究竟是模型生成的答案更好,还是走完检索生成的答案更好。

        这里实际上不妨先用模型生成一个答案,这个答案一起放在召回的数据中,参与rerank。

5.5 知识图谱

        知识图谱对RAG来说特别重要。特别是像最近微软开源的Graph RAG ,两天积累了3000+的star。我其实很早之前大概四月份,就关注到了这个。起初他们只是出了论文。源码开源的晚上,我就看了。我关注的是prompt是怎么写的。其他我都不关注。我知道graph能够解决哪些问题,更知道它绝对不会像官方吹的那样,能够比传统的RAG提升那么多。 但是garph确实能够和传统的RAG互补,应该说弥补传统RAG的一些缺陷。知识图谱最主要的解决的就是有复杂关联的知识所对应的问题。这是单个片段无法正确回答的。年初的时候,还探索过,如何解决此类问题。

        我还关注了蚂蚁开源的DB-GPT。我觉得它的框架非常好,就是bug太多了,剩下的交给时间就好了。它里边也支持graph,但是我看了它的用来构建图的prompt,实在是太简陋了。整体给我的感觉就是,从外边看,DB-GPT就是一个豪华大别墅,进去看看,纯毛坯房,指不定哪里还漏雨。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/45521.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UDP协议介绍和作用

什么是UDP? UDP是User Datagram Protocol的简称,中文名是用户数据报协议,是OSI参考模型中的传输层协议,它是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。 UDP的正式规范是IETF RFC768。UDP在IP报文的协议号是…

手撸俄罗斯方块(四)——渲染与交互

手撸俄罗斯方块(四)——渲染与交互 如何渲染游戏界面 我们知道,当我们看到页面先呈现图像时,实际上看到的是一张图片,多张图片按照一定的刷新频率进行切换,则变成了动态的视频。当刷新频率超过24Hz时&…

Spring设计模式

Spring框架在设计和实现时使用了许多设计模式,这些设计模式帮助Spring提供了灵活、可扩展和松耦合的架构。以下是Spring中一些常见的设计模式: 1. 单例模式(Singleton Pattern): - Spring的默认作用域是singleton,…

DWG文件发布至IIS后无法下载和预览解决办法

问题描述 DWG文件发布至IIS后无法下载和预览 原因分析: iis里面需要添加扩展 解决方案: 在服务器端IS属性的HTTP头下的MIME内容中添加扩展名“.dwg” MIME类型填入application/acad

「AIGC」TDSQL技术详解

创建一个完整的TDSQL实例涉及到多个步骤,包括数据库的创建、配置、连接以及基本的数据库操作。请注意,以下示例代码是模拟操作,实际使用时需要根据TDSQL的具体环境和要求进行调整。 步骤1: 创建TDSQL实例 在TDSQL的官网上,进入产品控制台,选择数据库服务器所在的地域,以…

29.PLL(锁相环)-IP核的调用

(1)PLL IP核的简介: Phase Locked Loop,即锁相环,是最常用的IP核之一,其性能强大,可以对输入到FPGA的时钟信号进行任意分频、倍频、相位调整、占空比调整,从而输出一个期望时钟。锁相…

JVM学习(day1)

JVM 运行时数据区 线程共享:方法区、堆 线程独享(与个体“同生共死”):虚拟机栈、本地方法栈、程序计数器 程序计数器 作用:记录下次要执行的代码行的行号 特点:为一个没有OOM(内存溢出&a…

C语言:指针详解(4)

作者本人由于大一下学期事情繁多,大部分时间都在备赛,没有时间进行博客撰写,如今已经到了暑假时间,作者将抓紧每一天的时间进行编程语言的学习,由于目前作者已经进行到了C的学习,C语言阶段的学习与初阶数据…

Tensorflow入门实战 T08-Vgg16网络进行猫狗识别

目录 1、前言 2、代码 3、运行结果 4、反思 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 | 接辅导、项目定制 1、前言 本周学习内容为,采用自己设置的vgg-16网络进行猫狗识别,并非官网提供的…

Three 平面(Plane)和 三维几何线段(Line3)

平面(Plane) 在三维空间中无限延伸的二维平面,平面方程用单位长度的法向量和常数表示为海塞法向量Hessian normal form形式。 构造器(Constructor) Plane( normal : Vector3, constant : Float ) normal - (可选参…

【公益案例展】亚运天穹——践行亚运理念,筑牢安全防线

‍ 安恒信息公益案例 本项目案例由安恒信息投递并参与数据猿与上海大数据联盟联合推出的 #榜样的力量# 《2024中国数据智能产业最具社会责任感企业》榜单/奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 杭州第19届亚运会是中国第三次举办亚洲最高规格的国际综合…

217.贪心算法:加油站(力扣)

代码解决 class Solution { public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int curtotol 0; // 当前累积油量int tatol 0; // 总的油量减去总的花费油量int start 0; // 起始加油站的索引// 遍历所有加油站for (int i 0; i &…

AJAX是什么?原生语法格式?jQuery提供分装好的AJAX有什么区别?

ajax 的全称 Asynchronous JavaScript and XML (异步 JavaScript 和 XML)。 AJAX是一种创建交互式网页应用的网页开发技术。其中最核心的依赖是浏览器提供的 XMLHttpRequest 对象&#xff0c;是这个对象使得浏览器可以发出 HTTP 请求与接收 HTTP 响应。实现了在页 面不刷新的…

try catch 解决大问题

项目开发中遇到一个棘手的bug&#xff0c;react前端项目独自运行时一切正常&#xff0c;但是把项目集成到使用wujie的大平台微前端项目中之后&#xff0c;突然有个地方无故报错&#xff0c;导致程序运行停止&#xff0c;后续的方法不再执行。报错如下&#xff1a; DOMExceptio…

5款文案生成神器,自动一键生成原创文案

文案在我们的生活中随处可见&#xff0c;好的文案内容不仅可以为企业带来销售转化&#xff0c;而且还能提升品牌的影响力&#xff0c;因此文案的重要性可想而知&#xff0c;对于文案创作者来说&#xff0c;写作好的文案不是轻松容易的事&#xff0c;但如果把这个任务交给文案生…

C++ 函数返回值是void* 使用场景

函数返回值为 void* 的使用场景主要涉及以下几个方面&#xff1a; 1、 通用指针传递 void* 是一种通用指针类型&#xff0c;可以指向任何类型的数据。在某些情况下&#xff0c;你可能需要编写一个函数&#xff0c;该函数可以返回指向不同类型数据的指针。使用 void* 可以实现…

Python中的null是什么?

在知乎上遇到一个问题&#xff0c;说&#xff1a;计算机中的「null」怎么读&#xff1f; null正确的发音是/n^l/&#xff0c;有点类似四声‘纳儿’&#xff0c;在计算机中null是一种类型&#xff0c;代表空字符&#xff0c;没有与任何一个值绑定并且存储空间也没有存储值。 P…

MySQL CONCAT函数的简单使用

CONCAT函数用于将mysql中查询多列的值拼成一列显示&#xff0c; 使用示例&#xff1a; SELECT CONCAT(attr_name,"&#xff1a;",attr_value) FROM pms_sku_sale_attr_value WHERE sku_id1; 上面SQL语句使用CONCAT函数将attr_name、attr_value两列的值拼成一列&am…

动态sql 单选变多选

实体类 添加数组存储值 private ArrayList tssjfjList; <!-- <if test"tssjfj ! null and tssjfj ! ">and tssjfj #{tssjfj}</if>--><if test"tssjfjList ! null and tssjfjList.size() > 0">AND tssjfj IN<fo…

JeecgBoot 前端 vue3 项目,配置项目多页面入口

前端 vue3配置项目多页面入口 1.项目根目录新建home.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><…