跳到正文

什么是 Agent?

从修复一个网页按钮的例子出发,理解 Agent 如何调用工具、读取结果并继续执行,以及怎样判断任务是否完成。

前面我们已经知道,模型可以请求调用工具,AI Chat 也可以帮我们生成和修改交互内容。

这些都是 Chat 产品的功能,现在流行的所谓的智能体(Agent)又是什么?它和 Chat 有什么区别?

一、Agent 是什么?

Agent 常被译为「智能体」或「代理」。

前面的课程中我们提到,当用户使用 Chat 产品的时候,模型程序接收到服务器程序的输入后,会进行一系列的计算,然后生成回答。最后,服务器程序将回答传回给 Chat 程序,Chat 程序再将其展示给你。

而 Agent 则稍微有点区别,Agent 程序会先让模型思考当前应该做什么,然后获得结果后,调用工具行动,再观察工具返回的结果,并继续思考下一步。

这个「想」 → 「做」 → 「看」 → 「想」 → 「做」 → 「看」 → …… 的过程,会一直重复,直到任务完成。

二、模型怎么从「回答」变成「能想」和「能做」?

我们将通过一个具体的例子,来理解模型怎么从「回答」变成「能想」和「能做」。

假设模型的训练数据里没有任何《盗梦空间》和《黑客帝国》的信息,然后用户问模型:电影《盗梦空间》(Inception)导演的出生年份,加上《黑客帝国》(The Matrix)第一部的上映年份,总和是多少?

Agent 程序发送消息到服务器程序后,经过一系列运算,会返回如下结构的数据。

json
{
  "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 字段,这个字段里显示的就是模型思考的过程。这一步就是前面提到的 「想」:

json
{
  "reasoning": "要算出总和,我需要先知道两个未知数:《盗梦空间》导演是谁及其出生年份,以及《黑客帝国》第一部的上映年份。先查《盗梦空间》的导演。", // 模型的思考过程
}

有了这个思考后,模型会根据这个思考,生成一个搜索工具请求,搜索「盗梦空间的导演」,这一步就是前面提到的 「做」:

json
{
  "tool_calls": [
        {
          "type": "function",
          "function": {
            "name": "search_web",
            "arguments": "{\"query\":\"Inception movie director\"}" // 搜索盗梦空间导演 
          }
        }
      ]
}

工具会返回搜索结果,然后模型会进行「看」:

json
{
  {
    "role": "tool", // 消息身份:工具
    "content": "《盗梦空间》(Inception)是 2010 年上映的科幻动作片,由克里斯托弗·诺兰(Christopher Nolan)编剧并执导。" // 工具返回的结果
  }
}

从上面的 JSON 数据可以看到,工具返回了导演的名字「克里斯托弗·诺兰(Christopher Nolan)」,但并没有给出导演的出生年份,于是模型会根据这个结果,进行第二次思考和工具调用(第二次的想、做、看),并获得结果:

json
{
  "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 日」,于是模型会根据这个结果继续进行剩余的查询和计算任务,直到获得所有需要的数据后,最终得到如下结果:

json
{
  "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 的阅读可能有点困难,我们将关键信息整理成图,整个过程如下:

用户提问问题电影《盗梦空间》(Inception)导演的出生年份,加上《黑客帝国》(The Matrix)第一部的上映年份,总和是多少?第 1 轮确认导演想要算出总和,我需要先知道两个未知数:《盗梦空间》导演是谁及其出生年份,以及《黑客帝国》第一部的上映年份。先查《盗梦空间》的导演。做Search["Inception movie director"]看《盗梦空间》(Inception)是 2010 年上映的科幻动作片,由克里斯托弗·诺兰(Christopher Nolan)编剧并执导。第 2 轮查询出生年份想导演是 Christopher Nolan。但我还没有他的出生年份,也没有《黑客帝国》的上映年份。接下来先查 Christopher Nolan的出生年份。做Search["Christopher Nolan birth year"]看克里斯托弗·诺兰(Christopher Nolan)出生于 1970 年 7 月 30 日。第 3 轮查询上映年份想第一个数字拿到了,是 1970。现在还需要第二个数字:电影《黑客帝国》(TheMatrix)第一部的上映年份。做Search["The Matrix release year"]看《黑客帝国》(The Matrix)于 1999 年3 月 31 日在美国上映。第 4 轮计算总和想两个数字都齐了:1970 和 1999。为了避免心算出错,我调用计算器工具求它们的和。做Calculator["1970 + 1999"]看3969第 5 轮输出答案想计算结果是 3969,所有步骤均已验证完毕,可以输出最终答案。做Finish[《盗梦空间》导演克里斯托弗·诺兰出生于 1970 年,《黑客帝国》上映于1999 年,两者年份之和为 3969。]

三、为何有这种模式?

上述的这个过程「想」 → 「做」 → 「看」 → 「想」 → 「做」 → 「看」 → …… 的过程,又被称为 ReAct。这就是 Agent 的核心工作原理,它也是和传统的 AI Chat 最大的区别。

为何会有这种使用模式?

原因是 AI Chat 在某些情况下,仅运行一次,并不足以让大语言模型答出答案。如果上述的例子(还是假设大语言模型不知道什么是《盗梦空间》和《黑客帝国》),在 AI Chat 里提问,可能获得的答案将会是:

电影《盗梦空间》(Inception)导演的出生年份,加上《黑客帝国》(The Matrix)第一部的上映年份,总和是多少?

search_web

调用参数

{
  "query": "Inception movie director"
}

返回结果

{
  "director": "Christopher Nolan"
}

抱歉,我仅知道《盗梦空间》的导演是 Christopher Nolan,但不知道他的出生年份。

四、接下来学什么?

到这里,你已经能把 AI Chat 等知识都搞懂了。接下来你可以选择继续学习 Agent 101,了解更多与 AI Agent 相关的知识。

如果你对 AI Agent 不感兴趣,对 AI 编程更感兴趣,则可以先去看看 Coding 101。这个课程会从基础的编程知识讲起,然后逐步教会你使用 AI 开发一个网站。