Appearance
什么是 AI Agent
定义
我们先看AI Agent的定义,不一定非常专业,但是足够我们理解:
AI Agent 是一个能够围绕目标,自主判断下一步行动,使用工具与外部环境交互,并根据执行结果持续调整,直到完成任务或触发停止条件的系统。
这个定义里面有几个关键词。
目标,决定 Agent 最终要完成什么。
比如:
- 修复一个项目里的登录 Bug
- 调研几个 Coding Agent 产品
- 分析网站注册量为什么下降
- 处理一条用户售后请求
Agent 面对的通常不仅仅是一道单纯的问答题,而是一个需要逐步推进的任务。
判断,意味着系统需要根据当前情况决定下一步做什么。
例如 Coding Agent 在修复 Bug 时,并不知道一开始就应该修改哪个文件。它可能先搜索代码,再读取相关模块,然后根据找到的信息继续判断。
行动,意味着 Agent 不只是生成文字。
它还可以调用工具,例如:
- 搜索网页
- 读取文件
- 执行命令
- 查询数据库
- 操作浏览器
- 调用业务 API
反馈,指的是 Agent 执行一个动作以后,会拿到新的结果。
比如:
text
执行测试
↓
测试失败
↓
获得错误信息错误信息就是一次新的反馈。
Agent 会根据这个反馈继续决定下一步,而不是执行一次以后就结束。
所以定义里最重要的一句话其实是:
围绕目标持续推进任务。
这也是 Agent 和普通一次性模型调用之间最明显的差别之一。
Agent 的核心:一个持续执行的循环
理解 Agent 最重要的,并不是先记住一堆组件名称,而是先理解它的执行过程。
一个最简单的 Agent,可以抽象成下面这个循环:
text
目标
↓
判断下一步
↓
执行行动
↓
观察结果
↓
判断是否完成
↓
继续行动 / 结束也可以进一步压缩成:
text
目标 → 决策 → 行动 → 反馈 → 再决策这个循环通常被称为 Agent Loop。
还是以 Coding Agent 为例。
现在给它一个任务:
修复登录接口返回 500 的问题。
Agent 可能先读取错误日志。
text
读取错误日志
↓
发现 NullPointerException根据这个结果,它继续搜索相关代码:
text
搜索登录接口
↓
找到 LoginService然后读取实现:
text
读取 LoginService
↓
发现某个用户对象可能为空接着修改代码并运行测试:
text
修改代码
↓
运行测试
↓
测试失败这时候任务还没有结束。
Agent 会继续读取新的错误信息,再次判断:
text
读取错误
↓
重新分析
↓
继续修改
↓
再次测试直到测试通过,或者系统认为已经无法继续处理。
完整过程可能变成:
text
修复登录接口
↓
读取错误
↓
搜索代码
↓
分析原因
↓
修改代码
↓
执行测试
↓
观察结果
↙ ↘
失败 成功
↓ ↓
继续分析 完成任务这里真正关键的是:
前一步产生的结果,会影响下一步做什么。
测试失败以后继续修改。
搜索不到信息以后继续搜索。
查询数据发现异常以后继续拆分维度。
正是这种不断根据环境反馈调整下一步动作的过程,让 Agent 从“一次模型调用”变成了一个持续运行的系统。
Agent 是一个系统,不是一个模型
我们千万不要认为 Agent 就是一个大模型。
在目前常见的 LLM Agent 中,大语言模型通常负责核心的理解、推理和决策,但一个真正能够执行任务的 Agent,还需要很多其他部分配合。
可以先把一个 Agent 简化成下面这个结构:
text
目标
↓
┌─────────┐
│ 模型 │
└─────────┘
↓
判断下一步
↓
┌──────────────┐
│ 工具 │
└──────────────┘
↓
执行并返回结果
↓
┌──────────────┐
│ 状态 │
└──────────────┘
↓
再次进入模型除此之外,系统还需要一套控制逻辑,决定整个循环怎么运行。
模型负责理解和决策
在目前主流的 LLM Agent 中,大语言模型通常承担核心的理解和决策能力。
例如用户提出:
帮我修复项目中的登录问题。
模型需要先理解:
- 任务目标是什么
- 当前有哪些上下文
- 已经知道哪些信息
- 还缺少哪些信息
- 下一步应该调用什么工具
假设 Agent 已经获得一条错误日志:
text
NullPointerException at LoginService.java:82模型可能判断:
下一步应该读取
LoginService.java附近的代码。
于是生成一次工具调用。
读取代码以后,又获得新的信息。
模型再根据新的上下文判断下一步。
所以可以先把模型理解成 Agent 的“决策核心”。
它主要负责解决:
现在应该做什么?
但模型本身通常并不能直接完成所有真实动作。
它需要工具。
工具负责获取信息和执行动作
如果模型只能够生成文字,那么它知道得再多,很多任务也只能停留在“给建议”。
例如模型可能判断:
应该检查
LoginService.java。
但如果它无法读取文件,就只能告诉我们:
请打开
LoginService.java检查第 82 行。
Agent 则可以直接调用文件工具:
text
read_file("LoginService.java")然后把真实代码读取回来。
工具可以非常多。
Coding Agent 可能拥有:
text
读取文件
搜索代码
修改文件
执行命令
运行测试
GitResearch Agent 可能拥有:
text
搜索
打开网页
读取文档Data Agent 可能拥有:
text
数据库查询
SQL 执行
数据分析Browser Agent 可能拥有:
text
打开网页
点击
输入
滚动
下载文件企业里的 Agent 还可能直接连接业务系统:
text
订单 API
CRM
ERP
工单系统
内部知识库所以工具解决的是另外一个问题:
Agent 怎么真正和外部世界发生交互?
可以把模型和工具简单理解成:
text
模型:决定做什么
工具:真正去做当然,真实系统会更加复杂,但这个理解对于入门已经足够。
状态记录任务进行到了哪里
Agent 经常需要执行很多步。
假设 Coding Agent 已经完成:
text
读取报错
↓
搜索代码
↓
修改文件
↓
第一次测试失败
↓
第二次修改当它进入下一轮判断时,系统必须知道前面已经发生了什么。
否则它可能重新做一遍相同的事情。
所以 Agent 通常需要保存一定的 State,也就是状态。
状态里可能包括:
text
当前目标
已经执行过的步骤
工具调用结果
读取过的文件
中间生成的内容
错误信息
剩余任务例如:
text
目标:
修复登录接口
已读取:
LoginController.java
LoginService.java
已修改:
LoginService.java
测试结果:
仍有一个异常
下一步:
继续检查 UserRepository这些内容共同描述了:
任务现在进行到了什么位置。
这也是为什么复杂 Agent 很少只是:
text
Prompt → LLM → 输出而更像一个持续维护上下文和任务状态的执行系统。
这里先理解 State 就可以。
后面涉及 Memory、Context Engineering 等概念时,我们再继续展开。
控制逻辑决定什么时候继续、什么时候停止
如果只有:
text
判断
↓
行动
↓
反馈
↓
继续判断还不够。
因为理论上 Agent 可以一直循环下去。
例如:
text
测试失败
↓
继续修改
↓
测试失败
↓
继续修改
↓
测试失败
↓
……显然不能无限执行。
所以 Agent 系统通常还需要一套控制逻辑。
它需要决定:
- 什么时候任务已经完成
- 什么时候应该继续执行
- 失败以后是否重试
- 最多允许执行多少步
- 最多允许消耗多少成本
- 哪些操作可以直接执行
- 哪些操作必须人工确认
- 出现什么情况应该终止
例如 Coding Agent 可以自动:
text
读取文件
搜索代码
运行测试但如果接下来要执行:
text
删除生产数据库系统显然不应该让它直接继续。
这时候就可能需要:
text
Agent 请求执行高风险操作
↓
暂停执行
↓
请求人工确认
↙ ↘
允许 拒绝
↓ ↓
继续执行 停止所以真正完整的 Agent Loop 并不是无限自主循环。
它始终运行在一套规则和边界之内。
Agent 的“自主”到底是什么意思
Agent 经常会和一个词一起出现:
自主性(Autonomy)。
但这个词也很容易造成误解。
看到“自主 Agent”,很容易联想到:
给它一个目标以后,系统就像一个真正的人一样,完全自己想办法完成所有事情。
实际工程中的 Agent 通常不是这样。
Agent 的自主性更多指:
在给定目标和允许的边界内,根据当前状态动态决定下一步行动。
Agent 不是完全自由行动
还是以 Coding Agent 为例。
用户只提出:
修复登录接口。
Agent 可以自己决定:
text
先看错误日志
还是先搜索代码?
应该读取哪个文件?
应该调用什么工具?
修改以后要运行什么测试?
测试失败以后下一步查哪里?这些步骤没有全部提前写死。
这就是它的自主性。
但与此同时,它可以受到很多限制。
例如只允许使用这些工具:
text
读取文件
修改文件
搜索代码
运行测试不允许:
text
访问项目之外的目录
修改服务器配置
删除数据库
直接发布生产环境也可以限制执行次数:
text
最多执行 30 步限制成本:
text
最多消耗一定 Token还可以规定:
text
删除文件 → 需要确认
执行高风险命令 → 需要确认
部署生产环境 → 需要确认所以更准确的理解不是:
Agent 可以自由做任何事情。
而是:
Agent 可以在系统给定的边界里,自主决定怎么完成任务。
这也是实际开发 Agent 时非常重要的设计原则。
能力越强,并不意味着权限就应该越大。
自主程度可以不同
Agent 的自主性也不是一个简单的“有”或者“没有”。
不同系统可以有完全不同的自主程度。
例如最受控的方式可能是:
text
用户指定每一步
↓
模型只完成当前步骤再往前一步:
text
流程提前确定
↓
部分节点由模型判断自主程度再高一些:
text
给定目标
↓
模型自己选择工具
↓
根据结果决定下一步再继续增加:
text
给定一个较大的目标
↓
Agent 自己拆分任务
↓
连续执行很多步骤
↓
中途只在必要时请求人工介入可以简单看成一个连续范围:
text
人工控制较多
↓
模型完成局部判断
↓
模型动态选择工具
↓
模型动态规划执行路径
↓
较长时间自主推进任务所以讨论一个 Agent 时,只问:
它是不是 Agent?
有时候还不够。
还可以继续看:
它拥有多大的自主空间?
不同业务需要的答案也完全不同。
代码搜索可以允许较高自主性。
生产环境部署则需要更加严格的控制。
普通资料调研可以连续执行很多步。
高风险业务操作则可能每一步都需要权限检查。
Agent 的自主程度应该服务于任务,而不是越高越好。
一个最小 Agent 长什么样
把前面的内容放到一起,我们已经可以搭出一个非常简单的 Agent。
假设现在要做一个最小 Coding Agent。
目标只有一个:
修复项目中的登录接口异常。
系统拥有一个大语言模型,以及四个工具:
text
读取文件
搜索代码
修改文件
执行测试然后整个 Agent 开始运行。
第一步,模型理解目标:
text
目标:
修复登录接口异常目前没有足够信息,于是判断:
先找到登录相关代码。
调用搜索工具:
text
search_code("login")工具返回:
text
LoginController.java
LoginService.java
AuthService.java模型读取结果以后,继续判断:
先查看 LoginController 和 LoginService。
调用读取文件工具。
拿到代码以后发现一个潜在问题,于是继续调用修改工具。
text
修改 LoginService.java修改完成以后,Agent 判断:
需要验证刚才的修改。
于是执行测试。
text
run_test()测试结果:
text
FAILED
UserRepository mock is null任务还没有完成。
Agent 根据新的反馈继续判断:
问题可能还涉及 UserRepository。
于是再次搜索、读取、修改,然后运行测试。
整个过程变成:
text
用户目标
↓
修复登录接口
↓
搜索代码
↓
读取文件
↓
分析问题
↓
修改代码
↓
执行测试
↓
观察结果
↙ ↘
测试失败 测试通过
↓ ↓
继续分析 完成任务
↓
再次行动现在回头看,这个最小系统里已经出现了 Agent 的几个关键部分:
目标
text
修复登录接口模型
负责理解任务、分析结果和决定下一步。
工具
text
读取
搜索
修改
测试状态
记录已经读取了什么、修改了什么、测试结果是什么。
执行循环
text
判断 → 行动 → 观察 → 再判断停止条件
text
测试通过
→ 任务完成或者:
text
达到最大执行次数
→ 停止到这里,一个最基本的 Agent 结构其实已经出现了。
它不一定需要复杂的框架,也不一定需要几十种工具。
真正关键的是:
系统能够围绕一个目标,在执行过程中不断观察结果,并动态决定下一步。
总结
理解 AI Agent,可以先抓住三个核心认识。
第一:
Agent 是一个系统,不是一个模型。
大语言模型通常承担理解和决策能力,但 Agent 还需要工具、状态、控制逻辑等部分共同运行。
第二:
Agent 的核心执行方式可以抽象成一个循环:
text
目标
↓
判断
↓
行动
↓
观察
↓
再判断
↓
……
↓
完成任务也就是:
目标 → 决策 → 行动 → 反馈 → 再决策
第三:
Agent 所谓的“自主”,并不是无限自由。
更准确地说:
Agent 在给定目标和系统边界内,根据当前状态动态决定下一步。
到这里,可以先把 AI Agent 理解成:
一个围绕目标持续获取信息、做出判断、使用工具并根据反馈不断推进任务的系统。
至于一个系统会调用工具、会执行多步任务以后,就一定算 Agent 吗?
Agent、Workflow、RAG 和普通聊天应用之间又该怎么区分?
这些概念的边界,我们再放到后面单独讨论。