前言

学习 UP 主 马克的技术工作坊Agent 的概念、原理与构建模式 —— 从零打造一个简化版的 Claude Code 视频,了解下 Agent 中常见的 ReAct 运行模式的原理和执行流程,并搭建一个简易的 Agent,记录下个人学习笔记,仅供自己参考😄

video:Agent 的概念、原理与构建模式 —— 从零打造一个简化版的 Claude Code

code:https://github.com/MarkTechStation/VideoCode

1. 简述

这篇文章我们来聊聊 Agent,它也叫 AI Agent,这是一个随着大模型热潮而兴起的重要概念,虽然 agent 这个词现在被频繁的提起,但它究竟是什么,是如何运作的,很多人其实并不清楚,这篇文章我们就来一起跟随 UP 主学习下

2. 什么是 Agent

大家都知道现在的大模型比如 GPT、DeepSeek 之类的,它们回答问题很厉害逻辑也很强,但平时我们用它们的时候会发现一个限制,它们无法感知或者改变外界环境。这句话是什么意思呢,我们来举个例子说明下:

在这里插入图片描述

比如你想让 GPT 帮你写一个贪吃蛇游戏,它确实可以给你代码,但是写完之后,像把代码写入到文件这种事情还是得你自己动手,也就是说大模型无法改变外界环境

在这里插入图片描述

而且有没有一种可能,你其实已经有一些贪吃蛇的代码了,你只是想让模型帮你基于这些代码来改写,增加一些功能。在这种情况下,你就必须把你已有的代码复制给 GPT 才行,我们不主动告诉 GPT 的话,它是无法自己查看这些代码的,换句话说,这就是大模型无法感知外部环境的体现

在这里插入图片描述

所以综合来看,大模型是无法感知或者改变外部环境的,那有没有办法解决掉这个问题呢,其实是有的,我们给它接上对应的工具就可以了,比如说读写文件内容的工具、查看文件列表的工具、运行终端命令的工具。工具就像是大模型的感官和四肢,有了它大模型就可以自己查询已有文件,自己写入代码,自己运行程序,整个过程不需要我们插手,完全自动化

在这里插入图片描述

像这样把大模型和一堆工具组装起来,变成一个能感知和改变外部环境的智能程序,我们就称它为 agent。通常 agent 用一个机器人来表示,这与大模型的大脑图标形成了鲜明的对比,毕竟 agent 有了感官和四肢嘛,能自己独立做事了,就像一个机器人一样

agent 有很多类型,前面举的是编程类的 agent,它可以用来开发程序,除此之外还有一些 agent 可以做 ppt,有一些 agent 可以深度搜索等等。总的来说 agent 的类型有很多,擅长的领域也各不相同,下面我们来举几个具体点的例子:

在这里插入图片描述

第一个例子便是大名鼎鼎的 cursor,相信即使你没有使用过它也多多少少听说过它的存在,cursor 是一个用于编程的 agent,我们只需要给它提交任务,它便会调用大模型和各种工具来帮我们写代码直至完成任务,整个过程中你顶多点个确定按钮,别的基本上什么什么也不用动

在这里插入图片描述

再举个例子,前一阵子比较火的 Manus,它也是一个 agent,在这个例子中,用户希望 Manus 帮它比较几个手机的性能、照相等能力。为了解决用户的问题,manus 会生成执行计划,搜索并浏览相关网页,最后把报告整理成一个页面展示给用户看,整个过程基本上也不需要用户插手,Manus 利用大模型和一些工具就可以解决用户的问题

OK,相信到这里,你对 agent 就有一个大致的了解了,下面我们就来讲讲 agent 的运行模式

3. ReAct 模式的运行流程

agent 的运行有很多种模式,其中最有名的一种是 react,react 本身是一个缩写,它的全称是 reasoning and acting,也就是思考与行动。react 可能是目前使用最为广泛的 agent 运行模式,如果你要学习 agent 的实现原理,那你就绝对绕不开 react

在这里插入图片描述

这个模式最初由 2022 年 10 月份的一篇论文提出,虽然距离现在已经有接近三年的时间了,但是它所提出的 agent 的运行模式仍然有着非常广泛的使用,说它是目前使用最为广泛的 agent 的运行模式也不为过

在这种模式下用户先提交任务,然后 agent 先做思考(thought),它思考后会决定是否调用工具,如果是的话它便会去调用合适的工具,比如读取文件、写入文件内容之类的,react 称这一步是行动(action

在行动后 agent 会去查看工具的执行结果,比如所读取的文件内容、写入是否成功等等,react 称这一步是观察(observation),也就是观察工具执行结果。在观察之后,react 会继续思考,它会再次判断是否需要调用工具,如果还是需要的话,它就会继续重复之前所说的行动观察思考的流程

直到某个时刻它认为不需要再调用工具了,可以直接给出结论了,此时它就输出了最终答案(final answer),整个流程到此结束

在这里插入图片描述

所以从上面的流程图里面也可以看出,react 流程的核心步骤是 thought、action、observation 和 final answer,记住这几个词,我们后面会用到

4. ReAct 模式的实现原理

了解了 react 模式的流程之后,下一个问题就是这种 react 模式是如何实现的,为什么模型拿到用户问题之后会先思考再行动,它为什么直接行动呢?

是因为模型就这么训练的吗?不是的,这跟模型的训练过程关系不大,大部分的奥秘其实都集中在系统提示词上,系统提示词是跟用户问题一起送给模型的提示词,它规定了模型的角色运行时要遵守的规则以及各种环境的信息等等

在这里插入图片描述

比如我们在系统提示词里面写,你的回答必须包含两个 XML 标签,一个叫做 question 用于存放用户的问题,一个叫做 answer 用于存放你的回答。你把这个系统提示词和用户问题一起发给大模型,在这种情况下,大模型便会遵循这种规范来输出答案

上面举的是一个简单的例子,如果你想要模型按照 react 模式返回答案的话,你的系统提示词就会更加复杂一些,这里有 UP 主准备的一个更具体的例子:

在这里插入图片描述

Note:完整的内容获取可以访问 UP 主的 github 仓库 https://github.com/MarkTechStation/VideoCode

这个系统提示词大致有五个部分,分别是职责描述、示例、可用工具、注意事项和环境信息,我们来仔细读一下

首先看职责描述部分:

在这里插入图片描述

你需要解决一个任务,为此你需要将任务分解为多个步骤,对于每个步骤,首先使用 thought 思考要做什么,然后使用 action 调用一个工具,工具的执行结果会通过 observation 返回给你,持续这个思考和行动的过程,直到你有足够多的信息来提供 final answer

这段话其实就是在描述我们刚才的那个 react 执行流程图,我们希望大模型按照 react 这个标准来运作,后面则是专门说明了每个标签的功能

在这里插入图片描述

紧接着我们举了几个例子,比如说第一个用户的问题是:埃菲尔铁塔有多高?模型就先用 thought 标签做了一些思考,然后再使用 action 调用了 get height 工具,传入的参数是埃菲尔铁塔,工具的返回结果通过 observation 返回给了模型,模型接到结果之后它再做了一些思考,然后就给出了最终的答案,这个就是一个非常典型的 react 流程

后面的例子 2 其实也是类似,只不过是它调用工具调了两遍,这个我们就不细说了

在这里插入图片描述

再往后列举了一些可用的工具,分别用于读取文件内容、写入文件内容和运行终端命令,都是非常常用的功能

然后我们列举了一些注意事项,而且告诉了大模型相关的一些环境信息,比如说当前的操作系统、目录和目录下的文件列表等等

下面我们就来演示一下如何使用这个系统提示词,我们用 deepseek 来举例,我们先把我们的系统提示词复制一下作为用户输入的一部分,之后再在后面加上具体要完成的任务:<task>写一个贪吃蛇游戏,使用 html、css 和 js 实现,代码分别放在不同的文件中</task>

在这里插入图片描述

有一点需要提一下,按照规范的做法,系统提示词和用户任务应该分开传给模型,但 deepseek 并没有提供单独提交系统提示词的地方,所以我们就把系统提示词和用户任务合在一起当成一条消息提交给它,这样的处理方式在大多数的情况下也是没有问题的,模型依然能够按照预期运行

在这里插入图片描述

可以看到 deepseek 按照我们的要求先在 thought 标签里面思考了一下,然后它使用 action 标签请求调用 writer_to_file 工具来写入 snake.html 文件,后面跟着的就是具体的文件内容了

大家注意一下这里的措辞,大模型 请求 调用工具,这里体现的是请求两个字,大模型本身是不能调用工具的,调用工具的是 agent 的工具调用组件,这里大模型只能是请求

现在如果运行的是一个真的 agent 的话,它便会去调用工具背后的 write_to_file 函数写入 html 文件内容,不过我们现在在模拟嘛,我们就假设调用已经完成了,并且假设工具的返回结果是写入成功,所以我们回复:<observation>写入成功</observation>

在这里插入图片描述

拿到这个结果后 deepseek 又开始运行了,这次它还是先用 thought 标签思考了一下,然后再使用 action 标签请求写入 css 文件的内容

在这里插入图片描述

我们照例回复:<observation>写入成功</observation>,deepseek 又开始返回了,可以看出 deepseek 还是先用 thought 思考,再用 action 请求写入 js 文件的内容

在这里插入图片描述

我们还是回复:<observation>写入成功</observation>,然后 deepseek 的返回就有了变化,因为三个必要的文件都已经写入完成了,不需要再调用工具了,因此 deepseek 在 thought 之后返回了一个 final answer,整个回答就彻底结束了

可以看到这就是 react 模式真正运行时的节奏,每一步都按照系统提示词的要求来,thought→action→observation,thought→action→observation,…,一直到任务完成,此时会输出 thought 和 final answer

系统提示词就相当于给模型安排了一个迷你剧本,它会严格按照这个剧本一步一步的走完

5. 动手实现一个 ReAct Agent

前面我们用 deepseek 演示了一个 agent 的运行流程,可以看到整个流程的关键在于系统的提示词,它决定了模型该如何一步步运行,其实在这个系统提示词的基础上,再加上一些配套的代码,我们就可以搭建出一个真正可用的 react agent

实际上 UP 已经把这个 agent 写好了,就放在他的 github 仓库里,大家需要的可以访问:https://github.com/MarkTechStation/VideoCode。接下来我们先看一下这个 agent 的使用过程,随后再带大家一起看一遍它的代码

我们先把这个项目 clone 下来,然后进入到对应的 Agent 所处的项目目录,运行指令如下:

git clone https://github.com/MarkTechStation/VideoCode
cd VideoCode/Agent的概念、原理与构建模式

agent 这个项目目录的文件如下:

在这里插入图片描述

这里面的文件很多,但实际上只有两个文件需要我们留意一下,一个是 agent.py 文件,这个文件里面就写了我们的 agent 的代码,我们等会要运行的就是这个文件。另外一个是 snake 文件夹,它里面什么也没有,等会我们就会让 agent 把代码写入到这个文件夹里面

OK,介绍完毕,下面我们来执行一下这个 agent 让你看看它是如何运作的,首先我们启动一下这个 agent,指令如下:

uv run agent.py snake

Note:运行之前请按照 README.md 文档所述配置好对应的 API Key

前面的 uv run agent.py 就是来启动 agent.py 文件的,后面的 snake 是 agent.py 这个脚本的第一个参数,意思是告诉 agent.py 它要操作的项目目录是 snake,代码就写在那里面

在这里插入图片描述

agent.py 首先向我们询问需要完成的任务,我们的任务就是:写一个贪吃蛇游戏,使用 html、css 和 js 实现,代码分别放在不同的文件中

在这里插入图片描述

可以看到 agent.py 已经开始运行了,它现在正在请求大模型,UP 这里采用了同步返回的机制,所以需要等模型把所有内容都生成完毕之后才能看到结果,其实也可以用流式返回的,模型返回几个字就能看到几个字,这样可能效果更好一点,不过代码的复杂度会增加

在这里插入图片描述

OK,看到第一轮结果了,我们的结果一共是包含三个部分:thought、action、observation,跟我们之前在 deepseek 那里看到的是一模一样,这里的 action 是请求调用 write_to_file 工具写入 snake.html 文件,后面的 observation 显示的就是具体的调用结果了,写入成功

注意啊,这个写入成功可不是模拟的,这是真的执行了 write_to_file 工具,工具也真的返回了写入成功这几个字,这个是第一部分

后面的流程也基本类似:

在这里插入图片描述

可以看到在 observation 之后 agent 会再次请求模型,然后 agent 又进行了一段 thought、action、observation,这一轮写入的是 css

在这里插入图片描述

往后我们可以看到第三轮的 thought、action、observation,这次写入的是 js

在这里插入图片描述

最后所有文件都写完之后,它会给出 thoughts 和 final answer,整个流程就结束了,再看看 snake 文件夹确实三个文件都有了

在这里插入图片描述

执行 snake.html 看看游戏能不能玩:

在这里插入图片描述

可以看到运行起来还是非常流程的,从这个结果中也可以判断出我们这个 agent 做的非常成功,完全可以作为一个简化版的 cursor 来使用

下面我们来看一下这个 agent 的具体代码,我们首先从入口处看起:

@click.command()
@click.argument('project_directory',
                type=click.Path(exists=True, file_okay=False, dir_okay=True))
def main(project_directory):
    project_dir = os.path.abspath(project_directory)

    tools = [read_file, write_to_file, run_terminal_command]
    # agent = ReActAgent(tools=tools, model="openai/gpt-4o", project_directory=project_dir)
    agent = ReActAgent(tools=tools, model="deepseek-chat", project_directory=project_dir)  # 修改模型名称

    task = input("请输入任务:")

    final_answer = agent.run(task)

    print(f"\n\n✅ Final Answer:{final_answer}")

if __name__ == "__main__":
    main()

这里面的 project_directory 就是我们传给 agent.py 文件的第一个参数,也就是 snake 那个文件夹,tools 代表可用的工具列表,我们这里给出了三个,分别是用于读取文件、写入文件和运行终端命令,这些都是很实用的函数,我们可以大体看一下:

def read_file(file_path):
    """用于读取文件内容"""
    with open(file_path, "r", encoding="utf-8") as f:
        return f.read()

def write_to_file(file_path, content):
    """将指定内容写入指定文件"""
    with open(file_path, "w", encoding="utf-8") as f:
        f.write(content.replace("\\n", "\n"))
    return "写入成功"

def run_terminal_command(command):
    """用于执行终端命令"""
    import subprocess
    run_result = subprocess.run(command, shell=True, capture_output=True, text=True)
    return "执行成功" if run_result.returncode == 0 else run_result.stderr

从这里可以看出工具确实就是函数,我们回到原来的主链路继续往下看,其中的 ReActAgent 便是这个文件的核心了,它是一个类,构造这个类的时候需要提供三个参数,第一个是工具列表,这个我们前面已经构建好了,这里直接传了进来,第二个是我们要用的模型,我们这里用的是 deepseek,第三个是项目目录,也就是 snake 文件夹

传好了这三个参数之后我们便获取到了一个 agent 变量,之后我们会提示用户输入任务内容,然后我们把用户任务传入 agent.run 函数,这个函数是 ReActAgent 的核心,调用它就相当于是启动了这个 agent,之前提到的 thought、action、observation 和 final answer 都是在这个函数内部依次处理的

处理好了之后会给出一个最终答案 final answer,并且把这个 final answer 输出到屏幕上,到这里主链路就结束了

可以看到这段代码的核心是 ReActAgent,我们来看一下它里面写了些什么:

class ReActAgent:
    def __init__(self, tools: List[Callable], model: str, project_directory: str):
        self.tools = { func.__name__: func for func in tools }
        self.model = model
        self.project_directory = project_directory
        self.client = OpenAI(
            base_url="https://api.deepseek.com/v1",
            api_key=ReActAgent.get_api_key(),
        )

首先它这里定义了一些自身的属性,分别是工具列表、模型、项目目录和模型调用客户端,到这里构造函数就结束了,后面我们要看的函数便是这个 agent 的重点即 run 函数

class ReActAgent:
    def __init__(self, tools: List[Callable], model: str, project_directory: str):
        pass

    def run(self, user_input: str):
        messages = [
            {"role": "system", "content": self.render_system_prompt(react_system_prompt_template)},
            {"role": "user", "content": f"<question>{user_input}</question>"}
        ]

        while True:

            # 请求模型
            content = self.call_model(messages)

            # 检测 Thought
            thought_match = re.search(r"<thought>(.*?)</thought>", content, re.DOTALL)
            if thought_match:
                thought = thought_match.group(1)
                print(f"\n\n💭 Thought: {thought}")

            # 检测模型是否输出 Final Answer,如果是的话,直接返回
            if "<final_answer>" in content:
                final_answer = re.search(r"<final_answer>(.*?)</final_answer>", content, re.DOTALL)
                return final_answer.group(1)

            # 检测 Action
            action_match = re.search(r"<action>(.*?)</action>", content, re.DOTALL)
            if not action_match:
                raise RuntimeError("模型未输出 <action>")
            action = action_match.group(1)
            tool_name, args = self.parse_action(action)

            print(f"\n\n🔧 Action: {tool_name}({', '.join(args)})")
            # 只有终端命令才需要询问用户,其他的工具直接执行
            should_continue = input(f"\n\n是否继续?(Y/N)") if tool_name == "run_terminal_command" else "y"
            if should_continue.lower() != 'y':
                print("\n\n操作已取消。")
                return "操作被用户取消"

            try:
                observation = self.tools[tool_name](*args)
            except Exception as e:
                observation = f"工具执行错误:{str(e)}"
            print(f"\n\n🔍 Observation:{observation}")
            obs_msg = f"<observation>{observation}</observation>"
            messages.append({"role": "user", "content": obs_msg})

这个函数的参数是用户输入的任务,在函数的内部,它先构建了一个 message 列表,里面有两个元素,分别是系统提示词和用户问题,系统提示词是用 render_system_prompts 这个函数来渲染的

在这里插入图片描述

它接受一个参数是系统提示词模板,模板里面的内容(prompt_template.py)跟我们之前讲的那个系统提示词基本上是一样的,只不过这个模板里面有一些占位符,比如说工具列表、操作系统、当前目录下的文件列表等等,这些占位符都是 render_system_prompt 函数在运行的时候填进去的

在拼接好了 message 列表之后,我们使用 call_model 函数调用了模型,拿到了模型的执行结果,然后我们提取出返回结果中的 thought 部分,并且打印了出来,然后代码会检测 thought 之后的内容是不是 final answer,如果是的话我们返回这个 final answer,函数执行到此结束

如果不是的话,那 content 里面一定就包含 action 了,我们此时就把 action 给解析出来,提取出其中的函数名和参数列表,然后判断了下当前工具是不是运行终端命令的工具,如果是的话,我们会提示用户是否继续,因为运行终端命令比较危险,所以现在一般用于编程的 agent 都会在运行终端命令之前主动询问用户是否要执行

之后没有问题的话,我们就会去执行工具背后的函数了,并且把执行结果放到 observation 里面,再把 observation 放到 message 列表里面,因为我们在一个 while 循环里面,所以我们下一步还会来到循环的开头这里继续请求模型

我们给 call_model 这个函数传了 message 列表作为参数工具,执行结果不是作为 observation 放到了 message 列表里面了吗,而 message 又传给了模型,这样模型就可以拿到工具的执行结果了,它进而就可以根据工具的执行结果推测下一步要干什么

所以总结一下这个 while 循环做的事情,请求模型、提取 thought、检测 final answer、提取 action 并执行其中的工具,这个过程会一直重复下去,直到模型返回了 final answer 为止,这正是我们之前所提到的 react 运行流程

6. ReAct 运行时序图

为了确保你彻底明白这其中发生了什么,我们来画个 agent 的流程图。整个流程图里面有两个角色:用户和 agent,而 agent 又可以分成三个部分,分别是模型、工具也就是函数、还有 agent 的主程序,agent 主程序这个词我们之前没有提过,其实就是 agent 里面负责串联整个流程的代码逻辑,它会在合适的时候调用工具或者是模型等等,你可以大致理解为我们刚才代码里面的那个 run 函数

下面我们就来画个流程图,看看这四个角色之间是怎么沟通的:

在这里插入图片描述

在用户提交任务之后,任务先到了 agent 的主程序这里,agent 主程序会先去调用模型,模型返回 thought 和 action,agent 主程序把 thought 和 action 打印给用户看,然后去调用 action 里面的指定工具,工具执行完毕之后返回结果

agent 主程序把结果发回给用户看,然后把这个工具执行结果加入到历史消息列表里面,然后再次重复上图中绿色框中的流程,也就是请求模型并处理 thought、action 和 observation 的逻辑

直到某个时刻在请求模型后,模型认为用户的任务已经完成了,不需要再调用工具了,它就会返回 thought 和 final answer,agent 主程序把 thought 和 final answer 展示给用户看,整个流程就结束了,这就是一个完整的 react agent 的问答流程

7. Plan-And-Execute 模式介绍

前面我们讲了如何使用 react 模式来构建一个 agent,react 是目前最常见、使用最广泛的 agent 的构建模式,但它不是唯一的方案。除了 react 之外,还有很多其它的运行模式,其中很多 agent 的运行过程就是先规划再执行,比如我们之前演示过的 Manus

如果你仔细看的话就会发现,它在一开始回答的时候会构建一个代办列表,后面的执行过程都是遵循这个代办列表来,而 claude code 中也会经常看到这种先创建 Todos 再去执行的情况,这种先规划再执行的模式,目前并没有一个统一的名字,而且每个 agent 的实现多多少少也会有一些差别

在这里插入图片描述

我们这里来讲一个其中比较有名的 sss,是 LangChain 提出来的,Plan-And-Execute 模式,从总体上来看,它也是遵循了先规划再执行的流程,只不过它的流程引入了一些动态修改规划的环节,这使得它的方案有了很大的灵活性

8. Plan-And-Execute 运行流程

我们先用时序图来画一下 Plan-and-Execute 模式的运行流程,首先我们要搞清楚这个时序图里面有多少个角色,粗分下来的话,那肯定只有两个了,一个是用户,另外一个是 Plan-and-Execute agent

在这里插入图片描述

不过既然要研究 Plan-and-Execute agent 的运行流程,我们就肯定要搞清楚这个 agent 的组成部分,首先它里面有一个负责出执行计划的模型,我们称它为 Plan 模型,我们在运行的过程中,还需要根据每一步的执行结果来动态的调整计划,因此我们还需要一个负责修改执行计划的模型,我们称它为 Re-Plan 模型

Plan 和 Re-Plan 模型可以是同一个也可以分为两个,都是可以的,我们暂且将它们列为两个,除了这两个模型之外,我们还需要一个负责执行这个计划中每一个步骤的 agent,我们称它为 执行 Agent

对你没看错,这个 Plan-and-Execute agent 内部还有一个 agent,这种 agent 套 agent 的设计方案其实也是比较常见的,最后跟 react 那个流程一样,我们还需要一个 agent 的主程序负责串联整个流程,这就是 Plan-and-Execute agent 的全部模块了

下面我们就把它们放在流程图里面,看看各个模块之间是如何运作的:

在这里插入图片描述

首先用户会把问题提给 agent 的主程序,比如我们的问题就可以是:今年澳网男子冠军的家乡是哪里,agent 的主程序接到这个问题之后会把这个问题发给 plan 模型,让它给出具体的执行步骤

比如一个可能的执行步骤就是这样的:

在这里插入图片描述

先查询当前日期,然后查询在当前年份下澳网男子冠军的名字,比如当前时间是 2025 年的话就查询 2025 年的澳网男子冠军的名字,查出名字后,我们再根据这个名字来查询这个冠军的家乡,没错,这就是一个非常合理的执行步骤

那计划有了之后,agent 的主程序便会把这个计划传给执行 agent 让它去执行这个计划中的第一步,也就是查询当前日期的那个步骤,这个执行 agent 可以用我们之前讲的 react 模式来运行,它内置一个网络搜索工具,这样它就可以通过搜索网络来查询当前日期了

当然执行 agent 也完全可以用别的模式来运行,Plan-and-Execute 模式只要求执行 agent 能够完成指定的步骤就行,至于它的运行模式是不是 react,内置工具有哪些,它完全不关心

执行 agent 的内部一顿操作之后就吐出了一个执行结果并返回回去,然后 agent 的主程序会把用户的问题、执行计划和执行记录都发给 re-plan 模型,让它生成一个新的执行计划

毕竟我们拿到了第一步的执行结果了,多了一些信息,情况可能会发生些变化,把原计划改改是再正常不过的事情了,那 agent 的主程序接到新的执行计划之后它便会回头再重复这个绿色框中的过程

在我们这个例子中,这个过程一共会运行三轮,对应了执行计划里面的三步,每一轮都包含两个环节,一个是执行环节,一个是 re-plan 环节,为了能够让你彻底明白,我们模拟一下这个循环中的三轮,让你看看每一轮的执行环节和 re-plan 环节都具体发生了一些什么事情

在这里插入图片描述

在这里插入图片描述

首先是第一轮,在执行阶段我们把执行计划发给执行 agent,让它处理其中的第一步,执行 agent 返回之后,我们把它给出的执行结果加入到历史执行记录里,然后把用户问题、第一个执行计划和历史执行记录一起发给 re-plan 模型,让它给出第二个执行计划

第一个执行计划和第二个执行计划有两点不同,这里我们专门说一下,首先原来查询当前日期的那一步就不用出现在第二个执行计划里面了,毕竟已经执行完了不用再执行了,另外查询澳网男子冠军名字的这一步也发生了一些变化,在第一个执行计划中,它叫做查询对应日期的澳网男子冠军名字,在第二个执行计划中,它叫做查询 2025 年的澳网男子冠军名字,毕竟日期已经查出来了,因此我们可以直接把具体的年份放到执行计划里,这样执行 agent 接到的任务就更加精确了

在这里插入图片描述

在这里插入图片描述

然后进入到第二轮,在这一轮中,我们同样先取出最新的执行计划发给执行 agent,让它执行其中的第一步,拿到执行结果后,我们再把执行结果加入到历史执行记录中,然后在 re-plan 阶段把用户问题、执行计划和历史执行记录发给 re-plan 模型,拿到第三个执行计划

在这里插入图片描述

在第三轮中,我们还是先取出执行计划,让执行 agent 处理其中的第一步,当然现在也只剩一步了,执行之后我们就可以拿到一个执行结果,把执行结果加入到历史执行记录里,然后再把用户问题、执行计划和历史执行记录都发给 re-plan 模型

在最后一轮中,re-plan 模型会发现所有的步骤都已经做完了,用户的问题可以回答出来了,此时 re-plan 模型返回的就不是最新的执行计划了,而是最终的答案。

所以在之前的流程图里面,我们也要把执行计划换成最终答案,agent 主程序接到这个最终答案之后,便会把这个答案转发给用户,整个流程也就结束了

在这里插入图片描述

所以回头看一下这个流程图,我们之前说 agent 的主程序请求 re-plan 模型给出一个新的执行计划,这个说法其实并不准确,更准确的说法是,agent 主程序请求 re-plan 模型给出一个新的执行计划,或者是返回最终答案

如果还有步骤要执行的话,那就给出一个新的计划,如果没有步骤要做了,用户的问题已经回答出来了,那 re-plan 模型就返回最终答案就好了,因此 re-plan 模型的返回也有两种可能性,新的执行计划或者是最终答案,这样才是一个准确的流程图

相信到这里为止,你对 Plan-and-Execute 流程就有一个非常清晰的认识了,如果你想要 Plan-and-Execute 的具体实现代码,LangChain 官方提供了,你可以访问:https://langchain-ai.github.io/langgraph/tutorials/plan-and-execute/plan-and-execute/

OK,以上就是本篇文章的全部内容了

结语

这篇文章我们跟着 UP 主一起学习了 Agent 最有名的运行模式 ReAct 即思考与行动模式,了解了 ReAct 模式的实现原理,其实就是提供一个系统提示词,让模型按照我们想要的方式来回答问题

接着我们自己动手实现了一个简单的 ReAct Agent,并分析了其运行时序图,最后我们简略介绍了 Agent 的另一种运行模式即 Plan-And-Execute 模式,它也是遵循先规划再执行的流程,只不过引入了一些动态修改规划的环节

整个讲解非常通俗易懂,大家感兴趣的可以多关注关注,多看看 UP 的视频🤗

参考

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐