计算机系统应用教程网站

网站首页 > 技术文章 正文

使用promptulate框架&百度大模型 V4探究AI agent模式

btikc 2024-09-24 08:24:43 技术文章 20 ℃ 0 评论

大模型 LLM 提供了强大的 NLP 及文本生成能力,但是对复杂任务的处理就没有那么得心应手了,基于这个实际需求就诞生了 AI agent 模式,我先后接触并详细研究了 2 个开源的 AI agent 框架,分别是大名鼎鼎的 LangChain 和国产的 promptulate,今天就重点说说 promptulate,虽然他在不断的迭代升级阶段,但是他的架构思想还是非常复杂 AI agent 核心理念的。

要想用好 LLM 这两个工具必须掌握,一个是 prompt(提示词),一个是 AI agent,而且 prompt 是基础,是能否让AI agent精确分解复杂任务的关键,prompt 起到 AI agent 和 LLM 对话的翻译器。

AI agent 就是从一个任务出发,通过和 LLM 的多次交互,把这个任务逐步分解为多个子任务,再把这些子任务交付给不同的模块完成,有的模块是已经有第三方提供的能力,有些就需要开发者自行完成,这就给应用开发提供了很多便利的条件。AI agent 就类似一个指挥调度中心,借助于 LLM 这个 AI 来进行辅助决策。

多任务协同说起来简单,但是让人直观理解还是要费些思量的,我从事多年微服务架构的开发,所以我认为 AI agent 的架构类似于微服务架构,都是将复杂任务拆解为多个可以协同的简单任务来综合完成,我最喜欢用的例子就是计算一个四则运算的复杂表达式,下面就用这个例子详细介绍 AIagent 的架构思想和如何使用promptulate 及百度新发布的 V4 LLM 来实现。

问题:使用 LLM 计算类似 a0+a1*a2-a3+a4/a5的四则运算结果

思考:

  1. 规则描述,遵循基本的四则运算规则,即先乘除,后加减,相同优先级时从左到右
  2. 任务分解,按照规则将表达式拆解为若干个独立的+,-,*,/运算,分别定义加法、减法、乘法、除法运算,再按照计算的优先顺序多次运用这些独立的算法,知道完成所有计算
  3. 为什么要自行开发计算模块,LLM 严格说是语言概率模型,本身不具备计算能力,所以涉及的计算和逻辑最好利用现有的技术成果或者自行开发,下面就是一个简单的示例:同样的四则运算技术问题,文心一言给出的答案并不正确!

支持系统选型:

  1. LLM 选择百度大模型ErnieBot-V4
  2. AI agent 框架选择 promptulate

前期准备:

  1. 在百度智能云开通千帆大模型的开发者账号,申请文心大模型4.0的邀测权限,如果没有也可以开通 3.5 版本的权限,使用方法一致
  2. 安装 promptulate

pip install promptulate

完整代码:

# 使用promptulate框架开发LLM agent

from promptulate.llms import ErnieBot

import os


from promptulate.agents import ToolAgent

from promptulate.tools import define_tool

from promptulate.utils.logger import enable_log

from promptulate.hook import Hook

import time


os.environ["ERNIE_API_KEY"] = "zQ3fMzn?????H7QeclgDQm"

os.environ["ERNIE_API_SECRET"] = "MDW1?????GEKESRA8qTpxwfs"


@Hook.on_tool_create(hook_type="instance")

def handle_tool_create(*args, **kwargs):

print("math tool component create")


@Hook.on_tool_start(hook_type="instance")

def handle_tool_start(*args, **kwargs):

prompt = args[0]

print(f"math tool instance hook start, user prompt: {prompt}")


@Hook.on_tool_result(hook_type="instance")

def handle_tool_result(**kwargs):

result = kwargs["result"]

print(f"math tool component result: {result}")


# 识别字符串中的分隔符,然后再按照分隔符隔离数据

def split_str(query: str):

# 判断 query 中是否包含+,-,*,/字符,如果包含,则判断包含那个

if '+' in query:

datas=query.split('+')

elif '-' in query:

datas=query.split('-')

elif '*' in query:

datas=query.split('*')

elif '/' in query:

datas=query.split('/')

elif ',' in query:

datas=query.split(',')

# 去掉datas中每个数据的前后'号和空格

datas=[d.strip().strip("\'") for d in datas]

# 把 datas 里边的字符串转化为 float

datas=[float(d) for d in datas]

return datas


# 自定义加法工具

def addition(query:str):

if not query:

return -1

if query.startswith('[') and query.endswith(']'):

# 去掉query的第1个字符和最后一个字符

query = query[1:-1]

datas=split_str(query)

if len(datas) < 2:

return -1

return datas[0]+datas[1]


# 自定义减法工具

def subtraction(query:str):

if not query:

return -1

datas=split_str(query)

if len(datas) < 2:

return -1

return datas[0]-datas[1]


# 自定义除法工具

def division(query:str):

if not query:

return -1

datas=split_str(query)

if len(datas) < 2:

return -1

return datas[0]/datas[1]


# 自定义乘法工具

def multiplication(query:str):

if not query:

return -1

datas=split_str(query)

if len(datas) < 2:

return -1

return datas[0]*datas[1]


# 以时间戳命名保存文件

def save_file(query:str):

if not query:

return -1

# 文件名称为当前时间戳,扩展名为txt

fileName='./data/'+str(int(time.time()))+'.txt'

# 将query保存到文件中

with open(fileName, 'w') as f:

f.write(query)

return fileName


def main3():

# 定义使用那个LLM

llm = ErnieBot(model="ernie-bot-4")

# 定义外挂的工具集

tools = [

define_tool(name="addition", description="2个数的和或者字符串中出现符号+", callback=addition),

define_tool(name="subtraction", description="2个数的差或者字符串中出现符号-", callback=subtraction),

define_tool(name="multiplication", description="2个数的积或者字符串中出现符号*", callback=multiplication),

define_tool(name="division", description="2个数的商或者字符串中出现符号/", callback=division),

define_tool(name="save_file", description="保存文件", callback=save_file),

]

# 定义hook集

hooks = [handle_tool_create, handle_tool_start, handle_tool_result]

# 定义agent

agent=ToolAgent(tools=tools,llm=llm,hooks=hooks)

# 使用agent执行复杂任务

result=agent.run("计算23+87*12-878+123*121-1233/234+123,将最终结果保持到文件中。")

print(result)


if __name__ == "__main__":

enable_log()

main3()

备注:

因为百度文心一言大模型 4.0 还在测试阶段,所以还没有集成到 promptulate 框架里边,如果想使用就直接修改 promptulate 框架的 config.py 里边的配置,将百度api 的 URL 改成V4 版本的即可,如下所示:

self.ernie_bot_url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro"

prompt 的关键性对照:

这段代码编写完成后,运行的效果并不理想,LLM 对任务的理解非常不准,就开始怀疑给 AI agent 布置任务的时候描述的不是很准确,导致了任务拆解不合理,就多次对这部分的提示词进行了必要的优化,最后发现好的提示词,效果就很好,下面给出示例。

result=agent.run("按照四则运算的规则,先计算乘除,再进行加减,计算23+87*12-878+123*121-1233/234+123,将最终结果保持到文件中。")

也就是要明确告诉 AI 的思考规则,这里就提醒使用 AI agent 框架的时候也是要关注提示词的。

运行结果(可能每次的过程不完全相同):

Answer the following questions as best you can.

You have access to the following tools:

addition: 2个数的和或者字符串中出现符号+

subtraction: 2个数的差或者字符串中出现符号-

multiplication: 2个数的积或者字符串中出现符号*

division: 2个数的商或者字符串中出现符号/

save_file: 保存文件

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, must be one of [addition, subtraction, multiplication, division, save_file]

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: 按照四则运算的规则,先计算乘除,再进行加减,计算878+123*121-1233/234+123,将最终结果保持到文件中。

Thought:

根据四则运算的规则,需要先计算乘法和除法,然后再进行加法和减法。因此,我们需要先计算123乘以121和1233除以234,然后将结果与其他数相加或相减,最后将结果保存到文件中。

Action: multiplication

Action Input: 123, 121

Observation: 14883.0

Thought: 接下来需要计算1233除以234。

Action: division

Action Input: 1233, 234

Observation: 5.269230769230769

Thought: 现在我们已经得到了乘法和除法的结果,可以进行加法和减法运算。

Action: addition

Action Input: 878, 14883.0

Observation: 15761.0

Thought: 接下来需要减去1233除以234的结果。

Action: subtraction

Action Input: 15761.0, 5.269230769230769

Observation: 15755.73076923077

Thought: 最后加上123。

Action: addition

Action Input: 15755.73076923077, 123

Observation: 15878.73076923077

Thought: 最终结果为15878.73076923077,需要将结果保存到文件中。

Action: save_file

Action Input: "result.txt", "15878.73076923077"

Observation: ./data/1697782411.txt

Thought: 最终结果已经保存到文件中,任务完成。

Observation: None

Thought: I now know the final answer

Final Answer: None

[DEBUG] 2023-10-20 14:13:35 [pne hook] hooks <('Agent', 'on_agent_result')> mounted_obj <ToolAgent> call hook: <[BaseHookSchema(hook_name='on_agent_result', callback=<function StdOutHook.handle_agent_result at 0x7f9c19f02280>, component_type='Agent')]>

[Agent Result] None

Agent End.

None

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表