一个常被混淆的问题
"我让 GPT 调用了一个查天气的 API,这算不算 Agent?"
这是我被问得最多的问题之一。答案是:不完全算。 会调用工具,只是 Agent 的起点,远不是终点。
很多人以为"工具调用 = Agent",于是接了个 Function Calling 就觉得自己做出了智能体。但真正的自主 Agent 和"会调工具的模型"之间,隔着好几级台阶。
这篇我想把这几级台阶讲清楚:从最基础的工具调用,一步步走到能自己规划、自己决策、自己纠错的自主 Agent,中间到底发生了什么。
一、第一级:工具调用——让模型「能动手」
最基础的一级,是让模型能调用外部工具。
模型本身只会生成文本,它不会查数据库、不会发邮件、不会跑代码。工具调用解决的就是"动手"问题——你给模型一份工具清单,它根据需要决定调哪个、传什么参数。
tools = [{
"name": "get_weather",
"description": "查询指定城市的天气",
"parameters": {"city": "string"}
}]
# 模型决定调用
response = llm.chat(query="北京今天天气怎么样", tools=tools)
# 返回: {"tool": "get_weather", "args": {"city": "北京"}}
这一级的关键词是单次、被动:用户问一句,模型调一次工具,返回结果,结束。它没有"下一步"的概念。
这就是为什么我说它只是起点——它能动手,但还不会"自己想接下来干什么"。
二、第二级:多步循环——让模型「连续干」
往上一级,是让模型能连续地调用工具,直到任务完成。这就是经典的 ReAct 循环:想一步、做一步、看结果、再想下一步。
Thought(我该查什么)
→ Action(调用工具)
→ Observation(看返回)
→ Thought(根据结果,下一步干什么)
→ ……循环直到完成
到这一级,Agent 开始有了"过程"。它能把一个需要好几步的任务拆开来一步步做,比如"帮我查北京和上海的天气,然后告诉我哪个更适合户外活动"——它会先查北京、再查上海、最后综合判断。
但它的"规划"还是临时的、走一步看一步的,没有全局视野。任务一复杂,就容易跑偏。
三、第三级:任务规划——让模型「先想清楚再动手」
这一级的跃迁很关键:Agent 不再走一步看一步,而是先把整个任务拆成计划,再按计划执行。
def plan_and_execute(goal):
# 1. 先规划:把大目标拆成有序的子任务
plan = llm.plan(goal)
# plan = ["查北京天气", "查上海天气", "对比并给建议"]
results = []
# 2. 再执行:按计划逐步推进
for step in plan:
result = execute_step(step, context=results)
results.append(result)
# 3. 关键:每步后检查计划是否还成立
if need_replan(result):
plan = llm.replan(goal, results) # 动态调整
return summarize(results)
注意第 3 步——动态重规划。计划不是定死的,执行中发现情况变了(某个工具失败、查到的信息推翻了原假设),Agent 能回头修改计划。这是它和"死板执行脚本"的本质区别。
有了规划能力,Agent 才算有了"全局视野",能应对真正复杂的多步任务。
四、第四级:自主决策与纠错——让模型「自己兜底」
最高的一级,是 Agent 能自己判断对错、自己从错误里恢复,而不是一遇到问题就卡死或向你求救。
这一级有两个核心能力:
1. 自我反思(Reflection)
Agent 做完一步后,回头审视自己的产出:"这个结果合理吗?有没有更好的做法?"
def execute_with_reflection(task):
result = execute(task)
# 让模型批判自己的产出
critique = llm.reflect(task, result)
if critique.has_problem:
# 根据自我批评,重做一次
result = execute(task, feedback=critique.suggestion)
return result
2. 错误恢复(Error Recovery)
工具调用失败是常态——超时、限流、返回格式不对。成熟的 Agent 不会因为一次失败就崩溃,而是有兜底策略:重试、换工具、降级方案。
def robust_call(tool, args, max_retry=3):
for attempt in range(max_retry):
try:
return tool.run(args)
except ToolError as e:
if attempt == max_retry - 1:
return fallback(tool, args) # 最后兜底
args = llm.fix_args(args, error=e) # 让模型修正参数再试
走到这一级,Agent 才真正配得上"自主"二字——它能独立完成任务,遇到坑能自己爬出来,不用你全程盯着。
五、四级能力对照
把这四级摆在一起看,跃迁的脉络就很清楚了:
| 级别 | 能力 | 关键词 | 能干什么 |
|---|---|---|---|
| 一级 | 工具调用 | 单次、被动 | 查个天气、调个 API |
| 二级 | 多步循环 | 连续、ReAct | 拆几步完成一个小任务 |
| 三级 | 任务规划 | 全局、可重规划 | 处理复杂多步任务 |
| 四级 | 自主决策 | 反思、自纠错 | 独立兜底,无需盯防 |
每一级都建立在前一级之上,是叠加而非替代。
六、我踩过的三个坑
从工具调用做到自主 Agent,我交过的学费,挑三个最值的分享:
坑一:工具给太多,模型反而选不对。 一开始我恨不得把几十个工具全塞给模型,结果它经常选错。后来才明白——工具列表越短,模型选择越准。按任务动态裁剪工具集,比一股脑全给强得多。
坑二:没有步数上限,Agent 会无限循环。 自主 Agent 有时会陷入"调用-失败-重试-再失败"的死循环,把 token 烧光。一定要设 max_steps 硬上限,到顶就强制收尾。
坑三:自主≠放任。 高危操作(删数据、付钱、对外发送)即便 Agent 能自主决策,也必须留一道人工确认。自主是为了省心,不是为了失控。
写在最后
回头看这条路:工具调用 → 多步循环 → 任务规划 → 自主决策,本质是一个"把人从循环里逐步解放出来"的过程。
会调工具的,只是个听话的执行器;能自己规划、自己纠错的,才是真正的 Agent。
但也别盲目追最高级。任务简单,一级工具调用就够了,上自主 Agent 纯属过度设计。选对级别,比堆能力更重要。