在上一篇文章中,我们理解了 AI Agent 的本质——它是一个以目标为输入、在“决策—执行—观察”闭环中往复运行的程序。但这个闭环具体是怎么运转的?Agent 怎么知道该做什么、怎么记住之前做了什么、怎么调用外部能力?答案藏在规划(Planning)、记忆(Memory)、工具使用(Tool Use) 这三个核心模块里。它们相互融合、相互依赖,共同对任务进行拆解,得到可验证的子步骤。 本文深入拆解这三者,并通过一个完整的代码实战帮你理解 Agent 的内部运作机制。
一、规划模块:任务拆解与推理
规划是 Agent 的“大脑中枢”。 复杂任务通常不能一步到位。以“制定一份新能源汽车市场分析报告”为例,Agent 需要自己判断怎么拆:先收集市场数据,再分析主要厂商,然后梳理技术路线,最后整合成报告。这个拆解过程不是靠写死流程,而是靠规划模块动态生成。
目前业界广泛采用的规划方法之一是 ReAct(Reasoning + Acting) 。它的核心思路是让模型在一个循环中交替输出“思考”(Thought)、“行动”(Action)、“观察”(Observation),然后根据观察结果继续思考,形成闭环。这种方式允许模型在执行过程中根据反馈修正自己的计划。
ReAct 循环的完整流程:
text
Thought: 我需要先了解当前的数据情况
Action: query_database(“SELECT * FROM sales WHERE quarter = ‘Q3’”)
Observation: 返回了 150 条销售记录
Thought: 数据已获取,现在需要分析下降原因
Action: analyze_trend(data)
Observation: 发现华东地区销售额下降了 30%
Thought: 问题定位在华东地区,需要进一步分析
…
其他常见的规划方法还包括 Chain-of-Thought(CoT) 和 Tree-of-Thought(ToT) ,但在实际工程中,ReAct 的模式更接近真实执行场景,因为它天然对接了工具调用。
二、记忆模块:短期、工作与长期记忆
没有记忆的 Agent 每次都在“从零开始”。 Agent 的认知包括对话历史、工具输出以及在前面步骤中检索到的任何数据。记忆是实现一致性的关键:当用户说“实际上,这是错误的颜色”时,Agent 知道“它”指的是前面讨论的项目。
Agent 的记忆系统分为三个层次:
短期记忆通常由框架自动管理。以 GitHub Copilot SDK 为例,它通过跟踪会话中的聊天历史记录自动管理短期内存。对于可能超过模型上下文窗口的会话,SDK 的“无限会话”功能会压缩较旧的上下文,以防止令牌溢出,同时保留基本信息。
长期记忆需要显式实现。常见方案是将重要信息嵌入为向量,存储在向量数据库中,在需要时通过语义检索召回。这是 RAG(检索增强生成)的基础设施。
三、工具使用:Agent 真正能“干活”的关键
LLM 本身无法直接操作外部系统,它只能输出文本。 要让 Agent 执行具体操作,必须引入工具调用(Function Calling) 机制。
工具是 Agent 在其推理过程中可以调用的外部函数或 API。每个工具都表示 Agent 可以执行的特定操作:查找数据库记录、调用 REST API、发送电子邮件或运行诊断命令。
设计工具集的关键原则:每个工具都应很好地执行一项操作,并提供清晰的名称和说明,帮助 AI 模型了解何时使用它。你希望为 Agent 提供足够有用的工具,但不要过多,以免让其困惑或不堪重负。
工具的规划器协调机制是:规划器决定何时调用工具、何时提出澄清问题、何时生成最终答案。现代 AI Agent 使用 ReAct 循环,在思考(LLM 建议一个步骤)和行动(调用工具)之间交替。
四、生产级 Agent 的关键设计原则
从工程落地的视角,一个生产级 Agent 需要遵循以下设计原则:
结构化输出:Agent 的工具调用和最终响应都应遵循明确的 Schema,便于程序化解析和验证。
多级记忆:不要把所有信息都塞进上下文窗口。短期记忆用消息列表,工作记忆用状态对象,长期记忆用向量检索。
幂等工具调用:同一个工具调用重复执行不应产生副作用。这对重试和错误恢复至关重要。
全链路可观测性:每一步的思考、行动、观察都应被记录和追踪,便于调试和优化。
五、实战:用 ReAct 模式实现一个最简单的 Agent
以下代码展示了 ReAct 模式的核心逻辑(伪代码风格,聚焦理解):
importjsonclassSimpleAgent:def__init__(self,llm,tools):self.llm=llm self.tools={t.name:tfortintools}self.memory=[]# 短期记忆:对话历史defrun(self,goal:str,max_steps:int=10)->str:"""执行 ReAct 循环直到任务完成或达到最大步数"""context=f"目标:{goal}\n\n"forstepinrange(max_steps):# 1. 思考 + 行动决策prompt=self._build_prompt(context)response=self.llm.invoke(prompt)# 2. 解析 LLM 的输出thought=response.get("thought","")action=response.get("action")action_input=response.get("action_input",{})context+=f"Thought:{thought}\n"# 3. 判断是否完成ifaction=="finish":returnaction_input.get("answer",thought)# 4. 执行工具ifactioninself.tools:try:observation=self.tools[action].execute(**action_input)exceptExceptionase:observation=f"工具执行错误:{e}"else:observation=f"未知工具:{action}"# 5. 将观察结果追加到上下文(这就是"记忆")context+=f"Action:{action}({action_input})\n"context+=f"Observation:{observation}\n\n"self.memory.append((thought,action,observation))return"达到最大步数限制,任务未完成"def_build_prompt(self,context:str)->str:tool_descriptions="\n".join(f"-{name}:{tool.description}"forname,toolinself.tools.items())returnf"""{context}可用工具:
{tool_descriptions}
- finish: 任务完成时调用,传入最终答案
请输出 JSON 格式:
{{“thought”: “你的思考”, “action”: “工具名或finish”, “action_input”: {{…}}}}
“”"
代码要点:
run() 方法是 ReAct 循环的核心,每一步都执行“思考→行动→观察”。
context 变量就是工作记忆,随着每一步的执行不断累积。
self.memory 是短期记忆,记录完整的决策历史。
工具调用结果作为 Observation 追加到上下文,供下一步决策使用。
max_steps 是防止死循环的安全护栏。
六、三者的协作关系:铁三角
规划、记忆、工具使用不是三个独立模块,而是相互依赖的铁三角:
规划依赖记忆:没有记忆,规划无法知道之前做过什么、结果如何。
记忆依赖工具:工具调用的输出是记忆的重要内容来源。
工具依赖规划:没有规划,Agent 不知道何时该调用哪个工具。
规划依赖工具:工具的能力边界决定了规划的可能性空间。
三者共同对任务进行拆解,得到可验证的子步骤,并在“决策—执行—观察”的闭环中持续迭代。
七、小结
规划模块:用 ReAct 模式实现“思考→行动→观察”循环,动态生成任务拆解。
记忆模块:短期记忆(对话历史)、工作记忆(任务状态)、长期记忆(向量检索)三层协作。
工具使用:通过 Function Calling 让 Agent 真正能“干活”,工具设计遵循“一个工具一个目标”原则。
关键设计原则:结构化输出、多级记忆、幂等工具调用、全链路可观测性。
铁三角协作:规划、记忆、工具三者相互依赖,共同驱动 Agent 的自主执行闭环。