什么是 Agent?
从修复一个网页按钮的例子出发,理解 Agent 如何调用工具、读取结果并继续执行,以及怎样判断任务是否完成。
前面我们已经知道,模型可以请求调用工具,AI Chat 也可以帮我们生成和修改交互内容。
这些都是 Chat 产品的功能,现在流行的所谓的智能体(Agent)又是什么?它和 Chat 有什么区别?
一、Agent 是什么?
Agent 常被译为「智能体」或「代理」。
前面的课程中我们提到,当用户使用 Chat 产品的时候,模型程序接收到服务器程序的输入后,会进行一系列的计算,然后生成回答。最后,服务器程序将回答传回给 Chat 程序,Chat 程序再将其展示给你。
而 Agent 则稍微有点区别,Agent 程序会先让模型思考当前应该做什么,然后获得结果后,调用工具行动,再观察工具返回的结果,并继续思考下一步。
这个「想」 → 「做」 → 「看」 → 「想」 → 「做」 → 「看」 → …… 的过程,会一直重复,直到任务完成。
二、模型怎么从「回答」变成「能想」和「能做」?
我们将通过一个具体的例子,来理解模型怎么从「回答」变成「能想」和「能做」。
假设模型的训练数据里没有任何《盗梦空间》和《黑客帝国》的信息,然后用户问模型:电影《盗梦空间》(Inception)导演的出生年份,加上《黑客帝国》(The Matrix)第一部的上映年份,总和是多少?
Agent 程序发送消息到服务器程序后,经过一系列运算,会返回如下结构的数据。
{
"messages": [
{
"role": "user", // 消息身份:用户
"content": "电影《盗梦空间》(Inception)导演的出生年份,加上《黑客帝国》(The Matrix)第一部的上映年份,总和是多少?" // 用户的问题内容
},
{
"role": "assistant", // 消息身份:模型
"reasoning": "要算出总和,我需要先知道两个未知数:《盗梦空间》导演是谁及其出生年份,以及《黑客帝国》第一部的上映年份。先查《盗梦空间》的导演。", // 模型的思考过程
"content": null, // 模型生成的内容:空。因为没有回答,而是直接生成了工具调用请求。
"tool_calls": [
{
"type": "function",
"function": {
"name": "search_web",
"arguments": "{\"query\":\"Inception movie director\"}" // 搜索盗梦空间导演
}
}
]
},
{
"role": "tool", // 消息身份:工具
"content": "《盗梦空间》(Inception)是 2010 年上映的科幻动作片,由克里斯托弗·诺兰(Christopher Nolan)编剧并执导。" // 工具返回的结果
}
]
}可以细看对比一下和之前的区别,多了一个 reasoning 字段,这个字段里显示的就是模型思考的过程。这一步就是前面提到的 「想」:
{
"reasoning": "要算出总和,我需要先知道两个未知数:《盗梦空间》导演是谁及其出生年份,以及《黑客帝国》第一部的上映年份。先查《盗梦空间》的导演。", // 模型的思考过程
}有了这个思考后,模型会根据这个思考,生成一个搜索工具请求,搜索「盗梦空间的导演」,这一步就是前面提到的 「做」:
{
"tool_calls": [
{
"type": "function",
"function": {
"name": "search_web",
"arguments": "{\"query\":\"Inception movie director\"}" // 搜索盗梦空间导演
}
}
]
}工具会返回搜索结果,然后模型会进行「看」:
{
{
"role": "tool", // 消息身份:工具
"content": "《盗梦空间》(Inception)是 2010 年上映的科幻动作片,由克里斯托弗·诺兰(Christopher Nolan)编剧并执导。" // 工具返回的结果
}
}从上面的 JSON 数据可以看到,工具返回了导演的名字「克里斯托弗·诺兰(Christopher Nolan)」,但并没有给出导演的出生年份,于是模型会根据这个结果,进行第二次思考和工具调用(第二次的想、做、看),并获得结果:
{
"messages": [
{
"role": "user", // 消息身份:用户
"content": "电影《盗梦空间》(Inception)导演的出生年份,加上《黑客帝国》(The Matrix)第一部的上映年份,总和是多少?" // 用户的问题内容
},# 第一次思考和工具调用18 行
{
"role": "assistant", // 消息身份:模型
"reasoning": "要算出总和,我需要先知道两个未知数:《盗梦空间》导演是谁及其出生年份,以及《黑客帝国》第一部的上映年份。先查《盗梦空间》的导演。", // 模型的思考过程
"content": null, // 模型生成的内容:空。因为没有回答,而是直接生成了工具调用请求。
"tool_calls": [
{
"type": "function",
"function": {
"name": "search_web",
"arguments": "{\"query\":\"Inception movie director\"}"
}
}
]
},
{
"role": "tool", // 消息身份:工具
"content": "《盗梦空间》(Inception)是 2010 年上映的科幻动作片,由克里斯托弗·诺兰(Christopher Nolan)编剧并执导。" // 工具返回的结果
} # 第二次思考和工具调用
{
"role": "assistant", // 消息身份:模型
"reasoning": "导演是 Christopher Nolan。但我还没有他的出生年份,也没有《黑客帝国》的上映年份。接下来先查 Christopher Nolan 的出生年份。", // 模型的思考过程
"content": null, // 模型生成的内容:空。因为没有回答,而是直接生成了工具调用请求。
"tool_calls": [
{
"type": "function",
"function": {
"name": "search_web",
"arguments": "{\"query\":\"Christopher Nolan birth year\"}"
}
}
]
},
{
"role": "tool", // 消息身份:工具
"content": "克里斯托弗·诺兰(Christopher Nolan)出生于 1970 年 7 月 30 日。" // 工具返回的结果
}
]
}这次模型就从工具返回的结果中,得到了导演的出生年份「1970 年 7 月 30 日」,于是模型会根据这个结果继续进行剩余的查询和计算任务,直到获得所有需要的数据后,最终得到如下结果:
{
"messages": [
{
"role": "user", // 消息身份:用户
"content": "电影《盗梦空间》(Inception)导演的出生年份,加上《黑客帝国》(The Matrix)第一部的上映年份,总和是多少?" // 用户的问题内容
},# 第一次思考和工具调用37 行
{
"role": "assistant", // 消息身份:模型
"reasoning": "要算出总和,我需要先知道两个未知数:《盗梦空间》导演是谁及其出生年份,以及《黑客帝国》第一部的上映年份。先查《盗梦空间》的导演。", // 模型的思考过程
"content": null, // 模型生成的内容:空。因为没有回答,而是直接生成了工具调用请求。
"tool_calls": [
{
"type": "function",
"function": {
"name": "search_web",
"arguments": "{\"query\":\"Inception movie director\"}"
}
}
]
},
{
"role": "tool", // 消息身份:工具
"content": "《盗梦空间》(Inception)是 2010 年上映的科幻动作片,由克里斯托弗·诺兰(Christopher Nolan)编剧并执导。" // 工具返回的结果
},
# 第二次思考和工具调用
{
"role": "assistant", // 消息身份:模型
"reasoning": "导演是 Christopher Nolan。但我还没有他的出生年份,也没有《黑客帝国》的上映年份。接下来先查 Christopher Nolan 的出生年份。", // 模型的思考过程
"content": null, // 模型生成的内容:空。因为没有回答,而是直接生成了工具调用请求。
"tool_calls": [
{
"type": "function",
"function": {
"name": "search_web",
"arguments": "{\"query\":\"Christopher Nolan birth year\"}"
}
}
]
},
{
"role": "tool", // 消息身份:工具
"content": "克里斯托弗·诺兰(Christopher Nolan)出生于 1970 年 7 月 30 日。" // 工具返回的结果
}, # 第三次思考和工具调用
{
"role": "assistant", // 消息身份:模型
"reasoning": "导演是 Christopher Nolan。但还没有《黑客帝国》的上映年份。接下来先查《黑客帝国》的上映年份。", // 模型的思考过程
"content": null, // 模型生成的内容:空。因为没有回答,而是直接生成了工具调用请求。
"tool_calls": [
{
"type": "function",
"function": {
"name": "search_web",
"arguments": "{\"query\":\"The Matrix first movie release date\"}"
}
}
]
},
{
"role": "tool", // 消息身份:工具
"content": "《黑客帝国》(The Matrix)第一部上映于 1999 年 3 月 31 日。" // 工具返回的结果
},
# 第四次思考和工具调用
{
"role": "assistant", // 消息身份:模型
"reasoning": "两个数字都齐了:1970 和 1999。为了避免心算出错,我调用计算器工具求它们的和。", // 模型的思考过程
"content": null, // 模型生成的内容:空。因为没有回答,而是直接生成了工具调用请求。
"tool_calls": [
{
"type": "function",
"function": {
"name": "calculate",
"arguments": "{\"operation\":\"add\",\"numbers\":[1970,1999]}"
}
}
]
},
{
"role": "tool", // 消息身份:工具
"content": "1970 + 1999 = 3969" // 工具返回的结果
}
# 最终结果
{
"role": "assistant", // 消息身份:模型
"reasoning": "计算结果是 3969,所有步骤均已验证完毕,可以输出最终答案。", // 模型的思考过程
"content": "《盗梦空间》导演克里斯托弗·诺兰出生于 1970 年,《黑客帝国》上映于 1999 年,两者年份之和为 3969。", // 模型生成的内容:最终答案
}
]
}JSON 的阅读可能有点困难,我们将关键信息整理成图,整个过程如下:
三、为何有这种模式?
上述的这个过程「想」 → 「做」 → 「看」 → 「想」 → 「做」 → 「看」 → …… 的过程,又被称为 ReAct。这就是 Agent 的核心工作原理,它也是和传统的 AI Chat 最大的区别。
为何会有这种使用模式?
原因是 AI Chat 在某些情况下,仅运行一次,并不足以让大语言模型答出答案。如果上述的例子(还是假设大语言模型不知道什么是《盗梦空间》和《黑客帝国》),在 AI Chat 里提问,可能获得的答案将会是:
四、接下来学什么?
到这里,你已经能把 AI Chat 等知识都搞懂了。接下来你可以选择继续学习 Agent 101,了解更多与 AI Agent 相关的知识。
如果你对 AI Agent 不感兴趣,对 AI 编程更感兴趣,则可以先去看看 Coding 101。这个课程会从基础的编程知识讲起,然后逐步教会你使用 AI 开发一个网站。