简介
2023.3.13:当前的agent把nlp的门槛降低了,很多普通程序猿借助llm 也可以做一些之前只能由nlp 算法可以做的事儿。 大多本质上还是个路由器,以及固定了分析流程,区别是以前很多流程固定在代码里,现在是很多分析、逻辑固定在prompt里。虽然llm 是通用的,这些流程仍然是case by case的,比如基于100个api 组合起来 可以干200个活儿,现在的agent 还是做不到根据问题自动分析、拆解。
比尔·盖茨:AI Agent将彻底改变人类生活方式尽管软件在过去几十年里取得了显著的进步,但是,从很多方面来看,它依然有些 “笨拙”。在计算机上完成任务时,你需要告诉设备使用哪个应用程序。例如,你可以用微软 Word 和谷歌文档撰写商业提案,但它们无法帮你发送邮件、分享自拍、分析数据、策划派对或购买电影票。即便是最优秀的网站,也只能片面地了解你的工作、个人生活、兴趣及人际关系,在利用这些信息来为你服务方面能力有限。但在未来五年内,这一切将彻底改变。你不再需要针对不同的任务使用不同的应用。你只需用日常语言告诉你的设备你想要做什么,软件将能够根据你愿意分享的信息量做出个性化的回应,因为它将深入理解你的生活。在不远的将来,任何联网的人都将能夠拥有一个由 AI 驱动的个人助理,其能力将远超现今的技术水平。这种能够理解自然语言并根据对用户的了解来完成多种任务的软件,被称为 “Agent”。PS:各个app 不再直面用户,而是通过接入Agent,由Agent来完成和用户之间的交互,Agent 将成为下一个平台。具象化一下,就是钢铁侠中的Javis。
简单使用LLM 是不够的
目前的大模型一般都存在知识过时、逻辑计算能力低等问题,通过Agent访问工具,可以去解决这些问题。Agent是指能够感知环境、做出决策和采取行动的实体。本质上还是prompt工程,通过Prompt去驱动模型进行 计划和工具调用。PS:你知道一个工具的存在,约等于你会调用这个工具;你会调用这个工具,约等于你会学习使用这个工具;会学习这个工具,约等于你已经会用这个工具;所以,你知道工具的存在,约等于你能把这件事做出来。搜索高于学习, 学习高于熟练。
ChatGPT、DALL-E 3 或 Midjourney 等工具使用基于提示的界面进行人机交互。这意味着您需要用自然语言编写一组指令(通常随后进行大量的重复提示尝试)才能获得有意义的响应。考虑到人工智能模型的能力,它的速度很慢,而且违反直觉。我们需要更好、更有效的方式来与人工智能交互。人工智能体(AI Agent),扮演着AI监工的角色。它们以自我导向的循环方式工作,为人工智能设置任务、确定优先级和重新确定任务的优先级,直到完成总体目标。PS:仅靠LLM 还是不够
Agent在LangChain框架中负责决策制定以及工具组的串联,可以根据用户的输入决定调用哪个工具。通过精心制定的提示,我们能够赋予代理特定的身份、专业知识、行为方式和目标。提示策略为 Agent 提供了预设模板,结合关键的指示、情境和参数来得到 Agent 所需的响应。具体的说,Agent就是将大模型进行封装来简化用户使用,根据用户的输入,理解用户的相应意图,通过action字段选用对应的Tool,并将action_input作为Tool的入参,来处理用户的请求。当我们不清楚用户意图的时候,由Agent来决定使用哪些工具实现用户的需求。
吴恩达:目前,我们使用大语言模型的主要方式是一种non-agentic工作流程,即您输入一个提示,模型就生成一个回答。这有点像让一个人坐下来一次性从头到尾编写一篇文章,而不允许使用退格键,尽管这样做很难,但大语言模型的表现出奇地出色。相比之下,代理工作流程看起来是这样的:首先,让人工智能大语言模型写一个文章大纲,如果需要进行网络研究就先做研究,然后写出第一稿,然后阅读并思考需要修订的部分,再修改这一稿,如此循环往复、迭代多次。很多人没有意识到,这种做法可以带来显著的改进效果。我自己在使用这些代理工作流程时也感到非常惊讶,它们工作得如此之好。研究发现,GPT-3.5使用零样本提示时只有48%的正确率,GPT-4提高到了67%。但如果在GPT-3.5上使用一个代理工作流程,它的表现实际上比GPT-4还要好。如果在GPT-4上使用代理工作流程,它的表现也非常出色。这意味着采用代理工作流程对于构建应用程序至关重要。不过我们需要改变一种习惯,那就是习惯了在提示语言模型后立即获得响应。在代理工作流程中,我们需要学会能够耐心等待几分钟甚至几个小时,才能得到响应,就像我们交代任务给人时需要适当地等待一段时间再进行检查一样。
Agent不只是一个工具
- 一开始大家玩 Prompt 工程(把大模型当做工具来调用,工具模式),接着是Prompt Chain或Flow,再到Agent,多Agent,很清晰的一个脉络架构。
- 我们回到 Agent 这个概念上,实际上,人类是这个星球上最强大的 Agent。Agent是一个能感知并自主地采取行动的实体,这里的自主性极其关键,Agent要能够实现设定的目标,其中包括具备学习和获取知识的能力以提高自身性能。Agent 的复杂程度各不相同,一个简单的恒温器可以是一个 Agent,一个大型的国家或者一个生物群体也可能是个 Agent。感知环境、自主决策、具备行动能力,设定明确的目标和任务,适应环境及学习能力,都是 Agent 的关键特点。
- 我们认为Agent技术是未来实现社会全面自动化的关键技术。在大模型出现之前,自动化更多的是一些偏结构化固定模式环境中通过实现固定算法流程来完成自动化任务,而大模型智能体的通用性带来了灵活性,使其可能应对人类在脑力劳动中面临的各种复杂长尾任务,进一步实现体力和脑力任务的全面自动化。PS:LLM本质是文字接龙,看你让大模型接什么,如果使用大模型接出来的东西。有点一生二、二生三、三生万物的意思,就好像无论汽油机、还是电动机,基本的动力输出形式是转圈圈,但是经过一些机械传导,可以转为各种机械运动形式:水平、垂直(打夯机)、椭圆运动等等,简单机械运动组合起来可以进行复杂机械运动比如纺织机,进而推动了大部分手工劳动的自动化。
- 在通用人工智能(AGI)的漫长旅途中,大模型虽显强大,仍存在着显著的技术天花板。许多人开始探索如何挖掘大模型在大任务执行能力上的可能性,其中一个基本策略就是能够分解和组合。例如,经典的 MapReduce 模式可以将一个大型文本进行摘要,因为它的上下文有限,一种解决办法是扩大 context 的范围。另一个解决方案是,在有限的 context 中,我们先将文本拆分成小片段,对每个片段进行摘要,然后再将其组合,从而得出结果。大家也发现大模型直接给出答案似乎并不靠谱,那么是否可以让它像人类一样,一步一步思考呢?毕竟,人类在解决问题时,也是逐渐构建解决方案,而并非立即给出答案。因此,开始出现了一系列的尝试解法,比如思维链、多思维链、思维树和思维图等。上述的讨论主要是任务分解和组合,他们尽管强大,却不能与外界进行互动,这就不得不讲到反馈机制了。反馈是整个控制论的基石,也是动物体从诞生之初就具备的基本能力。最经典的方法实际就是 ReACT,ReACT让大模型先进行思考,思考完再进行行动,然后根据行动的结果再进行观察,再进行思考,这样一步一步循环下去。这种行为模式基本上就是人类这样的智能体主要模式。
- 众人熟知的认知飞轮,感知、认知、决策、行动,今天的人工智能代理更像是基于这个认知飞轮构建的。但是从本质上,人类智能远比这复杂。
- 智能究竟是什么?人类对世界进行建模,把世界以实体、关系、属性描绘出来。然而,这也是我们认知的极限,我们只能理解一个对象化的世界,非对象化的世界我们无法理解。比如,当我们探索量子的时候,我们还常常用对事物进行对象化的方式去理解,但是发现我们的理解力有时候是有限的,因为量子世界的真相超出了人类认知能力的范围,我们智能使用低维空间的投影去推断它,就像我们无法在三维世界去想象十一维世界的样子。
- 其实在大模型Agent技术出现之前,人们就已经意识到,试图集成各种深度学习模型以实现人工普遍智能(AGI)并不够,还需要更高层次的认知模型。Agent都必须对世界有准确的理解才能做出正确的决策。当模型不能正确运行时,决策就会出错;只有当世界模型构建的正确,才能选择正确的模型,进而做出正确的决策。
- 今天计算机领域的工程实践中,人们更多采用的是面向过程架构,无论是接口、函数、UI界面,还是组件,又或者是一个应用程序,都是以接口的形式存在的。而这个接口实质上是一种被调用的子流程,借此过程的完成,我们希望执行结果符合我们的预期,但程序并不为结果负责。它解决的是过程和流程问题,系统内没有目标的概念。当然,也存在一些以目标导向为核心理念的的软件工程,例如声明式编程,它只需要你描述你想要什么,而无需关心执行的过程,像HTML和SQL便是其经典例子。在这样的架构下,程序能够自行寻找达成目标的方法。然而问题在于,这种面向目标的架构只能应用于垂直领域,而无法普遍应用到所有领域,只有在特定的领域内才能发挥作用,这就限制了它的应用范围。总的来说,尽管面向目标架构在计算机领域有一席之地,但由于其只能在特定领域发挥作用,而无法解决所有领域的问题,因此它的应用还是有所限制,更多出现在特定的DSL(领域特定语言)中,这种架构的确也发挥了巨大的作用。在软件工程的范式迁移中,我们发现面向过程架构与面向目标架构之间的重要区别点:随着人类的生产方式的变化,软件工程可能正逐步演化为智能体工程(Agent Engineering);以前我们主导的生产方式是人类处于中心位,AI做辅助。而未来可能会变成以 AI 为中心,人类变为辅助。由此,整个产品形态和平台的构成可能会发生这样的转变。
AgentLM:能打的 Agent 模型来了!开源模型并非没有完成智能体任务的能力,可能只是在智能体任务上缺乏对齐。对于 Agent 能力提升的策略,现有许多工作多使用 Prompt / 微调方法优化模型,在单项智能体任务上取得了卓越的表现,但智能体任务之间的促进及泛化效果有待进一步探索。智谱AI&清华KEG提出了一种对齐 Agent 能力的微调方法 AgentTuning,该方法使用少量数据微调已有模型,显著激发了模型的 Agent能力,同时可以保持模型原有的通用能力。AgentTuning 主要包括 2 个阶段。首先,我们收集并过滤得到一个多任务指令微调数据集 AgentInstrcut;然后,我们将 AgentInstruct 数据集与通用数据对模型进行混合微调。评估结果表明,AgentTuning 能让 LLM 的 Agent 能力在未见过的 Agent 任务中展现出强大的泛化,同时保持良好的通用语言能力。AgentInstruct 是一个经过筛选的智能体任务数据集。其包含 6 项智能体任务,从 Shell 交互到数据库操作,平均回合数从 5 到 35 不等,每条轨迹都有 ReAct 形式的 CoT 标注,帮助模型深入理解决策过程。PS: 大家发现Agent/react 有用,就微调LLM强化这方面的能力。
企业AI智能体、数字化与行业分工现代企业是由人和机器组成的。
- 人:负责完成复杂的、具有不确定性的任务。人是一种高度智能化的智能体。
- 机器(蓝色方形节点):负责完成简单的、确定性的任务。包括软件、设备等,属于工具。 于是,在这两类节点之间,就产生了三种关系:
- 人与人之间:沟通关系。为了完成企业的目标,企业内部的人和人之间需要通过沟通的方式来协作。可能是小团队内紧密的team work,也可能是跨团队之间的沟通,或者是上下级之间的沟通。
- 人与机器之间:人机交互。人和机器之间需要通过产品界面来交互。
- 机器与机器之间:API。机器与机器之间通过API调用来协作,它们之间沟通所使用的,属于机器语言。 人是智能体,机器是工具。AI智能体加入进来以后,它兼具智能体和工具两种属性:
- 半智能体:可以提供知识,且是海量的知识。
- 半工具:可以自动化调用真正的工具。甚至,现在以大模型为基础的AI智能体,还能将一定程度的规划工作也自动化掉。 AI智能体可能扮演三种角色:
- AI-0:直接参与业务流程自动化。作为自动化流程中的一个节点,完成以前只能由人完成的工作。需要与企业数据对接。场景举例:从文档中批量抽取信息;文档批量翻译;批量的数据挖掘、预测等。
- AI-1:作为提供知识的Copilot。不直接面向企业的业绩目标,作为人的辅助。需要与人频繁交互,通常以Chat的形式。不需要与企业数据对接。场景:知识问答、总结、文段翻译、数据可视化分析、公开文献阅读、写报告、画图表、写代码,以及其它的各种创作性任务,等等。ChatGPT承担的主要就是这种角色。
- AI-2:作为新型的人机交互接口。提供更自然的交互界面,主要也是Chat的形式。需要与企业数据对接。这一角色承担的任务可大可小。可以是简单的企业私有文档问答,用于替代传统的文档检索;也可以具备非常复杂的逻辑,成为企业大脑,驱动人机协作更有效率。场景:企业私域问答;用自然语言执行命令,查询企业内部数据,驱动自动化流程编排,等等。 理想的AI智能体产品形态,应该是AI-1和AI-2相结合的。用户既能从AI智能体获取企业外部的海量知识和专业数据,又能通过它与背后的企业内部数据或软件工具交互,让更多的工作由AI来完成。
下一代智能体发展的三大关键领域:规划、用户体验和记忆。
- 规划是指 AI 智能体能够预先考虑多个步骤,并确定最佳行动方案的能力。目前,语言模型的规划能力还比较有限,主要依靠以下两种方法来加强:
- 外部提示策略:开发者通过设计特定的提示,引导语言模型进行规划。例如,可以要求模型在执行每个步骤之前,先列出所有可能的步骤并进行评估。
- 流程工程:通过设计预定义的流程图或状态机,将任务分解成多个步骤,并明确每个步骤的执行条件和顺序。这可以帮助语言模型更好地理解任务,并做出更合理的规划。 未来,随着语言模型能力的提升,它们或许能够自主进行更有效的规划,而不再需要外部提示或流程工程的辅助。
- 目前,AI 智能体的用户体验仍有许多需要改进的地方,例如:
- 可靠性不足:由于语言模型的局限性,AI 智能体有时会犯错或无法理解用户的指令。这可能会导致用户感到沮丧和困惑。
- 可控性不足:用户往往无法完全控制 AI 智能体的行为,这可能会导致一些意外的后果。
- 缺乏个性化:现有的 AI 智能体大多缺乏个性化,无法根据用户的特定需求和偏好进行调整。
- 记忆是指 AI 智能体存储和使用信息的能力。记忆对于 AI 智能体完成各种任务都至关重要,例如:
- 程序记忆:记忆如何正确地执行任务,例如如何预订机票或如何撰写电子邮件。
- 个性化记忆:记忆与特定用户相关的信息,例如用户的姓名、喜好、经历等。 目前,AI 智能体的记忆功能还比较简单,主要依靠以下两种方式实现:存储在数据库中:将信息存储在外部数据库中,并在需要时进行检索。嵌入语言模型中:将信息嵌入语言模型的参数中,使模型能够在生成文本时使用这些信息。
规划与COT
- 什么是“语言智能”?语言智能可以被理解为“使用基于自然语言的概念对经验事物进行‘理解’以及在概念之间进行‘推理’的能力”,随着参数量的飞升,以 Transformer 为基础架构的大规模语言模型以 “Chat” 的方式逐渐向人们展现出了它的概念理解与概念推理的能力。直观上,作为“语言模型”的大模型具备概念理解能力并不难理解,但是仅仅像 Word2vec 一样只能得到“国王”与“男人”的“距离”更近的结论对于语言智能而言必然远远不够。真正引发人们对大模型逼近“语言智能”无限遐想的,在于大模型展现出的概念推理能力。推理,一般指根据几个已知的前提推导得出新的结论的过程,区别于理解,推理一般是一个“多步骤”的过程,推理的过程可以形成非常必要的“中间概念”,这些中间概念将辅助复杂问题的求解。
- 2022 年,在 Google 发布的论文《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》中首次提出,通过让大模型逐步参与将一个复杂问题分解为一步一步的子问题并依次进行求解的过程可以显著提升大模型的性能。而这一系列推理的中间步骤就被称为思维链(Chain of Thought)。区别于传统的 Prompt 从输入直接到输出的映射
<input——>output>
的方式,CoT 完成了从输入到思维链再到输出的映射,即<input——>reasoning chain——>output>
。如果将使用 CoT 的 Prompt 进行分解,可以更加详细的观察到 CoT 的工作流程。 - 在许多 Agent 需要处理的任务中,Agent 的“先天知识”并不包含解决任务的直接答案,因此 Agent 需要在一系列与外部环境的交互循环中,制定计划,做出决策,执行行动,收到反馈……在一整个计划、决策与控制的循环中,大模型需要具备“感知”,“记忆”与“推理”的能力。无论是环境的反馈,还是人类的指令,Agent 都需要完成一个对接收到的信息进行“理解”,并依据得到的理解进行意图识别,转化为下一步任务的过程。而使用 CoT 可以大大帮助模型对现有输入进行“感知”,譬如,通过使用“Answer: Let’s think step by step. I see $$, I need to …”的 Prompt,可以让模型逐步关注接收到的信息,对信息进行更好的理解。
现有方案如CoT和基于分解的提示,都有擅长的任务类型,适合作为独立的原子模块,不具有普适性;大模型自动推理?谷歌等发布SELF-DISCOVER!
使用
自定义tool 实现
from langchain.tools import BaseTool
# 天气查询工具 ,无论查询什么都返回Sunny
class WeatherTool(BaseTool):
name = "Weather"
description = "useful for When you want to know about the weather"
def _run(self, query: str) -> str:
return "Sunny^_^"
async def _arun(self, query: str) -> str:
"""Use the tool asynchronously."""
raise NotImplementedError("BingSearchRun does not support async")
# 计算工具,暂且写死返回3
class CustomCalculatorTool(BaseTool):
name = "Calculator"
description = "useful for when you need to answer questions about math."
def _run(self, query: str) -> str:
return "3"
async def _arun(self, query: str) -> str:
raise NotImplementedError("BingSearchRun does not support async")
# 这里使用OpenAI temperature=0,temperature越大表示灵活度越高,输出的格式可能越不满足我们规定的输出格式,因此此处设置为0
llm = OpenAI(temperature=0)
tools = [WeatherTool(), CalculatorTool()]
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
agent.run("Query the weather of this week,And How old will I be in ten years? This year I am 28")
# 执行结果
I need to use two different tools to answer this question
Action: Weather
Action Input: This week
Observation: Sunny^_^
Thought: I need to use a calculator to answer the second part of the question
Action: Calculator
Action Input: 28 + 10
Observation: 3
Thought: I now know the final answer
Final Answer: This week will be sunny and in ten years I will be 38.
LangChain Agent中,内部是一套问题模板(langchain-ai/langchain/libs/langchain/langchain/agents/chat/prompt.py):
PREFIX = """Answer the following questions as best you can. You have access to the following tools:"""
FORMAT_INSTRUCTIONS = """Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question"""
SUFFIX = """Begin!
Question: {input}
Thought:{agent_scratchpad}"""
这个提示词就是 Agent 之所以能够趋动大模型,进行思考 - 行动 - 观察行动结果 - 再思考 - 再行动 - 再观察这个循环的核心秘密。有了这样的提示词,模型就会不停地思考、行动,直到模型判断出问题已经解决,给出最终答案,跳出循环。
通过这个模板,加上我们的问题以及自定义的工具,会变成下面这个样子(# 后面是增加的注释)
Answer the following questions as best you can. You have access to the following tools: # 尽可能的去回答以下问题,你可以使用以下的工具:
Calculator: Useful for when you need to answer questions about math.
# 计算器:当你需要回答数学计算的时候可以用到
Weather: useful for When you want to know about the weather # 天气:当你想知道天气相关的问题时可以用到
Use the following format: # 请使用以下格式(回答)
Question: the input question you must answer # 你必须回答输入的问题
Thought: you should always think about what to do
# 你应该一直保持思考,思考要怎么解决问题
Action: the action to take, should be one of [Calculator, Weather] # 你应该采取[计算器,天气]之一
Action Input: the input to the action # 动作的输入
Observation: the result of the action # 动作的结果
... (this Thought/Action/Action Input/Observation can repeat N times) # 思考-行动-输入-输出 的循环可以重复N次
Thought: I now know the final answer # 最后,你应该知道最终结果了
Final Answer: the final answer to the original input question # 针对于原始问题,输出最终结果
Begin! # 开始
Question: Query the weather of this week,And How old will I be in ten years? This year I am 28 # 问输入的问题
Thought:
我们首先告诉 LLM 它可以使用的工具,在此之后,定义了一个示例格式,它遵循 Question(来自用户)、Thought(思考)、Action(动作)、Action Input(动作输入)、Observation(观察结果)的流程 - 并重复这个流程直到达到 Final Answer(最终答案)。如果仅仅是这样,openai会完全补完你的回答,中间无法插入任何内容。因此LangChain使用OpenAI的stop参数,截断了AI当前对话。"stop": ["\nObservation: ", "\n\tObservation: "]
。做了以上设定以后,OpenAI仅仅会给到Action和 Action Input两个内容就被stop停止。以下是OpenAI的响应内容:
I need to use the weather tool to answer the first part of the question, and the calculator to answer the second part.
Action: Weather
Action Input: This week
这里从Tools中找到name=Weather的工具,然后再将This Week传入方法。具体业务处理看详细情况。这里仅返回Sunny。 由于当前找到了Action和Action Input。 代表OpenAI认定当前任务链并没有结束。因此向tool请求后拼接结果:Observation: Sunny 并且让他再次思考Thought。开启第二轮思考:下面是再次请求的完整请求体:
Answer the following questions as best you can. You have access to the following tools:
Calculator: Useful for when you need to answer questions about math.
Weather: useful for When you want to know about the weather
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [Calculator, Weather]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Begin!
Question: Query the weather of this week,And How old will I be in ten years? This year I am 28
Thought: I need to use the weather tool to answer the first part of the question, and the calculator to answer the second part.
Action: Weather
Action Input: This week
Observation: Sunny^_^
Thought:
同第一轮一样,OpenAI再次进行思考,并且返回Action 和 Action Input 后,再次被早停。
I need to calculate my age in ten years
Action: Calculator
Action Input: 28 + 10
由于计算器工具只会返回3,结果会拼接出一个错误的结果,构造成了一个新的请求体进行第三轮请求:
Answer the following questions as best you can. You have access to the following tools:
Calculator: Useful for when you need to answer questions about math.
Weather: useful for When you want to know about the weather
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [Calculator, Weather]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Begin!
Question: Query the weather of this week,And How old will I be in ten years? This year I am 28
Thought: I need to use the weather tool to answer the first part of the question, and the calculator to answer the second part.
Action: Weather
Action Input: This week
Observation: Sunny^_^
Thought:I need to calculate my age in ten years
Action: Calculator
Action Input: 28 + 10
Observation: 38
Thought:
此时两个问题全都拿到了结果,根据开头的限定,OpenAi在完全拿到结果以后会返回I now know the final answer。并且根据完整上下文。把多个结果进行归纳总结:下面是完整的相应结果:
I now know the final answer
Final Answer: I will be 38 in ten years and the weather this week is sunny.
可以看到。ai严格的按照设定返回想要的内容,并且还以外的把28+10=3这个数学错误给改正了。通过 verbose=True
可以动态查看上述过程。 PS: 通过prompt 引导llm 进行文字接龙,通过解析文字接龙来进行tool 的调用。
根据输出再回头看agent的官方解释:An Agent is a wrapper around a model, which takes in user input and returns a response corresponding to an “action” to take and a corresponding “action input”. 本质上是通过和大模型的多轮对话交互来实现的(对比常规聊天时的一问一答/单轮对话), 不断重复“Action+ Input -> 结果 -> 下一个想法”,一直到找到最终答案。通过特定的提示词引导LLM模型以固定格式来回复,LLM模型回复完毕后,解析回复,这样就获得了要执行哪个tool,以及tool的参数。然后就可以去调tool了,调完把结果拼到prompt中,然后再让LLM模型根据调用结果去总结并回答用户的问题。
大多数 Agent 主要是在某种循环中运行 LLM。目前,我们使用的唯一方法是 AgentExecutor。我们为 AgentExecutor 添加了许多参数和功能,但它仍然只是运行循环的一种方式。langgraph是一个新的库,旨在创建语言 Agent 的图形表示。这将使用户能够创建更加定制化的循环行为。用户可以定义明确的规划步骤、反思步骤,或者轻松设置优先调用某个特定工具。
原理
在 Agent 应用的开发和实践中,核心挑战之一是如何优雅地实现一个可控的循环(Loop)机制。这个循环机制不仅需要能够自动化地执行任务,还要能够在执行过程中根据反馈进行自我调整和优化(Loop+Feedback )。通过这种方式,LLM 能够模仿人类解决问题的基本方法论,如 PDCA(计划-执行-检查-行动)循环,从而更有效地拆解和解决问题。
认知框架Cognitive Architecture
AgentType 对应一个Agent class,对应一个prompt(又是prompt 起了关键作用),AgentType 有以下几种选择
- zero-shot ReAct,完全依靠对所用到的tools 的说明书来理解和使用tools,理论上支持无限多个。
- Structured tool chat,跟第一个不同的地方在于接收一个结构化的dict 作为参数且能记住上下文。
- OpenAI functions,OpenAI 在大模型层面针对 API的调用做了训练,相当于帮大家做了SFT,可以想象效果必然好。
- conversational,类似于第一、二类型,针对对话场景做了优化,比如聊天记录、聊天轮次等meta-data
- self-ask,通过自问自答的方式把大问题拆解成小问题之后再组成最终的单子。
ReAct是 Shunyu Yao 等人在 ICLR 2023 会议论文《ReAct: Synergizing Reasoning and Acting in Language Models》中提出的,一个关键启发在于:大语言模型可以通过生成推理痕迹和任务特定行动来实现更大的协同作用。具体来说,就是引导模型生成一个任务解决轨迹:观察环境 - 进行思考 - 采取行动,也就是观察 - 思考 - 行动。那么,再进一步进行简化,就变成了推理 - 行动。ReAct 框架会提示 LLMs 为任务生成推理轨迹和操作,这使得代理能系统地执行动态推理来创建、维护和调整操作计划,同时还支持与外部环境(例如 Google 搜索、Wikipedia)的交互,以将额外信息合并到推理中。PS:使用LLM来做ifelse,ReAct提示大型语言模型为给定任务生成口头推理历史步骤和操作。这些提示由少量的上下文示例组成,这些示例指导模型的思考和操作生成。
与CoT推理一样,ReAct 也是一种提示工程方法,它使用少量学习来教模型如何解决问题。CoT 被认为是模仿人类如何思考问题,ReAct 也包括了这个推理元素,但它更进一步,允许Agent操作文本,让它与环境互动。人类使用语言推理来帮助我们制定策略并记住事情,但也可以采取行动来获得更多的信息并实现目标。这就是 ReAct 的基础(PS:知行合一?)。ReAct 提示包括行动的例子、通过行动获得的观察结果,以及人类在过程中各个步骤中转录的思想(推理策略)。LLM 学习模仿这种交叉思考和行动的方法,使其成为其环境中的Agent。
一定要记住,观察结果不是由 LLM 生成的,而是由环境生成的,环境是一个单独的模块,LLM 只能通过特定的文本操作与之交互。因此,为了实现 ReAct,需要:
- 一种环境,它采取一个文本操作, 从一组可以根据环境的内部状态改变的潜在操作中返回一个文本观察。
- 一个输出解析器框架,一旦Agent编写了一个有效的操作,它就停止生成文本,在环境中执行该操作,并返回观察结果, 一般是将其追加到目前生成的文本中,并用该结果提示 LLM。
- 人工产生的示例,混合了思想,行动和观察,在环境中可以使用few-shot,例子的数量和细节取决于目标和开发者的设计
stop token
How to Get Better Outputs from Your Large Language ModelIt is especially useful to design a stopping template in a few-shot setting so the model can learn to stop appropriately upon completing an intended task. Figure shows separating examples with the string “===” and passing that as the stop word.我们知道一般 LLM 都会长篇大论,说一大堆废话,我们希望 LLM 在返回了我们需要的信息后就停止输出,这里就需要用到stop参数,这个参数是一个列表,列表中的每个元素都是一个字符串,代表了 LLM 输出中的某一句话,当 LLM 输出中包含了这句话时,LLM 就会停止输出,这样我们就可以只获取到我们需要的信息了
源码
langchain
/agents
/agent.py # BaseSingleActionAgent/BaseMultiActionAgent/AgentOutputParser/LLMSingleActionAgent/Agent/AgentExecutor
LangChain关键组件
- 代理(Agent):这个类决定下一步执行什么操作。它由一个语言模型和一个提示(prompt)驱动。提示可能包含代理的性格(也就是给它分配角色,让它以特定方式进行响应)、任务的背景(用于给它提供更多任务类型的上下文)以及用于激发更好推理能力的提示策略(例如 ReAct)。LangChain 中包含很多种不同类型的代理。PS: 一般情况下,一个Agent 像Chain一样,都会对应一个prompt。
- 工具(Tools):工具是代理调用的函数。这里有两个重要的考虑因素:一是让代理能访问到正确的工具,二是以最有帮助的方式描述这些工具。如果你没有给代理提供正确的工具,它将无法完成任务。如果你没有正确地描述工具,代理将不知道如何使用它们。LangChain 提供了一系列的工具,同时你也可以定义自己的工具。
- 代理执行器(AgentExecutor):代理执行器是代理的运行环境,它调用代理并执行代理选择的操作。执行器也负责处理多种复杂情况,包括处理代理选择了不存在的工具的情况、处理工具出错的情况、处理代理产生的无法解析成工具调用的输出的情况,以及在代理决策和工具调用进行观察和日志记录。AgentExecuter负责迭代运行Agent,直至满足设定的停止条件,这使得Agent能够像生物一样循环处理信息和任务。PS: Agent 只负责决策,不负责执行。
AgentExecutor由一个Agent和Tool的集合组成。AgentExecutor负责调用Agent,获取返回(callback)、action和action_input,并根据意图将action_input给到具体调用的Tool,获取Tool的输出,并将所有的信息传递回Agent,以便猜测出下一步需要执行的操作。AgentExecutor.run也就是chain.run ==> AgentExecutor/chain.__call__ ==> AgentExecutor._call()
和逻辑是 _call 方法,核心是 `output = agent.plan(); tool=xx(output); observation = tool.run();
def initialize_agent(tools,llm,...)-> AgentExecutor:
agent_obj = agent_cls.from_llm_and_tools(llm, tools, callback_manager=callback_manager, **agent_kwargs)
AgentExecutor.from_agent_and_tools(agent=agent_obj, tools=tools,...)
return cls(agent=agent, tools=tools, callback_manager=callback_manager, **kwargs)
# AgentExecutor 实际上是一个 Chain,可以通过 .run() 或者 _call() 来调用
class AgentExecutor(Chain):
agent: Union[BaseSingleActionAgent, BaseMultiActionAgent]
tools: Sequence[BaseTool]
"""Whether to return the agent's trajectory of intermediate steps at the end in addition to the final output."""
max_iterations: Optional[int] = 15
def _call(self,inputs: Dict[str, str],...) -> Dict[str, Any]:
while self._should_continue(iterations, time_elapsed):
next_step_output = self._take_next_step(name_to_tool_map,inputs,intermediate_steps,...)
# 返回的数据是一个AgentFinish类型,表示COT认为不需要继续思考,当前结果就是最终结果,直接将结果返回给用户即可;
if isinstance(next_step_output, AgentFinish):
return self._return(next_step_output, intermediate_steps, run_manager=run_manager)
if len(next_step_output) == 1:
next_step_action = next_step_output[0]
# See if tool should return directly
tool_return = self._get_tool_return(next_step_action)
if tool_return is not None:
return self._return(tool_return, intermediate_steps, run_manager=run_manager)
iterations += 1
time_elapsed = time.time() - start_time
return self._return(output, intermediate_steps, run_manager=run_manager)
def _take_next_step(...):
# 调用LLM决定下一步的执行逻辑
output = self.agent.plan(intermediate_steps,**inputs,...)
if isinstance(output, AgentFinish): # 如果返回结果是AgentFinish就直接返回
return output
if isinstance(output, AgentAction): # 如果返回结果是AgentAction,就根据action调用配置的tool
actions = [output]
result = []
for agent_action in actions:
tool = name_to_tool_map[agent_action.tool]
observation = tool.run(agent_action.tool_input,...)
result.append((agent_action, observation)) # 调用LLM返回的AgentAction和调用tool返回的结果(Obversation)一起加入到结果中
return result
Agent.plan() 可以看做两步:
- 将各种异构的历史信息转换成 inputs,传入到 LLM 当中;
- 根据 LLM 生成的反馈,采取决策。LLM 生成的回复是 string 格式,langchain 中ZeroShotAgent 通过字符串匹配的方式来识别 action。
因此,agent 能否正常运行,与 prompt 格式,以及 LLM 的 ICL 以及 alignment 能力有着很大的关系。
- LangChain主要是基于GPT系列框架进行设计,其适用的Prompt不代表其他大模型也能有相同表现,所以如果要自己更换不同的大模型(如:文心一言,通义千问…等)。则很有可能底层prompt都需要跟著微调。
- 在实际应用中,我们很常定期使用用户反馈的bad cases持续迭代模型,但是Prompt Engeering的工程是非常难进行的微调的,往往多跟少一句话对于效果影响巨大,因此这类型产品达到80分是很容易的,但是要持续迭代到90分甚至更高基本上是很难的。
# 一个 Agent 单元负责执行一次任务
class Agent(...):
llm_chain: LLMChain
allowed_tools: Optional[List[str]] = None
# agent 的执行功能在于 Agent.plan()
def plan(self,intermediate_steps: List[Tuple[AgentAction, str]],callbacks: Callbacks = None,**kwargs: Any,) -> Union[AgentAction, AgentFinish]:
# # 将各种异构的历史信息转换成 inputs,传入到 LLM 当中
full_inputs = self.get_full_inputs(intermediate_steps, **kwargs)
# 根据 LLM 生成的反馈,采取决策
full_output = self.llm_chain.predict(callbacks=callbacks, **full_inputs)
# full_output 是纯文本,通过断点调试可以看到,真的就是靠正则表达式提取tool的名称
# 最后的输出 AgentAction 中会包括:需要使用的 tool,使用该 tool 时候,对应的执行命令。
return self.output_parser.parse(full_output)
有人希望通过一些开源的 LLM 来实现 ReAct Agent,但实际开发过程中会发现开源低参数(比如一些 6B、7B 的 LLM)的 LLM 对于提示词的理解会非常差,根本不会按照提示词模板的格式来输出(例如不按Action: xx Action Input: xx
返回),这样就会导致我们的 Agent 无法正常工作,所以如果想要实现一个好的 Agent,还是需要使用好的 LLM,目前看来使用gpt-3.5模型是最低要求。
从文本补全到做决策写代码
Function Calling
ChatGLM3 的工具调用(FunctionCalling)实现原理
2023.6.13 OpenAI 在chat completion 模型中加入Function calling,代表着Chat模型不再需要借助LangChain框架就可以直接在模型内部调用外部工具API,从而更加快捷的构建以LLM为核心的AI应用程序。
使用Function Call功能时,你需要定义(并不是真的写程序去定义一个函数,而仅仅是用文字来描述一个函数)一些function(需要指定函数名,函数用途的描述,参数名,参数描述),传给LLM,当用户输入一个问题时,LLM通过文本分析是否需要调用某一个function,如果需要调用,那么LLM返回一个json,json包括需要调用的function名,需要输入到function的参数名,以及参数值。本质上是LLM(按特定意图)帮我们在做个文本结构化。实现上,把json格式的函数描述直接转换成了字符串,然后和其他输入一并送入LLM,归根到底function call能力就是在prompt上边做了手脚,微调时候有function call格式的数据。
以查询天气为例,当我们在openai的请求里添加了funtions相关的字段,他会增加一个判断是否需要调用function的环节。
func = {
"name": "get_current_weather",
"description": "获取今天的天气",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "获取天气情况的城市或者国家,比如北京、东京、新加坡"
},
"time": {
"type": "string",
"description": "时间信息"
},
},
"required": ["location", "time"]
}
}
以下以向ChatGPT输入“10月27日北京天气怎么样”为例:
- 请求里没有functions字段得到的结果如下,他会告诉你一大段答案(应该是假的),就是走Chatgpt正常的回答。
根据天气预报,10月27日北京的天气预计为晴到多云,气温较低。最高气温约为16摄氏度,最低气温约为4摄氏度。需要注意保暖措施,适时添衣物。
- 请求里如果有functions字段,返回了一个json,并帮我们从输入文本里抽取了get_current_weather所需要的location和time的函数值
{ 'name': 'get_current_weather', 'arguments': '{ "location": "北京", "time": "2021-10-27" }' }
OpenAI 原生调用 ```python functions = [ { “name”: “get_pizza_info”, “description”: “Get name and price of a pizza of the restaurant”, “parameters”: { “type”: “object”, “properties”: { “pizza_name”: { “type”: “string”, “description”: “The name of the pizza, e.g. Salami”, }, }, “required”: [“pizza_name”], }, } ] def chat(query): openai.api_base = “http://localhost:8000/v1” openai.api_key = “none” response = openai.ChatCompletion.create( model=”chatglm3-6b”, messages=[{“role”: “user”, “content”: query}], functions=functions, ) message = response[“choices”][0][“message”] # MESSAGE IN MEESAGE OUT return message
if name == “main”:
resp = chat(“What is the capital of france?”)
print(resp)
resp = chat(“How much does pizza salami cost?”)
print(resp)
# content=”get_pizza_info\n python\ntool_call(pizza_name='Salami')\n
” additional_kwargs={‘function_call’: {‘name’: ‘get_pizza_info’, ‘arguments’: ‘{“pizza_name”: “Salami”}’}}
结合langchain调用
```python
from langchain import LLMMathChain
from langchain.agents import AgentType
from langchain.agents import initialize_agent, Tool
class PizzaTool(BaseTool):
name = "get_pizza_info"
description = "Get name and price of a pizza of the restaurant"
def _run(
self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None
) -> str:
pizza_info = {
"name": query,
"price": "10.99",
}
return json.dumps(pizza_info)
async def _arun(
self, query: str, run_manager: Optional[AsyncCallbackManagerForToolRun] = None
) -> str:
"""Use the tool asynchronously."""
raise NotImplementedError("pizza tool does not support async")
llm = ChatOpenAI(temperature=0, model="chatglm3-6b")
tools = [
PizzaTool()
]
agent = initialize_agent(tools, llm, agent=AgentType.OPENAI_FUNCTIONS, verbose=True)
resp = gent.run("What is the capital of france?")
print(resp)
# The capital of France is Paris. Enjoy your pizza!
resp = agent.run("How much does pizza salami cost?")
print(resp)
# The cost of a pizza salami at this restaurant is $10.99.
从源码上,不得不佩服 AgentExecutor 和 Agent 抽象的前瞻性,OPENAI_FUNCTIONS对应的 OpenAIFunctionsAgent直接返回了tool 的名字及参数,不用再通过Prompt 诱导llm 按照特定格式响应,再从响应中截取tool的名字,也因此OpenAIFunctionsAgent 不再需要对应配套一个 prompt。
class OpenAIFunctionsAgent(BaseSingleActionAgent):
@property
def functions(self) -> List[dict]:
return [dict(format_tool_to_openai_function(t)) for t in self.tools]
def plan(self,...) -> Union[AgentAction, AgentFinish]:
full_inputs = dict(**selected_inputs, agent_scratchpad=agent_scratchpad)
prompt = self.prompt.format_prompt(**full_inputs)
messages = prompt.to_messages()
predicted_message = self.llm.predict_messages(messages,functions=self.functions,callbacks=callbacks,)
agent_decision = _parse_ai_message(predicted_message)
return agent_decision
代码解释器
ChatGLM3 的代码解释器(Code Interpreter)实现原理:背后的原理其实跟工具调用是一样的。无非就是将普通的函数替换成代码解释器,大模型预测的结果不再是函数的入参,而是具体的代码,根据这些代码我们调用代码解释器执行,然后在界面上面支持显示代码执行的结果。
要了解大模型是如何学会使用代码解释器的,就要先看训练样本是如何构造的。下面是一个官方提供的例子:
<|system|> 你是一位智能AI助手,你叫ChatGLM3,你连接着一台电脑,但请注意不能联网。在使用Python解决任务时,你可以运行代码并得到结果,如果运行结果有错误,你需要尽可能对代码进行改进。你可以处理用户上传到电脑上的文件,文件默认存储路径是/mnt/data/。 <|user|> 帮我画一个爱心 <|assistant|>interpreter ```python import numpy as np import matplotlib.pyplot as plt # 爱心形状的参数方程 def heart(t): x = 16 * np.sin(t) ** 3 y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t) return x, y t = np.linspace(0, 2 * np.pi, 1000) x, y = heart(t) plt.figure(figsize=(6, 6)) plt.plot(x, y, color='red') plt.axis('equal') plt.axis('off') plt.show() ``` <|observation|> ```result 【image】 ``` <|assistant|> 这是一个爱心形状。我使用了参数方程来描述这个形状,并使用matplotlib进行了绘制。如果您有任何其他需求或问题,请随时告诉我。 <|user|> # End
AgentTuning
finetune 就是让LLM “更懂”特定的instruction。 AGENTTUNING:为LLM启用广义的代理能力 有一点粗糙。工具调用能力的获得离不开模型微调,不同于通过Prompt 诱导llm 按照特定格式 响应tool的名字,通过特定的训练样本(可以练习)强化llm 返回tool的名字(和tool调用参数)。ChatGLM3的训练工具调用的样本数据是如何构造的?
<|system|> Answer the following questions as best as you can. You have access to the following tools: [ { "name": "get_current_weather", "description": "Get the current weather in a given location", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "The city and state, e.g. San Francisco, CA", }, "unit": {"type": "string"}, }, "required": ["location"], }, } ] <|user|> 今天北京的天气怎么样? <|assistant|> 好的,让我们来查看今天的天气 <|assistant|>get_current_weather ```python tool_call(location="beijing", unit="celsius") ``` <|observation|> {"temperature": 22} <|assistant|> 根据查询结果,今天北京的气温为 22 摄氏度。
AutoGPT
Andrej Karpathy 在 2017 年提出的 Software 2.0:基于神经网络的软件设计。真的很有前瞻性了。这进一步引出了当前正在迅速发展的 Agent Ecosystem。AutoGPT ,BabyAGI 和 HuggingGPT 这些项目形象生动地为我们展示了 LLM 的潜力除了在生成内容、故事、论文等方面,它还具有强大的通用问题解决能力。如果说 ChatGPT 本身的突破体现在人们意识到语言可以成为一种服务,成为人和机器之间最自然的沟通接口,这一轮新发展的关键在于人们意识到语言(不一定是自然语言,也包括命令、代码、错误信息)也是模型和自身、模型和模型以及模型和外部世界之间最自然的接口,让 AI agent 在思考和表达之外增加了调度、结果反馈和自我修正这些新的功能模块。于是在人类用自然语言给 AI 定义任务目标(只有这一步在实质上需要人类参与)之后可以形成一个自动运行的循环:
- agent 通过语言思考,分解目标为子任务
- agent 检讨自己的计划
- agent 通过代码语言把子任务分配给别的模型,或者分配给第三方服务,或者分配给自己来执行
- agent 观察执行的结果,根据结果思考下一步计划,回到循环开始
原生的 ChatGPT 让人和 AI 交流成为可能,相当于数学归纳法里 n=0 那一步。而新的 agent ecosystem 实现的是 AI 和自己或者其他 AI 或者外部世界交流,相当于数学归纳法里从 n 推出 n+1 那一步,于是新的维度被展开了。比如将机器人强大的机械控制能力和目前 GPT-4 的推理与多模态能力结合,也许科幻小说中的机器人将在不久成为现实。
与Chains依赖人脑思考并固化推理过程的做法不同,AutoGPT是一个基于GPT-4语言模型的、实验性的开源应用程序,可以根据用户给定的目标,自动生成所需的提示,并执行多步骤的项目,无需人类的干预和指导(自己给自己提示)。AutoGPT的本质是一个自主的AI代理,可以利用互联网、记忆、文件等资源,来实现各种类型和领域的任务。这意味着它可以扫描互联网或执行用户计算机能够执行的任何命令,然后将其返回给GPT-4,以判断它是否正确以及接下来要做什么。下面举一个简单的例子,来说明AutoGPT的运行流程。假设我们想让AutoGPT帮我们写一篇关于太空的文章,我们可以给它这样的一个目标:“写一篇关于太空的文章”。然后AutoGPT会开始运行,它会这样做:
- AutoGPT会先在PINECONE里面查找有没有已经写好的关于太空的文章,如果有,它就会直接把文章展示给我们,如果没有,它就会继续下一步。
- AutoGPT会用GPT-4来生成一个提示,比如说:“太空是什么?”,然后用GPT-4来回答这个提示,比如说:“太空是指地球大气层之外的空间,它包含了许多星球,卫星,彗星,小行星等天体。”
- AutoGPT会把生成的提示和回答都存储在PINECONE里面,并且用它们来作为文章的第一段。
- AutoGPT会继续用GPT-4来生成新的提示,比如说:“太空有什么特点?”,然后用GPT-4来回答这个提示,比如说:“太空有很多特点,比如说,太空没有空气,没有重力,没有声音,温度变化很大等等。”
- AutoGPT会把生成的提示和回答都存储在PINECONE里面,并且用它们来作为文章的第二段。
- AutoGPT会重复这个过程,直到它觉得文章已经足够长或者足够完整了,或者达到了一定的字数限制或者时间限制。
- AutoGPT会把最终生成的文章展示给我们,并且询问我们是否满意。如果我们满意,它就会结束运行;如果我们不满意,它就会根据我们的反馈来修改或者补充文章。
agent = SimpleAgent.from_workspace(agent_workspace, client_logger)
print("agent is loaded")
plan = await agent.build_initial_plan()
print(parse_agent_plan(plan))
while True:
current_task, next_ability = await agent.determine_next_ability(plan)
print(parse_next_ability(current_task, next_ability)
user_input = click.prompt("Should the agent proceed with this ability?", default = "y")
ability_result = await agent.execute_next_ability(user_input)
print(parse_ability_result(ability_result))
探索AI时代的应用工程化架构演进,一人公司时代还有多远?在冯诺依曼架构或者哈佛架构设备的实际开发中,我们会去关心如何使用相应协议去寻址去读写总线操作不同设备,如UART、I2C、SPI总线协议,这都是我们要学习掌握的,但我们基本不会关心CPU中的CU、ALU等单元。计算机架构这样求同存异的继续发展下去,将这些单元与高速存储及总线等作为抽象概念去进一步封装。而AI应用也是类似的,Agent会将相关的规划反思改进能力不断的作为自身的核心能力封装。因此,对于未来的AI应用极有可能不是在传统计算机上运行的程序,而是标准化的需求,在以规划能力专精的Agent 大模型作为CPU的AI计算机虚拟实例上直接运行的,而我们今天所谈论的应用架构,也会沉积到底层转变为AI计算机的核心架构。最终AI计算机将图灵完备,通过AI的自举将迭代产物从工程领域提升到工业领域。
多Agent框架
智能体的发展:从单任务到多代理协同与人代理交互。
AutoGen、ChatDev、CrewAI CrewAI:一个集众家所长的MutiAgent框架 PS: 你要是上万个tool的话,llm 上下文塞不下,此时让一个llm 针对一个问题决策使用哪一个tool 就很难(ToolLLaMa已经支持16k+了),此时很自然的就需要多层次的Agent,低层次的Agent 更专业聚焦一些。
应用
大佬:这一波Agent热潮爆发,其实是LLM热情的余波,大家太希望挖掘LLM潜力,为此希望LLM担任各方面的判断。但实际上有一些简单模块是不需要LLM的,不经济也不高效。例如我们要抽取每轮对话的情绪,可以用LLM,其实也可以用情绪识别模型。例如我们希望将长对话压缩后作为事件记忆存储,可以用LLM,也可以用传统摘要模型,一切只看是否取得ROI的最佳平衡,而不全然指望LLM。
- 创作与生成类助手,简单的借助Prompt工程即可实现
- 企业知识助手,本质上也是一种提示工程:借助于在大模型输入时携带相关的私有知识上下文,让大模型理解、总结、整理并回答用户问题。只是这里的私有知识上下文需要借助嵌入模型(Embedding Model)、向量数据库(Vector Store)、文档加载分割(Document Loader&Splitter)等相关技术来获得。
- 数据分析助手,基本以三种方式为主:自然语言转API、转SQL、以及代码解释器(转代码)。DB-GPT、OpenAgents、OpenInterpreter
- 应用/工具助手,能够把自然语言转换成对企业应用或者互联网开放API调用的一种基础Agent形式。比如:如果你需要AI帮你在协同办公系统中提交一个付款申请,那么你需要调用办公系统的接口;当然,在复杂任务场景下的这种调用往往不是单一的,复杂性主要体现在大模型对自然语言转API的能力:能否根据上下文理解,精确匹配到需要使用的API(一个或者多个);能否准确地提取或生成每个API的调用参数。LangChain、Assistants API、OpenAgents。
- Web操作助手,主要能力是自动化Web网络浏览、操作与探索的动作与过程,以简化web浏览访问与操作。对于个人来说,可以作为个人数字助理,简单对话即可让AI帮你完成Web浏览与操作,比如在线订票。而对于企业来说,则可以作为企业的数字员工,来简化企业日常工作中重复性较高、流程与规则固定、大批量的前端操作性事务。比如批量订单处理、批量客户联络、批量网站抓取等,提高效率,降低错误率。传统的RPA机器人也是用来完成此类工作的AI形式,由于这种AI机器人工作在软件的最上层即操作层面,好处是流程直观、简单、也可以配置化,且对应用无侵入性;但其缺点是与前端应用耦合性大,每个任务需要根据前端应用界面做精心配置与调试,自适应能力较差。在大模型出现以后,给这一类RPA智能也带来了新的优化空间。
- 自定义流程助手,严格来说是上面的几种基础Agent能力的组合,理想中的AI Agent是在丢给他一个工具包与一些知识以后,借助于大模型的理解、推理能力,完全自主的规划与分解任务,设计任务步骤,并智能的使用各种工具,检索知识,输出内容,完成任务。但是在企业应用中,由于企业知识、应用、业务需求的千差万别,以及大模型自身的不确定性,如果这么做,那么结果很可能是“开盲盒”一样的不可控。所以这也是越来越多的Agents项目要强调可控性的原因,即能够对AI智能体的执行过程与细节进行更多的控制,来让AI按照人类确认过的工作流程来完成任务。 PS: 人规定流程 + 单个步骤代码化(有些场景代码无法实现 或 个性化成本太高) ==> 人规定流程 + 单个步骤智能化 ==> 自动分析流程 + 单个步骤智能化
从需求满足的角度来聊一聊:我们首先以“用户去某地旅游”为需求来解释LLM、RAG、Agent三者的能力边界以及需求满足度。
- LLM:能够生成“无法考证可能正确”以及“不一定及时”的相关行程攻略,景点等信息。
- RAG:能够检索一些时效性高、内容可靠的信息源的内容,并生成相关的行程信息。PS:看能召回什么内容了
- Agent:能够基于用户的需求目标完成,通过使用各种工具和系统交互完成攻略制定,订票,制定行程日历等过程任务。PS:先去搜一些攻略,再去订酒店 ==> 从景色、经济、时间等各个角度做一些对比。
其它
一句指令帮你操作手机,最新多模态手机助手Mobile-Agent来了!为了便于将文本描述的操作转化为屏幕上的操作,Mobile-Agent生成的操作必须在一个定义好的操作空间内。这个空间共有8个操作,分别是:打开App(App名字);点击文本(文本内容);点击图标(图标描述);打字(文本内容);上翻、下翻;返回上一页;退出App;停止。点击文本和点击图标设计了输入参数。
- 在迭代开始之前,用户需要输入一个指令。我们根据指令生成整个流程的系统提示。在每次迭代开始时,Mobile-Agent会获取手机屏幕的截图,通过观察系统提示、操作历史和当前屏幕截图,输出下一步操作。如果Mobile-Agent输出的是结束,则停止迭代;否则,继续新的迭代。Mobile-Agent利用操作历史记录了解当前任务的进度,并根据系统提示对当前屏幕截图进行操作,从而实现迭代式自我规划流程。
- 在迭代过程中,Mobile-Agent可能会遇到错误,导致无法完成指令。为了提高指令的成功率,我们引入了一种自我反思方法。这种方法将在两种情况下生效。第一种情况是生成了错误或无效的操作,导致进程卡住。当Mobile-Agent注意到某个操作后截图没有变化,或者截图显示了错误的页面时,它会尝试其他操作或修改当前操作的参数。第二种情况是忽略某些复杂指令的要求。当通过自我规划完成所有操作后,Mobile-Agent会分析操作、历史记录、当前截图和用户指令,以确定指令是否已完成。如果没有,它需要继续通过自我规划生成操作。
别指望 AI 一次生成,其实不论是文本生成,还是代码生成,都涉及到生成式 AI 的能力问题:
- 用户无法提供所有上下文给模型。既然能提供,提供的成本往往过高(大于 AI 生成的时间)
- 模型无法理解你提供的所有上下文。