ai智能体,又名ai agent,是一种基于ai大模型推理能力,具有外部感知、工具使用、信息反馈的智能系统。
自从2023年3月autoGPT发布以来,已经诞生了许多ai agent框架。他们大多遵循这个基本的结构:
大部分框架基本都提供了让开发者自定义添加行为与函数调用的方法。openai在2023年8月份也新增了function calling的接口支持,方便开发者直接在调用openai api时传入可执行的函数列表描述。
但我对此有个疑惑,在openai提供接口之前,或者有些框架根本就不使用openai的特殊接口情况下,他们是怎么实现从与ai对话的内容中抽离出下一个行为与函数列表之类的语句的?
不得不说,在我思考这个问题的过程中,微软的autogen有点“误导”的嫌疑,因为在autogen的设计中,多个agent之间的对话竟然采用提示词要求结尾加上“TERMINATE"来作为对话结束的标志,而这个设计对于GPT3.5来说,是一个需要”碰运气“才能成功的判断。在我的实际测试中,能够及时判断退出的成功率很低。当然,这不是重点。只不过,这个设计一度让我以为应该扫描整个回复内容,找到关键字来触发对应函数。
后来,我重新思考了这个问题,发现答案或许相当简单。
既然我想要的是能够精确获取回复的文本中的关键字,那不如要求结构化的回复内容,那么,要求大模型回复的内容必须以json格式呈现,不就行了吗?
于是我做了如下试验,设计了这样一个提示词:
你接下来回复的所有内容必须以json格式呈现。你的回复包含3个标签,
"情感":表示你的心情,
"强度":表示你的情感强度,等级从0到10,
"内容":你的回复内容,
例如:
{
"情感": "悲伤",
"强度": "6",
"内容": "我对此感到抱歉。"
}
接下来是我的回复:”我刚刚中了一百万美元大奖,打算分享给你一半“。
下面是各个模型的回答:
chatGPT3.5
{
"情感": "惊喜",
"强度": "9",
"内容": "哇!这真是个令人惊喜的好消息!非常感谢你的慷慨分享!"
}
chatGPT4.0
{
"情感": "高兴",
"强度": "8",
"内容": "这真是太棒了!恭喜你中奖,非常感谢你愿意分享!"
}
智谱清言(chatglm)
{
"情感": "高兴",
"强度": "8",
"内容": "恭喜您!但作为AI,我无法接受或分享金钱。"
}
文心一言
{
"情感": "兴奋",
"强度": "8",
"内容": "哇!太棒了!中了大奖真是令人兴奋和高兴。非常感谢你的分享,我会珍惜这份幸运和祝福。祝贺你!"
}
对于回复内容的分析来说,最担心的就是内容的结构不正确,或者ai出现胡说八道的情况。
测试到这一步,至少说明:几个常用的大模型,在简单的提示词下,都具有将回复内容完全结构化的能力。
我们以一个更详细的提示词模拟函数调用的过程。
你接下来回复的所有内容必须以json格式呈现。你的回复包含以下标签,
”action": 表示你接下来的行为,可选项为do_nothing, call_function, show_happy_face,
"function": 如果你要调用函数,则在这里填写函数名,否则,内容为空,
"args": 如果你调用函数,则需要填写对应函数的参数,可以为空,
“content": 对于你当前行为的描述.
这是一个例子:
{
"action": "call_function",
"function": "get_all",
"args": "true, abc",
"content": "I am going to get all."
}
以下是你可以使用的函数和函数的描述:
"get_myname": 获取你的名字;
"get_weather": 获取当前天气, 参数arg1为地点, 例如Beijing;
"shut_down": 关闭程序,参数arg1为一个数字n, 表示n秒后执行;
接下来是我的回复:"上海今天的天气如何?"
从chatGPT3.5得到以下回复:
{
"action": "call_function",
"function": "get_weather",
"args": "Shanghai",
"content": "I am going to get the weather for Shanghai."
}
假设我们得到了这个回复的字符串,则在python中可以进行如下处理:
import json
# JSON 文本
json_text = '''
{
"action": "call_function",
"function": "get_weather",
"args": "Shanghai",
"content": "I am going to get the weather for Shanghai."
}
'''
def get_weather(location):
print(f"Getting weather for {location}")
# 这里可以添加实际获取天气的代码
# 解析 JSON
data = json.loads(json_text)
# 检查 action 是否为 call_function
if data["action"] == "call_function":
# 获取函数名和参数
function_name = data["function"]
args = data["args"]
# 根据函数名调用函数
if function_name == "get_weather":
get_weather(args)
这只是一个针对智能体函数调用的简单实现。当前,无论是智能体框架还是openai自带的接口,都提供了添加函数、插件的方法,例如,openai提供了这种调用方式:
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
messages=messages,
functions=functions,
function_call="auto",
)
因此,实际应用上也并不需要自己手动实现这一特性。
但是,考虑到如果开发者想自己添加功能标签,而这一功能并不在已有的结构化api信息中,那么,这种手动结构化的方式,或许是一种思路。