AI Agent是2025-2026年大模型应用的核心范式之一。但很多讨论停留在概念层面,缺少对其内部工作机制的深入分析。这篇文章从架构角度拆解Agent的完整技术链路:从接收一条自然语言指令,到完成多步骤的复杂任务,中间经历了哪些关键环节。
一、Agent的本质:感知-推理-行动循环
Agent不是一个单次调用模型的过程,而是一个循环:
while 任务未完成:
观察 = 获取当前状态(上一步执行结果、环境信息)
思考 = 大模型推理(分析观察结果,规划下一步)
行动 = 执行工具调用(Shell、API、文件操作等)
判断 = 任务是否完成?
这个循环被称为ReAct(Reasoning + Acting)模式,最早在2022年的论文中被形式化提出。其核心思想是:让模型在每一步都先"思考"再"行动",而不是一次性生成所有步骤。
为什么需要循环?
因为真实世界是不可预测的。你无法在第一步就知道后续每一步的具体参数。比如:
- 你要部署一个服务,但不知道当前服务器装的是nginx还是IIS
- 你要查数据库,但先得知道表名和字段结构
- 你执行了一条命令,可能成功也可能报错,后续步骤取决于这个结果
二、指令解析层
用户输入的是自然语言,Agent的第一步是理解意图并拆解任务。
意图分类
大模型通过System Prompt中的角色定义和工具描述,理解用户的意图类型:
- 信息查询:"这个服务器的IP是多少?" → 执行命令获取信息
- 状态变更:"把端口改成8080" → 修改配置并重启服务
- 复合任务:"部署一个网站" → 拆解为多个子任务
任务拆解策略
对于复合任务,模型会自动拆解。但好的Agent不会一开始就把所有步骤列出来,而是按需展开:
# 差的拆解方式(提前规划所有步骤,容易出错)
plan = [
"1. 创建目录",
"2. 解压文件",
"3. 配置IIS", # 但如果系统是Linux呢?
"4. 开放防火墙",
"5. 测试访问"
]
# 好的拆解方式(按需探索)
step1: 检查操作系统和Web服务器类型
→ 根据结果决定step2
step2: 根据实际环境执行对应的部署操作
→ 根据结果决定step3
step3: 验证部署是否成功
→ 如果失败,诊断原因并修复
三、工具调用层(Tool Use)
工具调用是Agent执行能力的基础。大模型通过生成符合JSON Schema的结构化数据来"调用"工具。
工具注册
每个Agent启动时,需要注册它可以使用的工具集合:
tools = [
{
"name": "bash",
"description": "执行Shell命令。适用于系统管理、文件操作、进程控制等。",
"parameters": {
"type": "object",
"properties": {
"command": {"type": "string", "description": "要执行的命令"}
},
"required": ["command"]
}
},
{
"name": "read_file",
"description": "读取指定路径的文件内容。",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "文件绝对路径"},
"offset": {"type": "integer", "description": "起始行号"},
"limit": {"type": "integer", "description": "读取行数"}
},
"required": ["path"]
}
},
{
"name": "edit_file",
"description": "精确替换文件中的指定文本。",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string"},
"old_string": {"type": "string"},
"new_string": {"type": "string"}
},
"required": ["path", "old_string", "new_string"]
}
}
]
工具描述的重要性
description字段不是给人看的,是给模型看的。好的描述直接影响模型选择工具的准确性:
# 差的描述
"description": "执行命令"
# 好的描述
"description": "在服务器上执行Shell命令。支持管道、重定向、环境变量。
适用场景:系统管理、进程控制、网络诊断、包管理。
注意:命令会在bash环境下执行,Windows系统使用bash兼容层。"
并行工具调用
现代Agent支持并行工具调用。当多个操作之间没有依赖关系时,同时执行可以显著提升效率:
# 串行执行(慢)
result1 = bash("php -v") # 等待...
result2 = bash("nginx -v") # 等待...
result3 = bash("mysql --version") # 等待...
# 总耗时 = t1 + t2 + t3
# 并行执行(快)
result1, result2, result3 = parallel(
bash("php -v"),
bash("nginx -v"),
bash("mysql --version")
)
# 总耗时 = max(t1, t2, t3)
四、上下文管理
Agent在多步执行过程中会积累大量上下文(每步的命令和输出)。但大模型的上下文窗口是有限的,如何管理是一个工程难题。
上下文膨胀问题
假设你让Agent分析一个日志文件,文件有10万行,每行100字符。如果把完整输出塞进上下文,直接超出任何模型的窗口限制。
解决策略
- 输出截断:工具返回结果时,超过一定长度自动截断,只保留头尾
- 增量读取:文件读取工具支持
offset和limit参数,按需读取 - 摘要压缩:历史对话过长时,用模型自动摘要压缩早期内容
- 工具选择优化:用
grep搜索而不是cat全文件,减少无关输出
# 差的做法:读取整个日志文件
read_file("/var/log/app.log") # 可能返回50MB文本
# 好的做法:精确搜索
bash("grep 'ERROR' /var/log/app.log | tail -20") # 只返回最近20条错误
五、错误恢复机制
Agent执行过程中不可避免会遇到错误。好的Agent需要有自动恢复能力。
错误分类与应对
错误类型 | 应对策略
-----------------+----------------------------------
命令不存在 | 检查是否安装,尝试安装或换替代命令
权限不足 | 尝试sudo,或提示用户调整权限
超时 | 调整超时参数,或拆分为更小的操作
参数错误 | 分析错误信息,修正参数重试
依赖缺失 | 自动安装依赖后重试
网络不通 | 检查DNS、防火墙、代理设置
重试策略
关键原则:不要盲目重试相同的命令。每次重试前必须分析错误原因并调整:
# 差的重试
for i in range(3):
result = bash("some_command")
if result.ok: break
time.sleep(5) # 盲目等待重试
# 好的重试
result = bash("some_command")
if not result.ok:
error_analysis = llm.analyze(result.stderr) # 让模型分析错误原因
fix_action = llm.suggest_fix(error_analysis) # 决定修复策略
bash(fix_action) # 执行修复
result = bash("some_command") # 然后重试
六、多Agent协作
复杂任务可以拆分给多个专门化的Agent协作完成:
- 主Agent:接收用户指令,拆解任务,分配给子Agent
- 研究Agent:负责信息搜索和代码分析
- 编码Agent:负责代码编写和修改
- 测试Agent:负责运行测试和验证结果
多Agent架构的挑战在于上下文同步:子Agent无法看到主Agent的完整对话历史,所以主Agent必须在分配任务时提供足够的上下文。
# 主Agent向子Agent委派任务时的Prompt设计
sub_agent_prompt = f"""
## 背景
用户需要部署一个PHP网站到IIS服务器。
## 已完成的步骤
1. 文件已解压到 C:\\mysite
2. IIS和PHP已确认安装
## 你的任务
创建IIS站点,绑定80端口。完成后验证localhost能访问。
## 约束
- 如果80端口被占用,先停掉占用的站点
- 验证完成后报告结果
"""
七、Agent开发的工程建议
- 从小工具集开始:不要一开始就注册50个工具,模型选择会变得不准确。5-10个核心工具就够了。
- 工具描述要精确:这是影响Agent准确率最大的因素之一。
- 设置合理的超时:避免Agent卡在一个长时间运行的命令上。
- 记录完整的执行日志:调试Agent问题时,完整的工具调用链路是最关键的信息。
- 设计退出条件:防止Agent陷入无限循环。设置最大步骤数和最大Token消耗限制。