AGI|如何构建一个RAG应用?入门新手攻略!

news2024/11/23 15:54:18

目录

 一、概述

二、过程概述

三、如何优化提问?

四、路由和高级查询

五、丰富索引结构

六、重排序上下文

七、总结


 一、概述

Retrieval Augmented Generation RAG 检索增强的内容生成。

从字面上来看检索只是一种手段途径,在人工智能领域中存在多种增强大语言模型输出的方式,而检索只是其中一种。不同于传统应用的检索,RAG中的检索更像是大语言模型能力的扩展,它的侧重点在于如何通过检索出来的信息,让大模型生成出更优质的内容。

为什么大语言模型的输出会需要增强呢?

现阶段大语言模型在训练时会接触到大量文本数据,这些文本数据可能包括书籍,网页,论文,新闻资讯等信息。这些数据构成了模型对现实世界的基础理解,模型信息中会特地标注训练时所使用的参数量(Billion),7B 代表着 70亿个训练参数。优质的内容和训练参数的数量级都会影响模型的能力和输出质量,但知识库的构建会基于某个时间点的数据,模型的训练也可能在之后的时间完成,这带来不可避免的滞后性和时效性。

通过检索最新的数据作为上下文提示,能在一定程度上弥补语言模型在知识更新方面的不足,可以提供更加准确的回答,但它的效果也依赖检索系统和知识库的质量。在私域场景下,大模型在理解私域文档后结合它自己知识库所产生的输出,要比传统私域文档中做检索要优质得多。

几十亿个训练参数听起来已经足够多了,LLAMA2 在训练时使用了2T大小的数据但它的上下文在4K左右,虽然训练参数和上下文随着时间的推移还在不断的增加,但对于模型应用来说还远远不够,对于整个人类世界来说还远远不够。而RAG就是为了在有限的上下文中让模型发挥更强大的能力。

二、过程概述

构建一个RAG大致能分为三个部分:

1.为私域数据建立索引(Embedding)

2.基于用户的输入,将相似度最高的内容的提取出来(向量搜索)

3.基于用户的问题,对回答的内容进行增强(提示词工程)。

下图来源于:https://scriv.ai/guides/retrieval-augmented-generation-overview

LangChain 三行代码构建一个简单的RAG示例:

fromlangchain.document_loaders importWebBaseLoader
fromlangchain.indexes importVectorstoreIndexCreator

loader = WebBaseLoader("http://www.paulgraham.com/greatwork.html")
index = VectorstoreIndexCreator().from_loaders([loader])
index.query("What should I work on?")

检索本质上是一种搜索操作,传统的搜索引擎可以根据用户的输入查找最相关的信息。在AI检索中的行为也是类似的,它由两个部分组成:

1.索引:将知识库变为可以搜索/查询的内容。

2.查询:从搜索词中提取最相关的知识。

任何搜索过程都可以用于检索,可以把检索当作一个外部扩展的工具,无论是通过Restful API 还是通过向量搜索,只要能检索出输出问题想匹配的信息,满足相关的上下文输出给大模型,那么这个检索过程就是符合要求的。

建立索引的过程也是Embedding的过程,因为模型会有上下文的限制,通常情况下建立私域知识库时会先将文档进行“切片”。切片对于RAG是一个很重要的部分,如果将一个大文档直接输入给大语言模型,根本没什么意义,这样检索出来的信息太泛化了。切的太小也会造成输出质量的下降——相关性内容会丢失。

开发者必须要考虑切成什么大小才能更接近平衡点,虽然LangChain 提供工具来简化这一过程,但不同的文档和内容不能一概而论,而是需要通过具体的场景再做权衡。索引是构建整个RAG最困难但又最重要的部分,整个索引部分可以分为两步:

1.加载:从通常存储的位置获取知识库的内容

2.分割:将知识库分割成适合嵌入搜索的片段大小的块。

"适合"这个词在软件工程中让人感觉格格不入,到底什么是适合?这句话和食谱中的“适量”有着相同的迷惑性,似乎存在各种不确定性。将用户输入的问题和一大堆的提示词结合在一起,将它们向量化后在另外一堆向量数据中进行匹配,最终输入给一个黑盒并企图它能输出优质内容,这更像是《计算机程序的构造和解释》前言中描述的魔法,因为它真的能运行。

三、如何优化提问?

怎样提一个好问题?从主观上来讲,如果别人问我们一个问题,比较理想的情况是:回答者只要稍加思索便能准确捕捉到其中的关键点,从而轻松回答出对方想要的答案。

上述描述肯定不是一个好的回答,因为太理想化,现实生活中因为问题质量差而导致得不到回答的例子比比皆是,那么又怎么能奢求大模型输出高质量的回答呢?提一个好的问题是有门槛的,否则互联网也不会存在关于“如何提一个好问题”的文章,市面上也不会存在指导人们如何提问的书。

反过来,通过现实生活的思考优化对大模型的提问似乎也是可行的。我们更希望问题中提供充足的相关背景,足够简单,具体的词句,目的明确。

但事实上应用无法决定用户输入什么,输入可以是一个简短的单词,它不存在上下文,或过于概括,也可能不存在目的性。在这种情况下,有一种思路是:将一个问题生成多个问题,以此来丰富整个问题。

输入:向量

生成:解释'向量'这个词?
生成:'向量'这一概念存在于哪些领域?
生成:请解释计算机领域中的向量
生成:请解释物理学中的向量
生成:请解释数学中的向量

...

在私域场景下,将一个问题生成多个问题的方式称为Multi Query,在这种情况下不同的问题自然会生成各自相关的检索,也可能在同一份文档中得到相同的块。在Multi Query中可以做的相对简单一点,直接去重就好了。

RAG-Fusion中会对检索后的信息进行排序,这背后的意义在于:文档块在多次被检索后出现的频率可以用作被分析的指标,就像传统应用中的热点缓存,通过分析某些重合的文档片段相似度来进行一个统一的排序,提高多次命中的热点文档片段在上下文中的排序。

将问题具象

将问题具象化很符合人类的思考方式,现实生活中将一个大的问题拆分成多个子问题,小的问题更容易回答,只要回答这些小的问题,大的问题也迎刃而解。同时这些小的问题也存在一定的关联性,更像是一个逐步递进的过程:

通过提示词将一个抽象的问题拆分成具象化的子问题,并要求这些问题依次回答,然后将答案作为检索文档的一部分,为下一个问题提供信息依据。

输入:如何写作?

生成:写作的基本概念是什么?
答案:写作是使用文字来表达思想、情感和信息的一种方式。

生成:写作有哪些不同的类型和风格?
答案:写作类型包括但不限于小说、散文、诗歌、剧本、报告、学术论文等。风格则根据作者的个人特点和写作目的而有所不同。

生成:如何确定写作的主题或论点?
答案:确定主题或论点通常基于个人兴趣、专业领域、社会热点或读者需求。

...

答案:写作是一个复杂的过程,但可以分解为几个关键步骤来逐一掌握。以下是写作的基本指南:
1.确定写作目的:首先明确你写作的目的是什么,是为了传达信息、娱乐读者、还是表达个人观点。
2.选择主题:根据你的写作目的,选择一个你感兴趣且具有一定知识基础的主题。
3.进行研究:如果需要,进行必要的研究以收集信息和数据,确保你的内容准确无误。
4.构思大纲:创建一个大纲,概述你的文章结构,包括引言、主体段落和结论。
5.撰写初稿:根据大纲开始写作,不必担心初稿的完美,关键是将想法转化为文字。

可预见的是:如果一个问题本身就很具体,如果再进行子任务的拆分,那么不可避免的到一些无意义的信息,这样不仅不会提高输出的质量,反而会下降。这也意味着,这种处理方式只适合太过概括或抽象的问题。如果太抽象的问题可以将它们具体化,那么具体的问题能不能抽象化呢?

将问题抽象化可以拔高视角,再与原问题进行检索,以得到更全面的信息。

HyDE(Hypothetical Document Embeddings) 提供另外一种思路:如果用户输入的问题过于简短,那么可以基于LLM的能力生成一个假设性文档,再对这个文档进行检索。这也是一种将问题抽象化的方式,但显而易见的是:对于现阶段AI应用来说它的效果可能并不好——如今AI应用都在极力降低LLM的幻觉,这种生成假设性文档的内容方式显然会加剧幻觉的不可控。当然,这种思路至少看起来会让问题产生更多的创造性。

上述是从应用的角度在“如何提问”这个维度进行分析,从用户的角度有一个小技巧也可以提高输出质量,即:用多种不同的语言提问,会得到完全不一样的答案。LLM 在训练时的预料质量和数据量都会影响输出的质量,不同语言的语言,语法也不一样,这点会很直观地反映到输出内容中。

四、路由和高级查询

优化问题最简单方式就是增加问题的覆盖面,将一个问题变成多个问题,意图得到更多的信息并加以分析。但私域文档能否提供足够的信息满足这些问题?或者如何找到契合的文档?

路由(Routing)将这些衍生出来的问题通过分发,将不同的问题映射到契合度更高的模版中,在不同场景使用不同的处理方式。

Logincal

当一个问题产生后,需要思考的是这个问题使用什么处理方式才是最优解?是传统的SQL查询?是图查询?还是进行向量索引?

一个常见的场景是用户输入一个指向性十分具体的问题,比如查询某年月日发生的事件的内容,这种情况下不需要任何生成的“创新”,使用传统检索的方式可能会更好,但如果依然使用向量检索,在向量数据库中本身就存有大量关联性的数据,在这种关联数据过于紧密的情况下反而会分散LLM的注意力,导致输出结果并不理想。

路由的作用就是在不同情况下使用不同的检索数据,但路由不是通过编程去实现的,在AI应用的构建中路由是通过LLM的相关能力完成的,这点虽然和传统的网络路由有相近的部分,但它的构建有着本质的区别。

传统应用在并发量较大时会将数据库分表分库,在构建AI应用时也可以沿用这样的思路,当私域文档过于庞杂后,通过多个向量数据库存放不同领域的文档,再通过路由分流以适用于各个场景。

Semantic routing

不是每个私域都存在大量文档,在某些轻量级的场景下使用多个向量数据库未免太过奢侈。模版也可以做语义化或近似度的匹配,Semantic routing的思路是将路由分到不同的提示词模版,在此之前直接将问题和提示词模版做向量化,当两者结合后在向量数据库中直接做近似度匹配。

使用向量数据库的原因是私域文档或文档内容信息太多,所以才需要使用向量索引提升检索效率,向量存储做非结构化很好,但是在AI领域中依然没有"银弹"。使用自然语言查询关系性数据库,或图数据库也是很常见的需求场景。

五、丰富索引结构

在过程概述这一小节中提到切片对于RAG是一个很重要的部分,将一个文档切分成若干个片段,比较简单的方式可以基于换行或段落来进行切片。如果这个文档中包含代码的片段(代码中的换行较多),那么切分出来的结果可能太过散乱,LLM并不能有效对这些信息加以分析。如果切得太大会导致上下文长度过长,切片中的噪音也会影响LLM的幻觉。

如果存在很多文档,在切片前可以使用一些特定函数将这些文档先进行聚合,合并成一个聚合文档,其中的特点是将整个过程聚合的文档都存入向量数据库中,在这个过程中可以形成一个阶梯状的多层级结构。这种方式的好处是,无论回溯还是检索在不同层面都能找到对应的检索点。

在[优化提问]中,将一个问题变成多个问题为的是丰富上下文的信息,将多个文档聚合的每个阶段都保留下来,也是为了有更好的召回率,而且细化了每个节点,增加了命中率。

文档中不仅仅只包含文本,也有可能包含大量的图片,图表等信息。这种情况下仅仅依靠切分文本信息是不够的,LangChain建议是使用unstructured框架将其中的复杂内容单独提取出来,然后通过LLM分别将它变为文本的摘要,最后再将这些信息分别向量化于原文档一同进行存储。在检索时根据源文件和检索信息相似度拟合,会有更好的召回率。

从技术理论上思考似乎潜力很大,在实际应用场景下会更复杂且多变,对于某些特定领域,使用通用的向量化可能也不太适用。在某些场景下建议使用专有的向量化模型进行enbeddings,比如ColBERT。

现有的开源大模型训练趋势是生产出通用能力的模型,这更像是一个基础的操作系统,AI应用在LLM的基础上扩展某一领域的能力,这些方式会有诸多限制,比如受限于上下文,受限于模型的能力,在复杂场景下虽然理论思路层出不穷,但构建AI应用时会受到很多挑战。

比较理想化的情况是:让各个领域训练专有模型,在此基础上构建AI应用会相对容易,也更容易发挥出模型的能力。但反过来思考,可能某些领域受限于高昂的算力和成本走向弱势化,最终趋同单一化。

六、重排序上下文

从[优化提问]开始,生成的问题本身可能就是经过某种关联关系衍生的,这个生成的过程本身就包含一定权重。对文档切片时,文档内容本身也是存在关联的,一般都是从简到繁。经过这些观察很容易想到,如果文档中的某一部分命中率较高,是不是能提高它的权重,让LLM更好的输出文档优质的内容?

但从排序来看通过权重来控制索引的排列顺序,这点类似于搜索引擎。但不同于权重算法来决定顺序,在RAG中重新排序是计算问题和文档中间的相关性,按照从高到低进行排序。因为LLM上下文的限制,需要对输入窗口TopK值进行调整。即使上下文可能很大,但过多的信息依然会分散LLM的注意力,毕竟可能引入了过多的低相关性的信息。

七、总结

本文简单概述RAG以及构建过程,讨论了如何优化提问,路由,索引切片和重新排序这几种方式提高输出质量。

RAG是一种简单而又强大的技术,可以仅靠三行代码构建出一个简易应用,相比Agent对LLM能力要求也较低,又可以显著提升在特定领域的应用能力。随着技术的爆发性进步,层出不穷优化RAG的思路在努力消除大语言模型带来的幻觉,提供更准确,更相关的信息,从而生成更高质量的内容。

作者:王凯| 后端开发工程师

学习资料:

1、从零开始学习RAG

2、How do domain-specific chatbots work? An Overview of Retrieval Augmented Generation (RAG)

3、https://rolen.wiki/talk-to-a-successful-american-with-seven-kids

4、http://www.catb.org/~esr/faqs/smart-questions.html

5、https://medium.com/@narenderbeniwal1234/multi-vector-retriever-for-rag-on-tables-text-and-images-775815fcb777

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

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

相关文章

【解决】虚拟机VMTool安装程序无法继续,Microsoft Runtime DLL安装程序未能完成安装

这个问题的原因是系统安装服务没有开启 打开任务管理器-服务-打开服务 找到windows installer 服务,开启即可

leetcode-85. 最大矩形

题目描述 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。 示例 1: 输入:matrix [["1","0","1","0","0"],["1&…

【Cursor教程】探索Cursor颠覆编程体验的创新工具!教程+示例+快捷键

文章目录 Cursor的全新定义Cursor的灵活订阅模式使用Cursor轻松创建支付页面Cursor的快捷键使用指南Cursor的未来展望Cursor的实际应用案例案例一:快速原型开发示例 案例二:教育培训示例 案例三:企业内部工具开发示例 更多的选择结语 在当今技…

turtlebot3使用

roslaunch turtlebot3_gazebo turtlebot3_house.launch roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch roslaunch turtlebot3_navigation turtlebot3_navigation.launch map_file:/home/hou/maps/housemap/map.yaml 以下为melodic版本 其他版本的ros命令有区别 …

SQL优化 where谓词条件OR优化

1.测试表,及测试语句where条件中OR对应两个字段选择度很高 create table t618 as select * from dba_objects; select object_name from t618 where (object_id12043 or DATA_OBJECT_ID12043) and STATUSVALID; 2.没有索引情况下,全表扫描逻辑读…

vue项目中使用drive.js元素未定位成功

在使用drive.js时,button我设了一个id 但是在使用时却定位失败 只要在mounted设置setTimeout即可

算法-依据先序遍历和中序遍历构建二叉树

简单的二叉树遍历算法, 为了通过给定的先序遍历(preorder)和中序遍历(inorder)数组构造二叉树,我们需要理解这两种遍历方式的特点: 先序遍历(Preorder):首先…

基于SpringBoot+Vue+MySQL的药品信息管理系统

系统展示 管理员界面 医生界面 员工界面 系统背景 随着医疗技术的不断提升,药品在治疗疾病中扮演着越来越重要的角色。传统的药品管理方式以人工方式为主,但人工管理难以满足现代社会快速发展的需求。因此,需要一种更加高效、便捷的信息化管理…

作为一个直播运营,需要关注哪些数据指标?

在直播电商这一高度竞争且日新月异的行业中,作为直播运营的专业人士,若未能充分利用先进工具并紧密关注一系列核心数据指标,将难以推动直播间的持续成长与突破,且在达到一定规模后极易陷入停滞不前的困境。 本人在直播带货领域深耕…

Redis数据结构和使用场景

背景 Redis提供了丰富且结构简单的数据结构类型,在开发中被大量使用,接下来就来盘点下Redis的各种常用数据结构,以及他们的内部编码实现和使用场景。 数据结构 String 字符串类型是Redis最基础的数据结构。首先键都是字符串类型&#xff0c…

Bootstrap 5 练习 - 显示工具提示

文章目录 引言准备工作创建HTML文件导入Bootstrap 5框架编写页面代码编写JavaScript脚本浏览网页注意事项结束语 引言 大家好,今天我们将一起学习如何在Bootstrap 5中创建一个简单的工具提示(Tooltip)。工具提示是一个非常实用的用户界面元素…

常见大模型架构模式

以下是几种常见的大模型架构模式: 1. 路由分发架构模式 工作原理 当用户输入一个Prompt查询时,该查询会被发送到路由转发模块。路由转发模块对输入Prompt进行分类。如果Prompt查询是可以识别的,那么它会被路由到小模型进行处理。小模型通常具…

【SQL】收入更高的员工

目录 语法 需求 示例 分析 代码 语法 FROM Employee a, Employee b 两个表之间笛卡尔积(Cartesian product)的形式,用了逗号分隔的连接(comma-separated join),这是早期SQL语法中用于连接表的一种方式…

SpringWeb运行流程

文章目录 定义工作流程springWeb的配置1.导入相关依赖2.在web.xml中配置DispatcherServlet3.开启springMVC注解4.处理器类搭建 定义 SpringWeb,也叫spring MVC,是spring框架中的一个模块,基于servlet API构建的原始web框架,ssm为springspringWebmybatis…

AILabel

官方文档:https://gitee.com/JoinXin/AILabel 定义 AILabel类库是一款集打点、线段、多段线、矩形、多边形、圆圈、涂抹等多标注形式于一体,附加文本(Text)、标记(Marker)、缩略图(EagleMap&…

SpringBoot配置入门

Spring Boot 概述 Build Anything with Spring Boot:Spring Boot is the starting point for building all Spring-based applications. Spring Boot is designed to get you up and running as quickly as possible, with minimal upfront configuration of Spring…

汽车行业线上预约小程序源码系统 在线预约试驾+贷款计算器 带完整的安装代码包以及搭建部署教程

系统概述 这款汽车行业线上预约小程序旨在为用户提供一个全方位了解汽车信息、轻松预约试驾、快速计算购车贷款成本的一站式服务平台。整个系统采用现代化的设计理念和技术架构,确保用户界面友好且响应迅速。同时,针对企业端,该平台还支持后…

利用特征点采样一致性改进icp算法点云配准方法

1、index、vector 2、kdtree和kdtreeflann 3、if kdtree.radiusSearch(。。。) > 0)

系统开发基础错题解析二【软考】

目录 前言1.人机界面设计2.架构设计2.1管道过滤器体系2.2仓库风格 3.软件测试相关概念4.白盒测试用例4.14.2 5.测试分类与阶段任务划分6.软件维护类型7.软件质量保证8.软件过程改进 前言 本文专门用来记录本人在做软考中有关系统开发基础的错题,我始终认为教学相长…

电脑插上U盘不显示怎么回事?怎么解决?

平时使用电脑的时候经常会使用U盘来传输数据或是备份文件,有时候会遇到一个令头疼的问题,比如,将U盘插入电脑的USB口后,设备却显示不出来。电脑上插入U盘后却不显示会影响我们的正常工作。接下来,我们一起分析一下故障…