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

目录

 一、概述

二、过程概述

三、如何优化提问?

四、路由和高级查询

五、丰富索引结构

六、重排序上下文

七、总结


 一、概述

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 importVectorstoreIndexCreatorloader = 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.rhkb.cn/news/446761.html

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

相关文章

什么是CGI?

什么是CGI? ‌CGI,全称为“通用网关接口”(Common Gateway Interface),是一种用于Web服务器与应用程序之间通信的标准接口。它可以让Web服务器调用应用程序来执行特定任务,并将结果返回给Web浏览器。 CGI描…

车载电源OBC+DC/DC

文章目录 1. 车载DC/DC应用场景2. PFC2.1 简介2.2 专业名词2.3 常见拓扑结构2.3.1 传统桥式PFC2.3.2 普通无桥型PFC2.3.3 双Boost无桥PFC2.3.4 图腾柱PFC2.3.5 参考资料 2.4 功率因数2.4.1 简介2.4.2 计算 3. DC/DC3.1 Boost升压电路3.1.1 简介3.1.2 电路框图3.1.3 工作原理3.1…

解锁编程的力量:SPL的学习之旅

SPL 一、前言二、集算器应用场景三、下载四、集算器的基本使用 一、前言 一种面向结构化数据的程序计算语言 集算器又称:SPL(Structured Process Language) 敏捷计算是集算器的主要特征 二、集算器应用场景 数据准备(跑批&…

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践

前言 AWS Lambda 是一项计算服务,使用时无需预配置或管理服务器即可运行代码。AWS Lambda 只在需要时执行代码并自动缩放。借助 AWS Lambda,几乎可以为任何类型的应用程序或后端服务运行代码,而且无需执行任何管理。 Lambda Layer 是一个包…

yakit使用教程(四,信息收集)

本文仅作为学习参考使用,本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 前言:yakit下载安装教程。 一,基础爬虫。 在新建项目或新建临时项目后,点击安全工具,点击基础爬虫。 此工具并不是为了爬取网站上的一…

Protobuf:消息更新

Protobuf:消息更新 更新字段保留字段未知字段option选项 在开发中,需要对产品进行版本迭代。迭代前后,类的成员可能就会有所改动,一旦类成员改动,那么老版本的对象,新版本可能就无法解析,此时就…

一文了解 Linux 系统的文件权限管理

文章目录 引入Linux文件权限模型查看文件权限权限信息解析修改文件权限符号模式八进制数字模式 引入 在Linux操作系统中,我们想查看我们对文件拥有哪些权限时,可以在终端键入ls -l或ll命令,终端会输出当前路径下的文件信息,如文件…

【网络】【Linux】多路转接技术

多路转接技术 文章目录 1.select1.1select系统调用及参数介绍1.2select基本工作流程1.3select技术实现echo服务器1.4select优缺点1.5select的适用场景 2.poll(了解)2.1poll系统调用及参数介绍2.2poll技术实现echo服务器2.3poll优缺点 3.epoll3.1epoll系…

【新人系列】Python 入门(二):Python IDE 介绍

✍ 个人博客:https://blog.csdn.net/Newin2020?typeblog 📝 专栏地址:https://blog.csdn.net/newin2020/category_12801353.html 📣 专栏定位:为 0 基础刚入门 Python 的小伙伴提供详细的讲解,也欢迎大佬们…

【Windows命令】Windows下启动Nginx后,在任务管理器里面没有发现nginx.exe进程

如题,当在本地Windows环境下想用反向代理时,突然发现在任务管理器里面没有发现nginx.exe进程,但是端口又是占用的。这时就要用Windows命令了。 查询端口占用 netstat -ano | findstr :80 根据进程ID(pid)查询进程名称…

ESP32移植Zephyr RTOS(一)-----hello world

硬件平台:实战派ESP32-C3开发板 zephyr版本:Zephyr version 3.7.99 开发环境:ubuntu 24.4 之前一直想用正点原子阿波罗F4来写zephyr系列教程来自,但是本人水平有限RGB LCD实在是搞不懂,遂放弃,正好手头有一…

行业标准丨《变电站智能巡检导则:图像识别》(征求意见稿)

2024年8月30日,能源行业电网设备智能巡检标准化技术委员会秘书处组织召开行业标准《变电站智能巡检导则第6部分:图像识别》编制启动会,2024年9月30日,能源行业电网设备智能巡检标准化技术委员会秘书处将征求意见稿在委员单位、有关单位和中国…

SLM883x系列SLM8834两个零漂移可设置和稳定TEC温度 超紧凑高效率高精度TEC控制器

SLM883x系列SLM8834是集成了双路功率调节器的单片TEC控制器。内部带有一个线性功率级、一个脉宽调制(PWM)功率级和两个零漂移、轨对轨运算放大器。线性功率级与PWM功率级同时工作,以控制H桥配置中的内部功率级的双向输出。通过测量热传感器反…

TinyOS 点对基站通信

文章目录 一、前言1.1 发包的BlinkToRadio的数据包格式 二、混淆基站源码分析2.1 Makefile2.2 组件连接2.3 主逻辑代码 一、前言 1.1 发包的BlinkToRadio的数据包格式 如下,注意:AM层类型(1byte)即handlerID使可以在组件中修改的。 二、混淆基站源码…

请确保已在git上配置你的user.name和user.email

问题:使用vscode在远程服务器上暂存修改报错: 原因:未在远程服务器上配置该项目对应的git的username和useremail 解决方法: 在vscode中新建一个终端 命名: git config --global user.email "youexample.com&qu…

2015年国赛高教杯数学建模C题月上柳梢头解题全过程文档及程序

2015年国赛高教杯数学建模 C题 月上柳梢头 月上柳梢头,人约黄昏后”是北宋学者欧阳修的名句,写的是与佳人相约的情景。请用天文学的观点赏析该名句,并进行如下的讨论:   1. 定义“月上柳梢头”时月亮在空中的角度和什么时间称为…

SketchUp Pro 2024 for Mac 3D建模 草图设计大师软件安装【保姆级教程,简单小白轻松上手】

Mac分享吧 文章目录 SketchUp Pro 3D建模 草图设计大师软件 安装完成,软件打开效果一、Mac中安装SketchUp Pro 3D建模 草图设计大师软件——v241️⃣:下载软件2️⃣:安装软件,将安装包从左侧拖入右侧文件夹中3️⃣:应…

树莓派应用--AI项目实战篇来啦-5.OpenCV绘画函数的使用

1. 介绍 OpenCV作为一款功能强大的计算机视觉库,被广泛地应用于图像处理和计算机视觉领域。 除了在机器视觉和人工智能领域有者广泛的应用,OpenCV 还能够媲美艺术家的创造力,通过其强大的绘图函数,绘制出令人叹为观止的艺术画作。…

子组件向父组件传值$emit

点击子组件的按钮&#xff0c;将子组件的值传递给父组件&#xff0c;并进行提示。 子组件 <template><div><button click"emitIndex">clickme</button></div> </template> <script> export default {methods: {emitInde…

petalinux 自动登陆 自动启动程序

PetaLinux 自动登陆 (1) cd 到项目工程目录下&#xff1b; (2) 运行命令&#xff1a;petalinux-config -c rootfs (3) 依次选择 Image Features -> serial-autologin-root 保存退出 创建APP petalinux-create apps --template install --name init-app --enable编辑文件 …