Agent检索增强生成

检索增强生成(RAG)设计模式通常用于在特定数据域中开发大语言模型(LLM)应用。然而,RAG的过往的研究重点主要在于提高检索工具的效率,例如嵌入搜索、混合搜索和微调嵌入,而忽视了智能搜索。本文介绍了一种受人类研究方法启发的新方法,该方法涉及多种搜索技术、观察临时结果、精炼以及在提供响应之前在多步骤过程中重试。本文提出基于智能Agent的检索增强方案,突破传统RAG模式的局限性,构建更加智能、更加贴近事实的LLM应用。

1 - 基本RAG模式和限制

标准RAG模式实现概述:

图片

  • 该过程首先根据用户的问题或对话创建查询,通常通过提示语言模型(LLM)。这通常称为查询重写步骤。

  • 然后将该查询分派到搜索引擎,搜索引擎返回相关知识(检索)。

  • 然后,检索到的信息会通过包含用户问题的提示进行增强,并转发给LLM。

  • 最后,LLM对用户的查询(生成)做出回应。

RAG的局限性:

  • 在RAG模式中,检索、增强和生成由单独的进程管理。LLM可能会通过不同的提示来进行每个过程。然而,直接与用户交互的LLM通常最了解回答用户查询所需的内容。检索LLM可能不会以与生成LLM相同的方式解释用户的意图,从而为其提供可能妨碍其响应能力的不必要的信息。

  • 每个问题都会执行一次检索,没有来自LLM的任何反馈循环。如果由于搜索查询或搜索词等因素导致检索结果不相关,LLM缺乏纠正这种情况的机制,可能会诉诸捏造答案。

  • 检索的上下文一旦提供就不可更改且无法扩展。例如,如果研究结果表明需要进一步调查,例如检索到的文档引用了应进一步检索的另一文档,则没有此规定。

  • RAG模式不支持多步骤迭代搜索。

2 - Agent智能RAG模式原理

智能Agent模型在回答缺乏直接知识的问题时从人类的研究方法中汲取灵感。在此过程中,在提供最终答案之前,可以执行一次或多次搜索以收集有用的信息。每次搜索的结果可以确定是否需要进一步调查,如果需要,则确定后续搜索的方向。这个迭代过程一直持续到我们相信我们已经积累了足够的知识来回答,或者得出结论我们无法找到足够的信息来回答。有时,研究结果可以进一步阐明用户的意图和查询范围。

为了复制这种方法,建议开发一个由语言模型(LLM)提供支持的智能Agent,用于管理与用户的对话。Agent自主确定何时需要使用外部工具进行研究,制定一个或多个搜索查询,进行研究,审查结果,并决定是否继续进一步研究或寻求用户的澄清。此过程一直持续到Agent认为自己已准备好向用户提供答案为止。

图片

3 - Agent智能RAG模式实现

可以借助Azure OpenAI的功能调用能力来实现一个能自主使用搜索工具查找所需信息以协助处理用户请求的Agent。仅这一项功能就简化了RAG模式的传统实现方式(如前所述包括查询改写、增强和生成的独立步骤)。

Agent使用系统定义的角色和目标与用户交互,同时了解其可以使用的搜索工具。当Agent需要查找它不具备的知识时,它会制定搜索查询并向搜索引擎发出信号以检索所需的答案。

这个过程不仅让人想起人类行为,而且比RAG模式更有效。在RAG模式中,知识检索是一个单独的过程,无论是否需要都向聊天机器人提供信息。

实现此功能分为以下几步:

(1)定义角色、预期行为和要使用的工具以及何时使用。

PERSONA = """
You are Maya, a technical support specialist responsible for answering questions about computer networking and system.
You will use the search tool to find relavent knowlege articles to create the answer.
Answer ONLY with the facts from the search tool. If there isn't enough information, say you don't know. Do not generate answers that don't use the sources below. If asking a clarifying question to the user would help, ask the question.
Each source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. Use square brakets to reference the source, e.g. [info1.txt]. Don't combine sources, list each source separately, e.g. [info1.txt][info2.pdf].
If the user is asking for information that is not related to computer networking, say it's not your area of expertise.
"""

(2)定义json格式的函数规范,包含函数和参数描述。

FUNCTIONS_SPEC= [  {"name": "search_knowledgebase","description": "Searches the knowledge base for an answer to the technical question","parameters": {"type": "object","properties": {"search_query": {"type": "string","description": "The search query to use to search the knowledge base"},},"required": ["search_query"],},},
] 

有趣的是,“用于搜索知识库的搜索查询”的参数描述起着至关重要的作用。它指导LLM根据帮助用户进行对话所需的内容制定合适的搜索查询。此外,可以描述搜索查询参数并将其限制为遵守特定的工具格式,例如Lucene查询格式。还可以结合其他参数来执行过滤等任务。

(3)实现函数调用流程。

图片

此时,我们开发了一种能够进行独立搜索的智能Agent。然而,为了真正创建一个能够承担更复杂的研究任务(例如多步骤和自适应执行)的智能Agent,我们还需要实现一些额外的功能。

为了增加Agent在系统消息中计划、行动、观察和调整的能力,我们需要在角色定义中添加如下信息:

Being smart in your research. If the search does not come back with the answer, rephrase the question and try again.Review the result of the search and use it to guide your next search if needed.If the question is complex, break down to smaller search steps and find the answer in multiple steps.

更新之后的角色定义如下:

PERSONA = """You are Maya, a technical support specialist responsible for answering questions about computer networking and system.You will use the search tool to find relavent knowlege articles to create the answer.Being smart in your research. If the search does not come back with the answer, rephrase the question and try again.Review the result of the search and use it to guide your next search if needed.If the question is complex, break down to smaller search steps and find the answer in multiple steps.Answer ONLY with the facts from the search tool. If there isn't enough information, say you don't know. Do not generate answers that don't use the sources below. If asking a clarifying question to the user would help, ask the question.Each source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. Use square brakets to reference the source, e.g. [info1.txt]. Don't combine sources, list each source separately, e.g. [info1.txt][info2.pdf].If the user is asking for information that is not related to computer networking, say it's not your area of expertise."""

添加的指令表示机器人应该重试并根据需要更改问题。此外,它还表示机器人应该审查搜索结果以指导下一次搜索,并在需要时采用多步骤方法。这假设可以多次调用搜索工具。

由于LLM无法自行重复此过程,因此我们需要使用应用程序逻辑来管理此过程。我们可以通过将整个过程放在一个循环中来做到这一点。当模型准备好给出最终答案时,循环退出:

while True:response = openai.ChatCompletion.create(deployment_id=self.engine,  # The deployment name you chose when you deployed the GPT-35-turbo or GPT-4 model.messages=conversation,functions=self.functions_spec,function_call="auto")response_message = response["choices"][0]["message"]# Step 2: check if GPT wanted to call a functionif response_message.get("function_call"):print("Recommended Function call:")print(response_message.get("function_call"))print()# Step 3: call the function# Note: the JSON response may not always be valid; be sure to handle errorsfunction_name = response_message["function_call"]["name"]# verify function existsif function_name not in self.functions_list:raise Exception("Function " + function_name + " does not exist")function_to_call = self.functions_list[function_name]# verify function has correct number of argumentsfunction_args = json.loads(response_message["function_call"]["arguments"])if check_args(function_to_call, function_args) is False:raise Exception("Invalid number of arguments for function: " + function_name)search_query = function_args["search_query"]print("search_query", search_query)# check if there's an opportunity to use semantic cacheif function_name == "search_knowledgebase":if os.getenv("USE_SEMANTIC_CACHE") == "True":cache_output = get_cache(search_query)if cache_output is not None:print("semantic cache hit")conversation.append({"role": "assistant", "content": cache_output})return False, query_used, conversation, cache_outputelse:print("semantic cache missed")query_used = search_queryfunction_response = function_to_call(**function_args)print("Output of function call:")print(function_response)print()# Step 4: send the info on the function call and function response to GPT# adding assistant response to messagesconversation.append({"role": response_message["role"],"name": response_message["function_call"]["name"],"content": response_message["function_call"]["arguments"],})# adding function response to messagesconversation.append({"role": "function","name": function_name,"content": function_response,})  # extend conversation with function responsecontinueelse:break  # if no function call break out of loop as this indicates that the agent finished the research and is ready to respond to the user

完整代码可以参考:
https://github.com/microsoft/OpenAIWorkshop/blob/sephack/scenarios/incubations/copilot/smart_agent/utils.py

以下是演示场景中正在运行的智能Agent:

图片

问题是对两种产品之间的功能进行比较。每个产品的功能都存储在单独的文档中。为此,我们的Agent执行两个搜索查询:

X100 vs Z200 power profile for Radio 0
X100 power profile for Radio 0

第一个查询是一种贪婪方法,因为Agent希望有一个包含比较的文档。情况并非如此,因为搜索查询没有返回有关X100的足够信息,因此添加了专用于X100的第二个查询。

如果将其提供给经典的RAG解决方案,它将无法找到好的答案,因为它会在第一个查询处停止。

4 - 结论

实施Agent模式可以显着增强LLM应用能力。这是由于该模式具有测试各种策略并根据观察到的结果改进其方法的智能能力。 

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

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

相关文章

for循环判断有几个偶数

num100 count0 for i in range(1,num):if i%20:print("为偶数")count1 print(f"1-100的范围内,有{count}个偶数") 运行结果如下:

代码随想录Day21 | 530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 236. 二叉树的最近公共祖先

代码随想录Day21 | 530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 236. 二叉树的最近公共祖先 二叉搜索树的最小绝对差二叉搜索树中的众数二叉树的最近公共祖先 二叉搜索树的最小绝对差 文档讲解:代码随想录 视频讲解: 二叉搜索树中,需…

使用免费敏捷工具Leangoo领歌管理Sprint Backlog

什么是Sprint Backlog? Sprint Backlog是Scrum的主要工件之一。在Scrum中,团队按照迭代的方式工作,每个迭代称为一个Sprint。在Sprint开始之前,PO会准备好产品Backlog,准备好的产品Backlog应该是经过梳理、估算和优先…

C语言编译链接

1.翻译环境和运⾏环境 在ANSI C的任何⼀种实现中,存在两个不同的环境。 第1种是翻译环境,在这个环境中源代码被转换为可执⾏的机器指令。 第2种是执⾏环境,它⽤于实际执⾏代码。 2. 翻译环境 翻译环境是由编译和链接两个⼤的过程组成的&…

Spring环境搭配

概述 Spring 是一个开源框架,Spring 是于2003 年兴起的一个轻量级的Java 开发框架,由 RodJohnson 在其著作 Expert One-On-One J2EE Development and Design 中阐述的部分理念和原型衍生而来。它是 为了解决企业应用开发的复杂性而创建的。框架的主要优势…

mockjs使用1

mockjs使用 1、定义 Mock.js 是一款模拟数据生成器,旨在帮助前端攻城师独立于后端进行开发,帮助编写单元测试。提供了以下模拟功能: 根据数据模板生成模拟数据模拟 Ajax 请求,生成并返回模拟数据基于 HTML 模板生成模拟数据 2…

软件测试|SQLAlchemy query() 方法查询数据

简介 上一篇文章我们介绍了SQLAlchemy 的安装和基础使用,本文我们来详细介绍一下如何使用SQLAlchemy的query()方法来高效的查询我们的数据。 创建模型 我们可以先创建一个可供我们查询的模型,也可以复用上一篇文章中我们创建的模型,代码如…

游戏开发,中小公司跳槽去大厂容易还是考研应届生校招容易?

游戏开发,中小公司跳槽去大厂容易还是考研应届生校招容易? 在之前的文章中,我们提到过,游戏开发行业首选直接进入游戏大厂。《开发者必读:如何选择适合的游戏开发公司?》因为大厂不仅能提供良好的职业发展…

接口防刷方案

1、前言 本文为描述通过Interceptor以及Redis实现接口访问防刷Demo 2、原理 通过ip地址uri拼接用以作为访问者访问接口区分 通过在Interceptor中拦截请求,从Redis中统计用户访问接口次数从而达到接口防刷目的 如下图所示 3、案例工程 项目地址: htt…

localStorage、sessionStorage、vuex区别和使用感悟

一、介绍及区别 localStorage的生命周期是永久;不手动在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。 sessionStorage的生命周期为当前窗口或标签页,一旦窗口或标签页被永久关闭,那么所有通过sessionStorage存…

AI红娘开启约会新时代;网易云音乐Agent实践探索;微软生成式AI课程要点笔记;ComfyUI新手教程;图解RAG进阶技术 | ShowMeAI日报

👀日报&周刊合集 | 🎡生产力工具与行业应用大全 | 🧡 点赞关注评论拜托啦! 👀 Perplexity 官宣 7360 万美元B轮融资,打造世界上最快最准确的答案平台 https://blog.perplexity.ai/blog/perplexity-rais…

uniapp中uview组件库Toast 消息提示 的使用方法

目录 #基本使用 #配置toast主题 #toast结束跳转URL #API #Props #Params #Methods 此组件表现形式类似uni的uni.showToastAPI,但也有不同的地方,具体表现在: uView的toast有5种主题可选可以配置toast结束后,跳转相应URL目…

Linux系统——yum仓库及NFS共享

目录 一、yum仓库 1.yum简介 2.yum实现过程 3.如何实现安装服务 4.yum配置文件及命令 4.1yum配置文件 4.1.1主配置文件 4.1.2仓库设置文件 4.1.3日志文件 4.2yum命令详解 4.2.1查询 4.2.2yum安装升级 4.2.3软件卸载 4.2.4操作安装历史记录 5.搭建本地yum仓库 5…

【分布式技术】分布式存储ceph部署

目录 一、存储的介绍 单机存储设备 单机存储的问题 商业存储 分布式存储 二、分布式存储 什么是分布式存储 分布式存储的类型 三、ceph简介 四、ceph的优点 五、ceph的架构 六、ceph的核心组件 七、OSD存储后端 八、Ceph 数据的存储过程 九、Ceph 版本发行生命周…

NFS的共享与挂载

一、NFS网络文件服务 1.1简介 NFS(Network File System 网络文件服务) 文件系统(软件)文件的权限 NFS 是一种基于 TCP/IP 传输的网络文件系统协议,最初由 Sun 公司开发。 通过使用 NFS 协议,客户机可以像访…

【数据库8.0备份还原】之Percona XtraBackup

目录 Percona XtraBackup备份数据库1、Percona XtraBackup的介绍2、Percona XtraBackup安装3、Percona XtraBackup8.0的使用1.全库备份和还原2.增量备份和还原3.差异备份和还原4.差异备份和增量备份的区别5.压缩备份和还原 Percona XtraBackup备份数据库 yum源安装&#xff1a…

Spring基础属性一览:注释、对象装配、作用域、生命周期

在Spring中想要更简单的存储和读取对象的核心是使用注解,也就是我们接下来要学的Spring中相关注解。 之前我们存储Bean时,需要在自己添加的配置文件中添加一行bean才行: 而现在我们只需要一个注解就可以替代之前要写的一行配置的繁琐了。 …

消息队列的作用与使用场景?

一、消息队列的作用 队列的主要作用是消除高并发访问高峰,加快网站的响应速度。 在不使用消息队列的情况下,用户的请求数据直接写入数据库,在高并发的情况下,会对数据库造成巨大的压力,同时也使得系统响应延迟加剧。 …

HDFS WebHDFS 读写文件分析及HTTP Chunk Transfer Encoding相关问题探究

文章目录 前言需要回答的首要问题DataNode端基于Netty的WebHDFS Service的实现基于重定向的文件写入流程写入一个大文件时WebHDFS和Hadoop Native的块分布差异 基于重定向的数据读取流程尝试读取一个小文件尝试读取一个大文件 读写过程中的Chunk Transfer-Encoding支持写文件使…

postman 简单测试(二)

接着上一节 https://blog.csdn.net/myy2012/article/details/135616719 1.Tests的简单使用(后置处理器) 具体的截图是每一步操作后得来的,记录方便自己以后查阅,也希望能帮助到有缘人。 1.1 把返回值存入到环境变量中&#xff…