Agent 智能体开发学习博客(通俗原理 + 详细注释 · AI应用强化版)
Agent 是让大模型从“只会聊天”进化为“能自主执行任务”的关键技术。这篇博客从实际问题出发,用生活化类比建立直觉,通过术语详解深入概念本质,再用原理剖析、图解演示和可运行代码带你一步步理解。重点覆盖 Agent 面试中的高频考点。
一、初级篇:让模型“动起来”
1. 🔥 ReAct 模式:思考-行动-观察循环
问题
传统的 LLM 只能回答静态问题,如何让它能够自主地使用工具、分步完成任务,比如“帮我查一下北京天气,然后写一段周末出行建议”?
生活化类比
ReAct 就像你教一个实习生处理复杂任务:你告诉他“先思考需要什么信息,然后去执行(查资料、打电话),观察结果,再根据结果思考下一步,直到完成”。实习生不断循环这三步,最终交付成果。
术语详解
- ReAct= Reasoning(推理)+ Acting(行动)。它将大模型的思考和工具调用交织在一起,形成一个循环:
- 思考(Thought):分析当前状态,决定下一步做什么。
- 行动(Action):执行一个工具调用(如搜索、计算、API 调用)。
- 观察(Observation):接收工具返回的结果,作为下一次思考的输入。
这个循环一直重复,直到模型决定“任务完成”并输出最终答案。
原理
ReAct 模式的核心是把工具调用和推理过程统一成一个文本序列。每次循环,模型都会在上下文中追加一段“思考:…行动:…观察:…”,然后继续生成。这样,模型能利用之前的观察结果,动态调整后续行为,而不是一次性地预测所有步骤。相比固定流程的 Chain,ReAct 更灵活、更抗干扰。
图解演示:ReAct 循环流程
用户问题 │ ▼ ┌─────────────┐ │ 思考 (Thought) │ ← 分析现状,制定计划 └──────┬──────┘ │ 决定调用工具 ▼ ┌─────────────┐ │ 行动 (Action) │ ← 执行具体工具(搜索、计算...) └──────┬──────┘ │ 工具返回结果 ▼ ┌─────────────┐ │ 观察 (Observation)│ ← 接收结果,更新上下文 └──────┬──────┘ │ 任务未完成,回到思考 ▼ (重复) │ 任务完成 ▼ 输出最终答案演示用例:手写一个极简 ReAct Agent(伪代码 + 可运行简化版)
为了直观理解,我们用一个手动循环来模拟 ReAct,不使用任何 Agent 框架。模型通过解析输出中的特殊标记来决定是否调用工具。
# 模拟 ReAct 循环(演示核心思想,实际可用 OpenAI Function Calling 更稳健)fromopenaiimportOpenAIimportjson client=OpenAI()# 模拟外部工具:一个简单的词典查询deflookup_word(word:str)->str:"""模拟查询词典,返回词义"""dictionary={"苹果":"一种水果,通常是红色或绿色。","香蕉":"一种长条形黄色水果。","天气":"大气状况,如晴、雨、雪等。"}returndictionary.get(word,"未找到该词")# 工具列表(用文本形式告诉模型可调用的工具)tools_desc=""" 你可以调用以下工具: - lookup_word(word):查询一个词的含义,返回字符串。 当你需要查词时,输出格式为: Action: lookup_word Action Input: 要查的词 当你能直接回答时,输出格式为: Action: Finish Final Answer: 最终答案 """# ReAct 循环defreact_agent(user_query:str,max_steps:int=5):# 初始消息:系统指令 + 用户问题messages=[{"role":"system","content":f"你是一个智能助理。{tools_desc}\n请严格遵循格式输出。"},{"role":"user","content":user_query}]forstepinrange(max_steps):# 调用 LLM 生成思考+行动response=client.chat.completions.create(model="gpt-3.5-turbo",messages=messages,temperature=0.0)reply=response.choices[0].message.contentprint(f"--- Step{step+1}---")print(f"模型输出:\n{reply}")# 将模型的输出作为新消息加入对话(模拟上下文扩展)messages.append({"role":"assistant","content":reply})# 简单解析:查找 Action 和 Action Inputif"Action: Finish"inreply:# 提取最终答案final_answer=reply.split("Final Answer:")[-1].strip()returnfinal_answerelif"Action: lookup_word"inreply:# 提取要查的词word=reply.split("Action Input:")[-1].strip()# 执行工具observation=lookup_word(word)print(f"工具返回:{observation}")# 将观察结果作为新消息(通常以 "Observation: ..." 形式)messages.append({"role":"user","content":f"Observation:{observation}"})else:# 格式不符合预期,强行结束return"Agent 输出格式错误,无法继续。"return"达到最大步数,任务未完成。"# 测试result=react_agent("苹果是什么?")print("\n最终答案:",result)输出结果(示例,实际可能略有差异)
--- Step 1 --- 模型输出: Thought: 用户想知道“苹果”的含义,我需要查词典。 Action: lookup_word Action Input: 苹果 工具返回: 一种水果,通常是红色或绿色。 --- Step 2 --- 模型输出: Thought: 我已获得词义,可以回答用户。 Action: Finish Final Answer: 苹果是一种水果,通常是红色或绿色。 最终答案: 苹果是一种水果,通常是红色或绿色。面试要点:ReAct 循环的核心是思考-行动-观察的交互模式,面试官常问“ReAct 和普通的 Chain 有什么区别?”——Chain 是固定流程,ReAct 是动态决策。
AI 应用场景:ReAct 是构建能自主使用工具、搜索、计算、操作数据库的 Agent 的基础模式,也是 OpenAI Assistant API、LangChain Agent 等框架的底层逻辑。
2. ⭐ 记忆管理:缓冲记忆、摘要记忆、向量长期记忆
问题
对话越来越长,Agent 需要记住之前的交互内容。但直接把所有历史塞进上下文会导致 token 爆炸。如何高效管理记忆?
生活化类比
- 缓冲记忆就像你的草稿纸——只记最近几句话,用完就擦。
- 摘要记忆就像你的课堂笔记——每隔一段时间把前面的内容总结成要点。
- 向量长期记忆就像你的外部硬盘——把重要信息存到向量数据库,需要时再检索出来。
术语详解
- 缓冲记忆(Buffer Memory):直接保存最近 K 轮对话原文。简单但占空间,适合短对话。
- 摘要记忆(Summary Memory):用 LLM 将长对话逐步总结为一段摘要,只保留摘要。省 token 但可能丢失细节。
- 向量长期记忆(Vector Long-term Memory):将对话片段转为向量存入数据库,需要时用语义检索。保留细节且可扩展,但实现复杂。
原理
记忆管理的本质是在上下文窗口有限的情况下,尽可能保留对后续推理最有用的信息。缓冲记忆利用“最近性”(最近的信息最重要);摘要记忆利用“概括性”(压缩信息);向量记忆利用“相关性”(只提取与当前问题相关的历史)。三种方式常组合使用:短期用缓冲,长期用摘要或向量。
演示用例:使用 LangChain 实现三种记忆
# pip install langchain langchain-openaifromlangchain.memoryimportConversationBufferMemory,ConversationSummaryMemoryfromlangchain_openaiimportChatOpenAIfromlangchain.chainsimportConversationChain llm=ChatOpenAI(model="gpt-3.5-turbo",temperature=0.3)# ---- 1. 缓冲记忆:保留所有对话原文 ----buffer_memory=ConversationBufferMemory(return_messages=True)chain_buffer=ConversationChain(llm=llm,memory=buffer_memory)chain_buffer.predict(input="你好,我是小明。")chain_buffer.predict(input="我喜欢吃苹果。")# 查看当前记忆中的消息(完整历史)print("缓冲记忆中的消息数量:",len(buffer_memory.chat_memory.messages))# ---- 2. 摘要记忆:逐步压缩历史为摘要 ----summary_memory=ConversationSummaryMemory(llm=llm,return_messages=True)chain_summary=ConversationChain(llm=llm,memory=summary_memory)chain_summary.predict(input="你好,我是小明。")chain_summary.predict(input="我今天去了公园,看到了很多花。")# 记忆内部存储的是摘要,而非原文print("摘要记忆中的摘要内容:",summary_memory.buffer)# ---- 3. 向量长期记忆(概念演示) ----# 实际实现通常将对话片段存入向量库(如 ChromaDB)# 查询时用当前问题去检索相关的历史记忆片段,拼接到上下文# 伪代码:# relevant_memories = vector_store.similarity_search(query, k=3)# context = "\n".join(relevant_memories)输出结果
缓冲记忆中的消息数量: 4 (用户2条+AI2条) 摘要记忆中的摘要内容: The human introduces themselves as Xiao Ming. They mention going to the park and seeing many flowers.AI 应用场景:缓冲记忆适合短期对话;摘要记忆适合长对话但可丢失细节;向量长期记忆是构建能“记住用户偏好”的 Agent 的关键技术。
二、中级篇:让 Agent 更聪明、更可靠
1. 🔥 多 Agent 协作:角色分工、状态传递
问题
复杂任务(如“调研市场并生成报告”)需要多个专业角色协作:一个搜索员、一个分析师、一个作家。如何让多个 Agent 分工合作?
生活化类比
多 Agent 协作就像公司部门会议:每个 Agent 是一个专家(市场部、技术部、财务部),他们各自完成分内工作,然后通过“会议纪要”(状态传递)将结果汇总给下一个部门。
术语详解
- 多 Agent 系统:由多个具有不同角色和目标的 Agent 组成,通过通信协作完成任务。
- AutoGen(微软)和CrewAI是两个主流多 Agent 框架。CrewAI 的核心概念是
Agent(角色)+Task(任务)+Crew(协作组)。 - 状态传递:上一个 Agent 的产出作为下一个 Agent 的输入,通过共享上下文或消息队列实现。
原理
多 Agent 协作的关键是清晰的角色定义和有序的任务分配。每个 Agent 有自己的系统提示(描述角色和职责)、工具集,以及一个“委派”机制。框架会自动将上一个任务的输出和当前任务的需求拼接成提示词,驱动下一个 Agent 工作。这比单个 Agent 反复切换角色更高效、更可控。
演示用例:用 CrewAI 构建一个调研+报告的多 Agent 系统
# pip install crewai langchain-openaifromcrewaiimportAgent,Task,Crew,Process# 定义两个专业 Agentresearcher=Agent(role="研究员",goal="找到关于{topic}的最新信息",backstory="你是一个经验丰富的研究员,擅长挖掘深度内容。",verbose=True,# 打印详细日志allow_delegation=False,# 不允许委托给其他 Agentllm="gpt-3.5-turbo")writer=Agent(role="撰稿人",goal="根据研究员的发现,撰写一份简洁的报告",backstory="你是一个专业撰稿人,擅长将复杂信息转化为流畅文章。",verbose=True,allow_delegation=False,llm="gpt-3.5-turbo")# 定义两个任务,并指定执行者task_research=Task(description="搜索并总结关于{topic}的三个关键点。",expected_output="一个包含三个要点的列表,每个要点一段说明。",agent=researcher# 由研究员执行)task_write=Task(description="根据研究员提供的要点,撰写一份简短报告(不超过200字)。",expected_output="一份结构清晰的报告。",agent=writer,# 由撰稿人执行context=[task_research]# 将研究任务的输出作为本任务的上下文)# 组建 Crewcrew=Crew(agents=[researcher,writer],tasks=[task_research,task_write],process=Process.sequential,# 顺序执行:先研究,后写报告verbose=True)# 启动协作result=crew.kickoff(inputs={"topic":"2024年人工智能发展趋势"})print("最终报告:\n",result)输出结果
[研究员] 搜索相关信息... [研究员] 找到三个关键点: 1. 多模态模型成为主流... 2. 开源模型性能逼近闭源... 3. AI 代理(Agent)开始商业化应用... [撰稿人] 根据要点撰写报告... 最终报告: 2024年人工智能发展呈现三大趋势:多模态模型成熟,文本、图像、语音统一处理;开源模型如Llama 3缩小了与闭源模型的差距;AI Agent开始在客服、编程等领域商业化落地。AI 应用场景:多 Agent 适合需要多角色协作的复杂流程,如自动生成市场研究报告、代码审查 + 修复、多轮辩论等。
2. 🔥 Plan-and-Execute 与反思机制
问题
ReAct 模式中 Agent 一边想一边做,容易“走一步看一步”而忽略全局规划,导致任务完成率低。如何让 Agent 先制定计划再执行,并且能从失败中反思?
生活化类比
- Plan-and-Execute就像建筑蓝图:先画好整个房子的设计图(Plan),再按图施工(Execute),而不是砌一块砖想一块。
- 反思机制就像考试后复盘:做完题后检查一遍,发现错误就修正,总结教训下次不再犯。
术语详解
- Plan-and-Execute:将 Agent 的决策分为两阶段——先由规划器(Planner)生成完整步骤列表,再由执行器(Executor)逐步完成。
- 反思(Reflection):Agent 完成一个步骤或整个任务后,自我评估结果的质量,如果不符合要求就重新规划或修正。
- ReWOO(Reason Without Observation):一种变体,规划时避免频繁等待工具结果,减少循环次数。
原理
ReAct 的问题在于决策碎片化:每执行一个工具就要重新调用 LLM 思考下一步,耗时且容易偏离目标。Plan-and-Execute 将“思考全局计划”和“执行具体步骤”解耦:Planner 一次性生成完整计划(如 1.搜索资料 2.分析数据 3.写报告),Executor 顺序执行,中间不需要 LLM 再次规划。反思机制则在执行后引入校验循环:如果结果不理想(如搜索返回空),Executor 可以请求 Planner 修改计划。
演示用例:模拟 Plan-and-Execute 流程(伪代码)
# 模拟 Plan-and-Execute 的核心思想defplan_and_execute(user_query:str):# ---- 阶段1:规划 ----planner_prompt=f"你是一个任务规划器。请将以下用户请求分解为不超过5个步骤,每步描述动作和预期结果:\n{user_query}"plan_response=client.chat.completions.create(model="gpt-3.5-turbo",messages=[{"role":"user","content":planner_prompt}])plan_text=plan_response.choices[0].message.contentprint("生成的计划:\n",plan_text)# 将计划解析为步骤列表(简化,实际可解析JSON)steps=[line.strip()forlineinplan_text.split("\n")ifline.strip().startswith(("1.","2.","3.","4.","5."))]# ---- 阶段2:执行(简化:打印步骤,实际会调用工具) ----results=[]forstepinsteps:print(f"执行:{step}")# 这里执行具体的工具调用,并将结果存入 results# 例如:如果步骤是“搜索xxx”,就调用搜索工具# 省略具体实现results.append(f"[完成]{step}")# ---- 阶段3:反思(可选) ----# 检查是否有步骤失败,若有则重新规划return"任务完成"plan_and_execute("调研LangChain框架的优缺点并给出总结")提升任务完成率的关键:
- 规划时要明确每个步骤的输入和输出。
- 执行中出错时,不要全盘重来,只修正失败步骤。
- 加入反思环节,用 LLM 评估“当前结果是否满足用户需求”。
面试考点:面试官常问“ReAct 有什么缺点?如何改进?”——答:ReAct 缺少全局规划,Plan-and-Execute 或 ReWOO 可以弥补;反思机制能显著提高成功率。
3. 🔥 MCP 协议:概念、资源/工具/提示的标准化暴露
问题
不同的 AI 应用各自定义工具接口,开发者需要为每个模型或框架适配一遍。有没有一种标准协议,让所有模型都能以统一方式调用工具和资源?
生活化类比
MCP 就像 USB 接口:以前每种设备有自己独特的接口(打印机用并口,鼠标用 PS/2),现在统一成 USB,任何设备都能即插即用。MCP 就是 AI 应用和工具之间的“USB 标准”。
术语详解
- MCP(Model Context Protocol):由 Anthropic 提出,定义了 AI 模型与外部工具、资源交互的标准协议。它规定了三类暴露端点:
- 工具(Tools):可执行的函数,如搜索、计算。
- 资源(Resources):可读取的数据源,如文件、数据库记录。
- 提示(Prompts):预设的提示模板。
- MCP Server:实现了 MCP 协议的服务端,负责暴露工具和资源。
- MCP Client:AI 应用(如 Claude Desktop)通过 MCP 客户端连接到 Server,自动发现并调用这些工具。
原理
MCP 使用 JSON-RPC 2.0 作为传输协议,Server 启动后注册自己支持的工具。Client 连接后,可以通过tools/list获取所有可用工具,通过tools/call调用具体工具并传参。这样,任何支持 MCP 的模型都能无缝调用任何 MCP Server 提供的工具,无需定制开发。2024-2025 年,MCP 正成为 Agent 生态的热点。
演示用例:写一个简单的 MCP Server(Python)
# pip install mcpfrommcp.server.fastmcpimportFastMCP# 初始化 MCP 服务器,命名为 "DemoServer"mcp=FastMCP("DemoServer")# 注册一个工具:加法计算器@mcp.tool()# 装饰器表示这是一个 MCP 工具defadd(a:int,b:int)->int:"""返回两个整数的和。参数 a 和 b 是加数。"""returna+b# 注册一个资源:模拟读取配置文件@mcp.resource("config://app")# 资源标识符defget_config()->str:"""返回应用的配置信息。"""return'{"theme": "dark", "language": "zh"}'# 启动服务器(在终端中运行此脚本)if__name__=="__main__":mcp.run(transport="stdio")# 使用标准输入输出传输(可改为 sse 或 streamable http)客户端连接示例(概念演示)
# 客户端代码(概念),实际通过 MCP Client SDK 调用# from mcp import Client# client = Client(transport="stdio", command="python server.py")# tools = client.list_tools() # 获取工具列表# result = client.call_tool("add", {"a": 3, "b": 5}) # 调用工具# print(result) # 8AI 应用场景:MCP 让 Agent 的工具生态从“封闭花园”走向“标准化市场”,未来开发者可以像安装插件一样为 Agent 添加新能力。
4. ⭐ 会话持久化与检查点恢复
问题
Agent 执行一个长任务(如持续几分钟的数据分析)时,如果服务崩溃或用户断开连接,所有中间状态都丢失了,必须从头开始。如何让 Agent 能“断点续传”?
生活化类比
检查点就像游戏存档:玩到一半时保存进度,即使电脑关机,下次还能从存档处继续,不用重打已经通过的关卡。
术语详解
- 会话持久化:将 Agent 运行中的状态(消息历史、中间结果、计划进度)保存到外部存储(如数据库、文件)。
- 检查点(Checkpoint):在关键步骤后保存的状态快照。Agent 可以从最近的检查点恢复执行。
- LangGraph等框架内置了检查点机制,可以在每个节点(步骤)后自动保存状态。
原理
持久化的核心是状态的序列化和反序列化。Agent 的完整状态包括:对话历史、当前任务计划、已完成的步骤、工具调用结果等。将这些保存为 JSON 或数据库记录,恢复时重新加载并继续执行下一步。LangGraph 使用checkpointer参数,在编译图时传入,框架自动在每一步执行后调用检查点保存。
演示用例:概念性伪代码(LangGraph 检查点)
# 伪代码展示 LangGraph 的检查点机制fromlanggraph.checkpointimportMemorySaver# 创建一个内存检查点(实际可用 SqliteSaver 持久化到磁盘)checkpointer=MemorySaver()# 编译图时传入检查点graph=create_agent_graph()# 构建 Agent 的状态图app=graph.compile(checkpointer=checkpointer)# 第一次运行,指定 thread_id 作为会话标识config={"configurable":{"thread_id":"user-session-123"}}app.invoke({"input":"开始一个长任务..."},config)# 模拟中断... 随后用相同的 thread_id 恢复# app.invoke({"input": None}, config) # 从上次检查点继续执行AI 应用场景:在需要长时间运行的 Agent 服务(如自动化数据分析、代码重构)中,检查点恢复是保证可靠性的关键。
AI 应用场景速查表
| 知识点 | 核心用途 | 典型场景 |
|---|---|---|
| ReAct 模式 | 让 Agent 动态使用工具 | 搜索问答、自动化操作 |
| 缓冲记忆 | 记住最近对话 | 短期上下文感知 |
| 摘要记忆 | 压缩长对话历史 | 客服长对话 |
| 向量长期记忆 | 持久化个性化记忆 | 用户偏好学习 |
| 多 Agent 协作 | 复杂任务分工 | 调研报告、代码审查 |
| Plan-and-Execute | 提升任务规划能力 | 多步骤数据分析 |
| 反思机制 | 自我纠错 | 提高任务成功率 |
| MCP 协议 | 工具标准化暴露 | 跨模型工具复用 |
| 会话持久化 | 断点续传 | 长任务可靠性 |
面试模拟题
1. 原理型:什么是 ReAct 模式?它和普通的 Chain 有什么区别?
答案要点:ReAct 将推理和行动交织在一起,通过思考-行动-观察循环动态决策。Chain 是固定的流程,不能根据中间结果调整后续步骤。ReAct 更灵活,但调用次数更多。
2. 场景型:你的 Agent 执行一个需要 10 步的任务,但经常在第 6 步出错后全部重来。如何改进?
答案要点:引入检查点机制,在每步后保存状态,出错后从最近的检查点恢复,而非从头开始。同时加入反思机制,让 Agent 分析失败原因并调整后续步骤。
3. 原理型:Plan-and-Execute 相比 ReAct 有什么优势?什么情况下应该使用它?
答案要点:Plan-and-Execute 先生成全局计划再执行,减少了 LLM 调用次数,任务完成率更高。适合步骤清晰、依赖关系明确的任务。ReAct 适合不确定性高、需灵活应对的场景。
4. 对比型:缓冲记忆、摘要记忆和向量长期记忆各有什么优缺点?如何组合使用?
答案要点:缓冲记忆简单但占空间,适合短期;摘要记忆省 token 但丢失细节;向量记忆保细节且可扩展,但实现复杂。组合方式:短期用缓冲,长期用摘要+向量,检索时先用向量召回相关历史。
593 热点型:什么是 MCP 协议?它解决了 AI Agent 开发中的什么痛点?
答案要点:MCP 是模型上下文协议,标准化了 AI 模型与外部工具、资源的交互方式。它让任何支持 MCP 的模型都能调用任何 MCP Server 提供的工具,避免了每个模型/工具组合都需要定制开发的碎片化问题。
总结
从 ReAct 的思考-行动循环,到记忆管理、多 Agent 协作,再到 Plan-and-Execute 的全局规划和 MCP 的标准化工具暴露,你已掌握 Agent 开发的核心技术栈。面试中的高频考点——ReAct 的原理、Plan-and-Execute 的改进思路、MCP 的概念——都已覆盖。现在你可以开始构建自己的智能体,并让它可靠地完成复杂任务了。