「AI Agent编程学习系列」第1篇:从ChatBot到Agent,AI代理的本质跃迁
你的AI还在"一问一答",别人的AI已经能自主订机票、写代码、发邮件了。差距到底在哪?
开篇钩子
2023年,ChatGPT让全世界见识了"对话AI"的威力。但很快,开发者们发现一个问题:它只能"说",不能"做"。你让它查天气,它给你一段文字描述;你让它订餐厅,它告诉你"抱歉,我没有这个功能"。而与此同时,AutoGPT、Devin、Manus等产品却开始自主浏览网页、调用API、执行代码,甚至完成复杂的业务流程。这背后的分水岭,正是从ChatBot到Agent的跃迁。理解这个跃迁,是你迈入AI Agent编程世界的第一课。
核心概念
什么是ChatBot?
ChatBot(聊天机器人)的核心模式是输入-处理-输出。用户发送一条消息,大语言模型(LLM)基于训练数据生成回复,然后对话结束。它的本质是** Stateless(无状态)的文本生成器**——每次交互都是独立的,不记忆上下文,不调用外部工具,也不执行实际操作。
典型特征:
- 被动响应:等待用户提问
- 纯文本交互:只输出文字,不操作外部系统
- 无记忆能力:多轮对话靠上下文窗口硬撑
- 知识截止:无法获取实时信息
什么是Agent?
Agent(智能代理)的核心模式是感知-决策-行动-反馈的循环。它不仅能"说",还能"做"。Agent可以调用工具(Tool)、访问外部API、执行代码、读写文件,甚至根据执行结果调整下一步策略。它的本质是Stateful(有状态)的自主执行体。
典型特征:
- 主动规划:能分解复杂任务并制定执行计划
- 工具调用:可以调用函数、API、数据库等外部资源
- 记忆管理:具备短期记忆(上下文)和长期记忆(向量数据库)
- 自主迭代:根据执行反馈自我修正,直到任务完成
本质区别:从"回答问题"到"完成任务"
用一个类比:ChatBot像一位知识渊博但只能口头建议的顾问;Agent像一位既能给建议、又能动手执行的助理。当你说"帮我安排一次北京到上海的出差",ChatBot会告诉你"你可以查携程、订高铁、找酒店";而Agent会真的去查航班、比价、订酒店、写行程单,最后把确认邮件发给你。
原理图解
Agent的核心循环被称为ReAct框架(Reasoning + Acting):先思考(Reasoning),再行动(Acting),然后根据观察结果(Observation)继续思考,形成闭环。这个循环让Agent具备了"自主解决问题"的能力,而不是"一次性回答问题"的能力。
代码实战
下面用Python实现一个最简版的ReAct Agent,让你直观感受Agent的工作机制。
import json
import re
# ============================================
# 1. 定义工具集:Agent的"手"
# ============================================
def search_weather(city: str) -> str:
"""查询城市天气(模拟)"""
weather_db = {
"北京": "晴天,25°C",
"上海": "小雨,22°C",
"深圳": "多云,28°C"
}
return weather_db.get(city, "暂无该城市天气数据")
def calculate(expression: str) -> str:
"""计算数学表达式"""
try:
# 安全计算:仅允许基本运算符
result = eval(expression, {"__builtins__": {}}, {})
return str(result)
except Exception as e:
return f"计算错误: {e}"
# 工具注册表:Agent可调用的所有工具
TOOLS = {
"search_weather": {
"description": "查询指定城市的天气情况",
"parameters": {"city": "城市名称,如北京、上海、深圳"}
},
"calculate": {
"description": "计算数学表达式",
"parameters": {"expression": "数学表达式,如 25 * 4 + 10"}
}
}
# ============================================
# 2. 模拟LLM:生成思考与行动
# ============================================
def mock_llm_react(prompt: str) -> dict:
"""
模拟LLM的ReAct输出
真实场景中,这里应调用OpenAI/Claude等API
"""
# 模拟LLM解析用户意图并生成ReAct格式的响应
if "天气" in prompt and "温度" in prompt:
return {
"thought": "用户想知道某城市的天气和温度,我需要先查询天气。",
"action": "search_weather",
"action_input": {"city": "北京"}
}
elif "计算" in prompt or "等于" in prompt:
# 提取表达式(简化处理)
expr = re.search(r'[\d\+\-\*\/\(\)\.]+', prompt)
if expr:
return {
"thought": "用户要求计算,我需要调用计算工具。",
"action": "calculate",
"action_input": {"expression": expr.group()}
}
return {
"thought": "任务已完成,可以直接回答用户。",
"action": "finish",
"action_input": {}
}
# ============================================
# 3. Agent核心循环:感知-规划-执行-反馈
# ============================================
class SimpleAgent:
def __init__(self):
self.tools = TOOLS
self.memory = [] # 短期记忆:存储交互历史
def execute_tool(self, action: str, action_input: dict) -> str:
"""执行工具调用"""
if action == "search_weather":
return search_weather(**action_input)
elif action == "calculate":
return calculate(**action_input)
return "未知工具"
def run(self, user_input: str, max_steps: int = 5) -> str:
"""
Agent主循环
max_steps: 最大迭代次数,防止无限循环
"""
print(f"[用户输入] {user_input}")
print("=" * 50)
step = 0
while step < max_steps:
step += 1
print(f"\n--- 第 {step} 步 ---")
# 构建包含上下文的提示
context = f"用户问题: {user_input}\n"
if self.memory:
context += f"历史记录: {self.memory}\n"
context += f"可用工具: {json.dumps(self.tools, ensure_ascii=False)}\n"
# 调用LLM进行推理(此处用mock替代)
response = mock_llm_react(context + user_input)
thought = response["thought"]
action = response["action"]
action_input = response["action_input"]
print(f"[思考] {thought}")
print(f"[行动] {action}({action_input})")
# 判断是否需要结束
if action == "finish":
return "任务完成"
# 执行工具并获取观察结果
observation = self.execute_tool(action, action_input)
print(f"[观察] {observation}")
# 将结果存入记忆
self.memory.append({
"thought": thought,
"action": action,
"observation": observation
})
return "达到最大步数限制"
# ============================================
# 4. 运行Agent
# ============================================
if __name__ == "__main__":
agent = SimpleAgent()
# 测试场景1:查询天气
result = agent.run("北京今天天气怎么样?温度多少?")
print(f"\n[最终结果] {result}")
print("\n" + "=" * 50)
# 测试场景2:数学计算
agent2 = SimpleAgent() # 新建实例,清空记忆
result2 = agent2.run("帮我计算 25 * 4 + 100 等于多少?")
print(f"\n[最终结果] {result2}")
代码解读:
-
工具层(Tools):
search_weather和calculate是Agent可调用的外部能力。真实项目中,这里可能是调用OpenWeatherMap API、执行SQL查询、发送邮件等。 -
模拟LLM:
mock_llm_react模拟了LLM的推理过程。实际开发中,你需要构造ReAct格式的Prompt,调用GPT-4/Claude等模型,让其输出Thought/Action/Action Input结构。 -
Agent循环:
SimpleAgent.run()实现了核心的感知-规划-执行-反馈循环。每次迭代,Agent都会基于当前状态重新规划下一步行动,直到任务完成或达到步数上限。 -
记忆机制:
self.memory存储了每一步的思考和观察结果,让Agent具备多步推理能力。
踩坑指南
坑1:LLM"幻觉"调用不存在的工具
现象:Agent尝试调用一个未注册的工具,导致程序报错。
解决:在Prompt中明确列出可用工具,并设置严格的输出格式约束(如JSON Schema)。同时做好异常捕获:
def execute_tool(self, action: str, action_input: dict) -> str:
if action not in self.tools:
return f"错误:工具 '{action}' 不存在。可用工具: {list(self.tools.keys())}"
# ... 正常执行
坑2:无限循环
现象:Agent在两个动作之间反复横跳,永远无法结束。
解决:设置最大迭代次数(max_steps),并在Prompt中明确告知LLM"如果无法解决,请调用finish结束"。
坑3:工具返回结果过长,撑爆上下文窗口
现象:Agent调用了返回大量数据的工具(如查询数据库返回1000行),导致后续推理质量下降。
解决:对工具返回结果做截断和摘要处理。例如只保留前500字符,或用另一个LLM调用对结果做摘要后再传入上下文。
坑4:状态污染
现象:多用户同时使用Agent时,记忆互相串扰。
解决:每个用户会话创建独立的Agent实例,或使用线程隔离的上下文管理。
进阶思考
1. 从单Agent到多Agent协作
复杂任务(如软件开发)往往需要多个Agent协作:一个负责需求分析、一个负责编码、一个负责测试。多Agent系统通过消息队列或共享状态进行协作,这是当前最前沿的研究方向之一。开源框架如AutoGen、CrewAI、LangGraph都在探索这一领域。
2. Agent的安全边界
Agent能执行代码、调用API,意味着它也可能造成破坏。如何给Agent设置"安全护栏"?常见策略包括:
- 沙箱执行:代码在隔离环境中运行
- 权限分级:敏感操作需要人工确认
- 审计日志:记录所有工具调用以便追溯
3. 成本与延迟的权衡
每轮ReAct循环都需要调用一次LLM API。一个复杂任务可能需要10轮以上,成本和时间都会累积。优化方向包括:
- 使用更小的模型做初步规划,大模型做关键决策
- 将常见任务模式预编译为工作流,减少实时推理
- 引入缓存机制,避免重复调用
4. 评估Agent性能
如何知道你的Agent做得好不好?传统LLM评估指标(如BLEU、ROUGE)不再适用。Agent评估需要关注:
- 任务完成率:是否达成了目标
- 步数效率:用了多少步完成任务
- 成本效率:消耗了多少Token
- 安全性:是否触发了不该调用的工具
文末互动
你第一次接触Agent概念是在哪个项目或产品中?是AutoGPT的爆火,还是LangChain的教程?欢迎在评论区分享你的Agent初体验。下一篇,我们将深入Agent的五层架构模型,从LLM内核到交互界面逐层拆解,帮你建立系统性的Agent设计思维。
每天进步一点点,坚持带来大改变,加油💪!~!
更多推荐



所有评论(0)