LLM Agent零微调范式 ReAct Self Ask

前三章我们分别介绍了思维链的使用,原理和在小模型上的使用。这一章我们正式进入应用层面,聊聊如何把思维链和工具使用结合得到人工智能代理。

要回答我们为什么需要AI代理?代理可以解决哪些问题?可以有以下两个视角

首先是我们赋能模型,如果说LLM是大脑,那Agent提供了手脚和感官

  1. 感官:获取真实世界的信息,包括实时信息像天气情况,金融市场,交通状况;包括私有信息例如用户个人数据;包括多模态信息像声音和图像
  2. 手脚:获得和真实世界交互的能力,例如运行python脚本,调用搜索引擎,预定机票酒店。

其次是模型赋能我们,Agent加持的大模型,作为更优的数据和任务中介/代理,赋予了我们和任意数据类型交互的能力,大模型正在重构数据和信息的处理方式。从之前的结构化数据为主向更多的非结构化数据转变。

OpenAI应用研究主管LilianWeng写的LLM Powered Autonomous Agents把人工智能代理(AI Agent)分成了以下3个部分:规划模块,工具调用模块和记忆模块。

之后几章我们会聊到AI代理方案的主要差异也在这三个方向

  1. 规划:如何对问题进行拆解得到解决路径,既模型推理步骤
  2. 工具:支持哪些工具使用,如何进行工具选择,并生成调用工具的请求
  3. 记忆:短期记忆包括工具的返回值,已经完成的推理路径,长期记忆包括可访问的外部长期存储例如知识库

第一篇我们结合langchain介绍无需微调,使用few-shot,zero-shot prompt来生成推理和工具调用模板的两个方案ReAct和SelfASk。个人对langchain是又爱又恨,爱的是它集成了很多前沿的大模型应用方案,恨是感觉它有些过度封装,有点简单问题复杂设计的感觉。因此推荐使用langchain来理解每种方案的实现原理,然后脱离langchain自己写,或者只使用langchain的基础组件来实现,不要去使用它的高级API。

Self Ask

  • Self-ask: MEASURING AND NARROWING THE COMPOSITIONALITY GAP IN LANGUAGE MODELS
  • Self-ask Prompting – Ofir Press

原理

Self Ask提出了一种把问题拆解成子问题的Prompt范式,每一步模型都会自我提问是否可以把问题改写/拆解成一个简单的子问题,并进行回答,回答时可以调佣搜索工具来获得答案,然后根据工具返回结果,继续进行自我提问,直到获得最终答案。其实自我提问的推理形式并不是核心,核心是引导模型来进行问题拆解,也就是开头提到的规划能力。

论文提出之所以需要把原始的思维链改造成一步步自我提问的形式,是因为发现模型在回答复杂问题的时候,模型虽然可以正确回答其中的子问题,但是却无法回答由子问题组合起来的复杂问题,作者称之为Compositionality Gap。举个栗子:模型可以正确回答贾斯汀比伯是哪年出生的? 以及谁是94年大师赛的冠军? 但是模型无法回答谁是贾斯汀比伯出生那一年的大师赛的冠军?而通过引入问题拆解的推理方式,可以很好解决这个问题

应用

我们来看下langchain的Self Ask实现,官网Demo是直接用initialize_agent来初始化代理,这里我们把中间步骤拆解开。以下使用了SerpAPI的google搜索工具和GPT3.5,都需要先去官网申请Key

import os
from langchain.agents.loading import AGENT_TO_CLASS
from langchain.agents.agent import AgentExecutor
from langchain.agents import AgentType, Tool
from langchain import OpenAI, SerpAPIWrapper
## 需要科学上个网
os.environ["http_proxy"] = "http://127.0.0.1:7890"
os.environ["https_proxy"] = "http://127.0.0.1:7890"
## 定义大模型和搜索工具
llm = OpenAI(temperature=0, openai_api_key=$你的Key)
search = SerpAPIWrapper(params={"engine": "google","gl": "us","hl": "zh-cn",
}, serpapi_api_key=$你的Key)“”“
以下的工具初始化方式对齐了Self Ask 的Prompt模板
”“”tools = [Tool(name="Intermediate Answer",func=search.run,description="useful for when you need to ask with search")
]
## 组装:初始化agent和Chain
agent_cls = AGENT_TO_CLASS[AgentType.SELF_ASK_WITH_SEARCH]
agent = agent_cls.from_llm_and_tools(llm, tools)
chain = AgentExecutor.from_agent_and_tools(agent, tools, return_intermediate_steps=True)

AGENT_TO_CLASS里面定义了所有的Agent类型,其中SelfAskWithSearchAgent是Self Ask的实现,但其实不同Agent的差异,主要是以下few-shot prompt和对应的parser不同。

from langchain.agents.self_ask_with_search.output_parser import SelfAskOutputParser
from langchain.agents.self_ask_with_search.prompt import PROMPT

其中SelfAsk的few-shot prompt 如下,few-shot除了提供解码的格式之外,还提示了模型要对问题进行拆解

_DEFAULT_TEMPLATE = """Question: Who lived longer, Muhammad Ali or Alan Turing?
Are follow up questions needed here: Yes.
Follow up: How old was Muhammad Ali when he died?
Intermediate answer: Muhammad Ali was 74 years old when he died.
Follow up: How old was Alan Turing when he died?
Intermediate answer: Alan Turing was 41 years old when he died.
So the final answer is: Muhammad AliQuestion: When was the founder of craigslist born?
Are follow up questions needed here: Yes.
Follow up: Who was the founder of craigslist?
Intermediate answer: Craigslist was founded by Craig Newmark.
Follow up: When was Craig Newmark born?
Intermediate answer: Craig Newmark was born on December 6, 1952.
So the final answer is: December 6, 1952省略2个shotQuestion: {input}
Are followup questions needed here:{agent_scratchpad}"""

构建完chain我们来跑一个问题看下模型的中间返回结果

# chain.run是用于直接返回最终结果,直接调用callable可以返回中间过程
output =  chain("昨日A股市场涨幅最高的板块成交量如何")

以下是带中间结果的返回值,可以发现few-shot-prompt引导模型把问题"昨日A股市场涨幅最高的板块成交量如何"拆分成了,"昨日A股市场涨幅最高的板块?",并通过谷歌搜索得到是券商板块后,继续提问"券商板块昨日成交量"得到最终结果

这里只展示了一个goodcase,因为badcase太多啦哈哈~SelfAsk结果不好的两个主要原因有

  • 搜索没有返回有效结果:当前搜索引擎的返回结果并非为大模型回答设计,而还是为传统搜索引擎设计,返回结果不可用可能是抽取的文章摘要(snippet)不合理,或者排序逻辑返回的Top1答案不合适,再或者回答的时效性错误等等,这里存在很大的优化空间
  • 模型拆解问题有误:SelfAsk当前主要针对组合类问题,如果你的问题拆解方式不同,需要对以上few-shot-prompt进行调整,或者进一步通过COT finetune来注入问题拆解的方式

Self Ask是一类最简单的工具调用模板,只支持单一搜索工具的使用,不支持工具选择。下面我们看下支持多种工具调用的ReAct范式~

ReAct

  • ReAct: SYNERGIZING REASONING AND ACTING IN LANGUAGE MODELS
  • ReAct (Reason+Act) prompting in LLMs – tsmatz

原理

ReAct文如其名,模型推理分成了两个部分,Reason和Action。Reason生成分析步骤,Action生成工具调用请求,二者交替进行直到得到最终的结果。和SelfAsk对比,ReAct进一步把推理和工具调用进行了解耦, 在Self Ask中,自我提问既是推理步骤也是搜索工具的请求query,而在ReAct中工具调用的请求在推理步骤之后,这样可以更好的支持搜索以外的其他工具。

ReAct在文档问答上给出的few-shot-cot推理模板如下

应用

同样是AGENT_TO_CLASS,ReActDocstoreAgent和ZeroShotAgent是基于ReAct开发的。为了保持一致性,我们用和以上Self Ask相同的方式来初始化以下两个Agent,更简洁的初始化代码详见官网ReAct, ReActDocument Store

  • ZeroShotAgent

需要提供可以使用的工具列表,以及每种工具的描述,LLM完全基于上下文,根据工具的描述进行工具选择,适用于没有固定推理套路的场景。为了和SelfAsk对比,这里我们还是使用谷歌搜索,再额外加入Wolfram Alpha工具,代码部分只用替换工具定义的部分和agent class,其余部分完全一样。

"""
需要提供工具的描述description:用于工具选择和工具请求的生成
同时tool.name从selfAsk中统一的Intermediate Answer,调整为工具本身的名称用于生成工具调用的前缀
"""
import os
from langchain.agents.loading import AGENT_TO_CLASS
from langchain.agents.agent import AgentExecutor
from langchain.agents import AgentType, Tool
from langchain import OpenAI, SerpAPIWrapper
from langchain.utilities.wolfram_alpha import WolframAlphaAPIWrapper
## 需要科学上个网
os.environ["http_proxy"] = "http://127.0.0.1:7890"
os.environ["https_proxy"] = "http://127.0.0.1:7890"
os.environ["WOLFRAM_ALPHA_APPID"] = "你的key"
## 定义大模型和搜索工具
llm = OpenAI(temperature=0, openai_api_key=$你的key)
search = SerpAPIWrapper(params={"engine": "google","gl": "us","hl": "zh-cn",
}, serpapi_api_key=$你的key)
wolfram = WolframAlphaAPIWrapper()
tools = [Tool(name="搜索",description="搜索引擎,当你需要回答当前问题的时候调用,输入是检索query",func=search.run),Tool(name="Wolfram",description="Wolfram Alpha,当你需要回答和数学,科学,科技,文化,社会,日常生活相关的问题时调用,输入是检索query",func=wolfram.run),
]
agent_cls = AGENT_TO_CLASS[AgentType.ZERO_SHOT_REACT_DESCRIPTION ]
agent = agent_cls.from_llm_and_tools(llm, tools)
chain = AgentExecutor.from_agent_and_tools(agent, tools, return_intermediate_steps=True)
output = chain("昨日A股市场涨幅最高的板块成交量多少") #chain.run不能返回中间结果,直接调用可以返回中间过程

加入谷歌搜索和Wolfram工具后,zero-shot prompt如下,包含工具的描述和Action部分可以调用的工具列表。

继续问:昨日A股市场涨幅最高的板块成交量如何?因为没有few-shot拆解问题的指引,只有以上zero-shot去描述工具选择,因此模型并没有正确拆解问题,不过正确选择了搜索工具。

当我们提问wolfram可以解决的问题领域,例如求解几何面积时,大模型会选择调用Wolfram来解决数学问题。

  • ReActDocstoreAgent

适用于文档问答的固定推理模板+固定工具使用,论文定义了两种工具Search检索,和Lookup在文档中查找关键词所在的句子。DocStore因为推理模板固定,可用的场景比较有限,我们就做不测试了,大家可以直接去看官网给出的Demo。

React虽然本身是可以不经过模型指令微调直接使用的,但论文中也提出指令微调后效果会有提升,不过微调的方案我们会单独放一章来说。

总结

看完了SelfAsk和React的实现,不难发现二者存在一些局限性

  • 更适合简单的工具调用:这里的简单是指工具的输入和上文的文本语义比较符合,工具输入比较“自然语言”风格例如搜索。高度结构化和符号化的工具输入,使用Prompt实现,准确率比较有限。
  • 更适合少量的工具组合:受限于Prompt上文的长度,不能把几十个工具prompt全塞进去,因此更适合少量的工具组合一般是3~5个以内
  • 规划能力:在问题拆解上few-shot的效果会比zero-shot要好,不过要支持特定的问题拆解逻辑需要定制化领域few-shot。如果逻辑过于复杂或者多样性较高,只依赖固定prompt的效果也会比较一般。
  • 串行计算延时高:SelfAsk和React都是串行推理逻辑,每一步推理和工具调用都依赖上一步的推理结果,导致整体计算耗时太长。针对这个问题可以看下ReWOO[4]提出的并行推理+槽位填充的方案~

针对更复杂多样的工具调用,和更有针对性/复杂的模型规划能力,我们下一章介绍基于指令微调的工具调用方案。

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

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

相关文章

TSINGSEE青犀智能分析网关V4在智慧园区车辆违停检测场景中的应用

一、背景与需求 园区作为企业办公、生产制造的重要场所,主要道路车辆违停等违规行为会对园区的安全造成隐患,并且在上下班高峰期内,由于发现不及时,车辆违停行为会造成出入口拥堵现象,这也成为园区管理的棘手问题。为了…

二叉搜索树/二叉排序树(代码实现)(c++)

BSTree 二叉排序树概念代码部分 BSTree框架查找操作插入操作删除操作**默认成员函数完整代码 BSTree性能分析 二叉排序树概念 二叉搜索树又称二叉排序树(BSTree, Binary Search Tree),它或者是一颗空树,或者是具有以下性质的二叉…

DNs服务学习笔记

DNS:域名系统(英文:Domain Name System)是一个域名系统,是万维网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。类似于生活中的11…

计算机毕业设计-----ssm+mysql实现的JavaWeb酒店管理系统

项目介绍 本项目为基于ssmmysql实现的JavaWeb酒店管理系统; 主要功能包括: 管理员登录,收入统计,客房管理,商品管理,客房预订,住宿登记,财务统计,旅客管理,接待对象管理等功能。 环境需要 1.运行环境:最好是java jdk 1.8,我们在这个平台上…

Efficient Classification of Very Large Images with Tiny Objects(CVPR2022补1)

文章目录 Two-stage Hierarchical Attention SamplingsummaryOne-stageTwo-Stage内存需求 Efficient Contrastive Learning with Attention Sampling Two-stage Hierarchical Attention Sampling summary 从一个大图像中按照指定的低分辨率比例和位置提取出一个小图块 一阶段…

C#编程-实现继承

C#允许您通过扩展现有类的功能以创建新类来实现继承。 从基类创建派生类 使用以下语法在C#中创建派生类: class <derived_class>:<base_class>{...}确定继承的层次结构 要确定继承层次结构,必须检查派生类与基类之间的关系种类。确保派生类是一种基类。 请考虑以…

基于Springboot的旅游管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的旅游管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

数据结构(JS实现)

目录 链表链表的特点链表中的常见操作单链表append(data)尾部追加新节点toString()输出链表的节点数据插入节点insert(position,data)get(position)获取链表指定位置节点的数据indexOf(data)查找对应数据节点的位置update(position, newData)更新指定位置节点数据removeAt(posi…

稿件代写3个不可或缺的步骤让你事半功倍-华媒舍

作为一个需求频繁的作者&#xff0c;你可能会面临大量的稿件代写任务。但是&#xff0c;你是否曾经为提高文章质量而苦恼过&#xff1f;是否希望在有限的时间内完成更多的代写任务&#xff1f;本篇文章将向你介绍三个不可或缺的稿件代写步骤&#xff0c;帮助你事半功倍&#xf…

NGUI基础-三大基础控件之Sprite精灵图片

目录 Sprite是什么 如何创建Sprite 参数相关 Atlas Sprite Material Fixed Aspect Type Simple(普通模式&#xff09; Sliced(切片模式&#xff09; Tiled(平铺模式&#xff09; Filled(填充模式&#xff09; 常见的填充模式有以下几种&#xff1a; Advanced(高级…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)创建并初始化TcpServer实例 以及 启动

对于一个TcpServer来说&#xff0c;它的灵魂是什么&#xff1f;就是需要提供一个事件循环EventLop(EventLoop)&#xff0c;不停地去检测有没有客户端的连接到达&#xff0c;有没有客户端给服务器发送数据&#xff0c;描述的这些动作&#xff0c;反应堆模型能够胜任。当服务器和…

Stable Diffusion架构的3D分子生成模型 GeoLDM - 测评与代码解析

之前&#xff0c;向大家介绍过3D分子生成模型 GeoLDM。 GeoLDM按照Stable Diffusion架构&#xff0c;将3D分子生成的扩散过程运行在隐空间内&#xff0c;优化了基于扩散模型的分子生成。可能是打开Drug-AIGC的关键之作。让精确控制分子生成有了希望。 详见&#xff1a;分子生成…