简单易懂的 AI Agent 框架解析:让你五分钟看懂复杂代码

作为一个新手,你可能会觉得复杂的代码就像外星语一样难以理解。别担心!今天我就带你一步一步地了解一个叫”Agent”的人工智能助手是如何工作的。我们不会讲太多复杂的理论,而是像剥洋葱一样,一层一层地揭开它的神秘面纱。

什么是 AI Agent?

简单来说,AI Agent 就像是一个智能小助手,它能听懂你说的话,想一想该怎么做,然后真的去执行一些任务。就像你告诉 Siri “帮我设个闹钟”,它就会思考怎么设置闹钟,然后真的帮你设置了。

在这个项目里,我们创建了一个叫 ReActAgent 的 AI 助手,它遵循一种叫 ReAct 的工作模式:

  1. 思考(Thought)- 先想想应该做什么
  2. 行动(Action)- 然后做点什么
  3. 观察(Observation)- 看看做了之后有什么结果
  4. 重复上面三个步骤,直到解决问题

整体架构一览

我们的 AI Agent 项目由几个核心部分组成:

  1. 主控制器(agent.py)- 控制整个流程的核心大脑
  2. 提示模板(prompt_template.py)- 告诉 AI 如何按照规定格式交流
  3. 配置文件(pyproject.toml)- 记录项目依赖关系
  4. 使用说明(README.md)- 告诉别人怎么用这个项目

接下来,我会带你深入了解每一部分的细节。

深入 agent.py - AI 助手的大脑

让我们从最重要的 agent.py 文件开始。你可以把它想象成 AI 助手的大脑,控制着整个思考和行动的过程。

核心类:ReActAgent

1
2
3
4
5
6
7
8
9
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://openrouter.ai/api/v1",
api_key=ReActAgent.get_api_key(),
)

这段代码定义了我们的 AI 助手类。构造函数(init)接受三个参数:

  • tools: 可用的工具列表(比如读文件、写文件、执行命令)
  • model: 使用的 AI 模型名称
  • project_directory: 项目所在的目录

这里还初始化了一个 OpenAI 客户端,用来和 AI 模型通信。

主循环:run 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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)

# 检查是否是最终答案
if "<final_answer>" in content:
final_answer = re.search(r"<final_answer>(.*?)</final_answer>", content, re.DOTALL)
return final_answer.group(1)

# 解析并执行动作
action_match = re.search(r"<action>(.*?)</action>", content, re.DOTALL)
tool_name, args = self.parse_action(action)
observation = self.tools[tool_name](*args)
messages.append({"role": "user", "content": f"<observation>{observation}</observation>"})

这是整个 AI 助手最核心的部分。它的工作流程是这样的:

  1. 准备初始消息:包括系统指令和用户问题
  2. 进入一个无限循环,直到得到最终答案:
    • 调用 AI 模型获取响应
    • 如果是最终答案就返回
    • 如果是动作指令就执行相应的工具
    • 把执行结果告诉 AI 模型,继续下一轮

工具系统

AI 助手的强大之处在于它可以使用工具。目前有三个内置工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

这些工具让 AI 助手可以真正地”做事”,而不仅仅是聊天:

  • 读取任何文件的内容
  • 创建或修改文件
  • 执行电脑上的命令

深入 prompt_template.py - AI 的行为准则

prompt_template.py 文件定义了 AI 应该如何表现和沟通。我们可以把它想象成教 AI 如何说话的”教材”。

ReAct 框架模板

1
2
3
4
5
6
7
8
9
react_system_prompt_template = """
你需要解决一个问题。为此,你需要将问题分解为多个步骤。对于每个步骤,首先使用 <thought> 思考要做什么,然后使用可用工具之一决定一个 <action>。接着,你将根据你的行动从环境/工具中收到一个 <observation>。持续这个思考和行动的过程,直到你有足够的信息来提供 <final_answer>。

所有步骤请严格使用以下 XML 标签格式输出:
- <question> 用户问题
- <thought> 思考
- <action> 采取的工具操作
- <observation> 工具或环境返回的结果
- <final_answer> 最终答案

这部分告诉 AI 必须按照特定的格式来交流。就像我们说话要有主谓宾一样,AI 的每句话都要放在对应的”标签”里:

  • <thought>: AI 在想什么
  • <action>: AI 要做什么
  • <observation>: AI 看到了什么结果
  • <final_answer>: AI 的最终答案

举例说明

模板中包含了两个具体的例子帮助 AI 理解应该如何工作:

1
2
3
4
5
6
7
例子 1:
<question>埃菲尔铁塔有多高?</question>
<thought>我需要找到埃菲尔铁塔的高度。可以使用搜索工具。</thought>
<action>get_height("埃菲尔铁塔")</action>
<observation>埃菲尔铁塔的高度约为330米(包含天线)。</observation>
<thought>搜索结果显示了高度。我已经得到答案了。</thought>
<final_answer>埃菲尔铁塔的高度约为330米。</final_answer>

通过这种方式,AI 学会了如何一步步解决问题,而不是直接给出答案。

工具列表注入

模板还有一个重要的特性,就是它会在运行时插入实际可用的工具列表:

1
2
本次任务可用工具:
${tool_list}

这样 AI 就知道它能使用哪些工具了。

配置文件和其他辅助部分

除了主要的代码文件,还有一些配置和辅助文件也很重要。

pyproject.toml - 项目依赖管理

1
2
3
4
5
6
7
8
9
10
[project]
name = "agent"
version = "0.1.0"
description = "Add your description here"
requires-python = ">=3.12"
dependencies = [
"click>=8.2.1",
"openai>=1.91.0",
"python-dotenv>=1.1.1",
]

这个文件告诉我们项目需要哪些依赖:

  • click: 用于创建命令行界面
  • openai: 用于与 AI 模型通信
  • python-dotenv: 用于加载环境变量

README.md - 使用说明

1
2
3
4
5
6
7
8
9
10
11
12
# 运行方法

首先请确保你已经安装了 uv,如果没有的话,请按以下页面的要求安装:
https://docs.astral.sh/uv/guides/install-python/

然后在当前目录下,新建一个叫做 .env 的文件,输入以下内容:
OPENROUTER_API_KEY=xxx

xxx 就是你在 OpenRouter 上配好的 API Key。

确保 uv 已经安装成功后,进入到当前文件所在目录,然后执行以下命令即可启动:
uv run agent.py snake

这个文件告诉使用者如何安装和运行这个 AI 助手。

命令行接口

最后,agent.py 文件末尾还定义了命令行接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@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)

# 获取用户任务输入
task = input("请输入任务:")

# 运行代理并获取最终答案
final_answer = agent.run(task)

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

if __name__ == "__main__":
main()

这一部分让用户可以通过命令行来启动 AI 助手,并指定要处理的项目目录。

总结

通过以上分析,我们可以看到这个 AI Agent 项目的整体工作原理:

  1. 初始化阶段:创建 ReActAgent 实例,配置好 AI 模型和可用工具
  2. 准备阶段:构建系统提示,告诉 AI 它的任务和沟通格式
  3. 执行阶段:进入主循环,不断与 AI 交互直到得到最终答案
  4. 交互流程:AI 思考 → AI 行动 → 执行工具 → 返回结果 → 继续循环

整个系统的设计非常巧妙,它将复杂的 AI 交互过程标准化,使得 AI 可以像人一样通过”思考-行动-观察”的循环来解决问题。

最重要的是理解这个框架的核心思想:不是让 AI 一次性解决所有问题,而是让它一步步地思考和行动,在每一步都验证结果,最终达成目标。

这种设计思路其实很像我们人类学习新技能的过程——先思考要做什么,然后动手尝试,观察结果,再调整策略,如此反复直到掌握。

希望这篇博客能帮助你更好地理解 AI Agent 的工作机制!