一、先搞清楚:Agent 到底是什么
很多人第一次听到 Agent(智能体),会觉得它是一个很玄的概念,好像必须是某种「会自己干活的机器人」。但如果把它拆开看,核心其实只有一句话:Agent = 大模型 + 循环 + 工具 + 记忆。它不是一个新模型,而是一种「使用模型的方式」——让模型不再是一问一答的「函数」,而是一个能在多轮交互中自主决策、调用外部能力、逐步逼近目标的「小系统」。
我个人比较认同的定义是:Agent 是一个能够感知环境、制定计划、采取行动、根据反馈调整的程序。这里的「环境」可以是浏览器、文件系统、数据库,也可以只是对话上下文。判断一个东西是不是 Agent,关键看它有没有「自主性」——是否能在没有人类逐步指令的情况下,自己决定下一步做什么。
提示:不要把 Agent 和「机器人」「RPA」混淆。RPA 是按固定流程执行,Agent 的每一步是模型现场推理出来的,路径不固定。
二、大模型在 Agent 里扮演什么角色
如果说 Agent 是一个「人」,那大模型就是它的大脑,而且是一个只负责「思考和决策」的大脑。它自己不会查天气、不会读文件、不会发请求——它的输出只是一段文本(或结构化的调用意图)。真正去「动手」的是外面包裹的那层程序,也就是我们写的编排代码。
这里有个关键认识:大模型是概率模型,Agent 是工程系统。模型负责在每一步给出「下一步该干什么」的建议,工程代码负责校验、执行、把结果喂回去。所以同一个模型,配上不同的工具集和循环策略,会变成能力差别巨大的 Agent——写代码的、做数据分析的、当客服的,底层可能都是同一个 LLM。
理解了这一点,你就明白为什么说「Agent 是大模型的应用范式」而不是「更强的大模型」。大模型能力越强,Agent 的决策质量越高,但 Agent 的上限也取决于工具是否好用、上下文管理是否得当、失败后能否恢复。
三、Agent 的核心循环:感知—规划—行动—反思
几乎所有 Agent 的骨架都是同一个循环(Loop),可以用四个词概括:
- 感知(Perceive):接收用户目标和环境反馈,组装成上下文;
- 规划(Plan):模型根据上下文推理,决定下一步动作(回答、调用工具、继续分解任务);
- 行动(Act):执行工具调用,拿到真实世界的结果;
- 反思(Reflect):把结果和预期对比,判断是否完成、是否需要修正。
这个循环会一直转,直到「目标达成」或者「达到最大轮数/预算」。你会发现,所谓「自主」其实就是循环里的每一步都由模型决定,而不是由 if-else 决定。ReAct(Reasoning + Acting)、Plan-and-Execute 等常见 Agent 框架,区别只是这个循环的组织方式不同:前者边想边做,后者先列计划再逐步执行。
提示:实践中最容易忽略的是终止条件。没有 max_rounds、预算上限或明确的「完成判据」,Agent 会陷入死循环疯狂烧 token。
四、工具调用(Tool Use):让 LLM 长出「手和脚」
工具调用(Function Calling / Tool Use) 是 Agent 能落地的技术基石。它的机制并不神秘:我们用 JSON Schema 向模型「描述」有哪些工具、参数是什么,模型在需要时输出一段结构化的调用意图,我们的程序解析这段意图、真正执行函数,再把返回值塞回对话历史,模型据此继续推理。
工具的设计质量直接决定 Agent 的智商。好的工具应该是职责单一、参数明确、返回结构化、错误信息可读的。把「读写整个文件系统」做成一个工具,不如拆成 read_file、write_file、list_dir,这样模型更容易做出正确决策,也更容易被权限控制。
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的当前天气,用于回答用户关于天气的问题",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名,例如:杭州"}
},
"required": ["city"],
},
},
}
]
五、记忆与上下文工程:Agent 的「长期资产」
大模型本身是无状态的,每次调用都是一张白纸。所谓 Agent 的「记忆」,本质上是我们把历史信息重新塞进上下文窗口的结果。因此 Agent 的记忆分层其实是个工程问题:
- 短期记忆:当前任务的对话历史和中间结果,存在
messages列表里; - 长期记忆:跨任务的知识,通常用向量数据库做
RAG检索,或者写入笔记文件; - 工作记忆:当前正在处理的任务清单、变量、待办,类似「草稿纸」。
上下文窗口是稀缺资源,塞太多会稀释注意力、增加成本,塞太少模型会「失忆」。所以成熟的 Agent 都会做上下文裁剪:摘要压缩旧轮次、只保留关键工具结果、把超长输出落盘只留引用。记住一句话:写 Agent 的大部分精力,其实在做上下文管理,而不是写提示词。
六、从零写一个最小可用的 Agent
下面用 OpenAI 风格的 API 写一个最小 Agent,你能看到「循环 + 工具 + 反馈」的完整骨架。麻雀虽小,它已经具备了 Agent 的全部本质特征。
import json
import openai
client = openai.OpenAI()
def get_weather(city: str) -> dict:
"""假装在调用真实天气服务"""
return {"city": city, "temp": 26, "condition": "晴"}
def run_agent(task: str, max_rounds: int = 5) -> str:
messages = [{"role": "user", "content": task}]
for _ in range(max_rounds):
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=tools,
)
msg = resp.choices[0].message
messages.append(msg)
# 模型不再调用工具,认为可以给出最终答案
if not msg.tool_calls:
return msg.content
# 执行工具,并把结果作为「观察」喂回上下文
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = get_weather(**args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result, ensure_ascii=False),
})
return "达到最大轮数,任务未完成"
print(run_agent("杭州今天天气怎么样?适合出门吗?"))
注意其中两个细节:tool_call_id 必须原样回传,否则多工具并发时模型无法对应结果;工具报错时不要抛异常中断循环,而是把错误信息当作正常结果返回,模型看到「查询失败:城市不存在」后通常会自我纠正。
七、我踩过的坑与几点理解
最后分享几条实践中总结的认识。第一,不要过早引入复杂框架。LangChain、AutoGen 这类框架能加速原型,但它们抽象层太多,出问题时很难调试;先用几十行原生代码写明白循环,再考虑上框架。第二,Agent 的失败大多是「幻觉 + 过度自信」的组合——模型编造了不存在的工具参数,或者没检查结果就宣布任务完成,所以关键动作要做程序化校验。
第三,也是我认为最重要的:Agent 不是万能的。对于流程固定、可穷举的任务,写普通代码更可靠、更便宜;Agent 的价值在于那些「步骤无法预先确定、需要根据中间结果动态决策」的场景,比如代码调试、开放性调研、复杂数据处理。判断标准很简单:如果任务能画出确定的流程图,就别用 Agent。
提示:学习 Agent 最有效的方式不是读论文,而是亲手写一个能调用两三个工具、能自我纠错的小循环,然后观察它的 messages 是怎么演化的。理解了那条消息流,你就理解了 Agent 的 90%。