AI Agent 四大核心模块深度拆解:ReAct、Planning、Memory 与 Tool Use

AI Agent 四大核心模块深度拆解:ReAct、Planning、Memory 与 Tool Use

前言

如果说大语言模型(LLM)是 AI Agent 的"大脑",那么 ReAct、Planning、Memory、Tool Use 就是让这个大脑能够思考、规划、记忆、行动的四大认知模块。

这四个模块共同构成了 Agent 的认知闭环:

复制代码
┌──────────────────────────────────────────────────────────┐
│                    AI Agent 认知闭环                      │
│                                                          │
│   ┌─────────┐      ┌─────────┐      ┌─────────┐         │
│   │ Planning│ ───▶ │  ReAct  │ ───▶ │Tool Use │         │
│   │  (规划) │      │ (推理)  │      │ (行动)  │         │
│   └────┬────┘      └────┬────┘      └────┬────┘         │
│        │                │                │               │
│        │                ▼                │               │
│        │          ┌─────────┐           │               │
│        └─────────▶│ Memory  │◀──────────┘               │
│                   │ (记忆)  │                           │
│                   └─────────┘                           │
└──────────────────────────────────────────────────────────┘

本文将从技术原理、核心算法、代码实现、最佳实践四个维度,对这四大模块进行系统性深度拆解。


一、Planning(规划模块):Agent 的"大脑皮层"

1.1 规划的本质

Planning 模块解决的核心问题是:

给定一个目标,如何将其分解为可执行的步骤序列?

这对应人类认知中的"执行功能"(Executive Function)------我们不会直接行动,而是先在脑中"预演":要做什么?先做什么?后做什么?每步预期什么结果?

1.2 规划的三种范式

范式一:任务分解(Task Decomposition)

将复杂目标拆解为原子任务。

经典方法:Plan-and-Solve

复制代码
输入:复杂目标 G
输出:任务序列 [T1, T2, T3, ..., Tn]

算法:
1. LLM 分析目标 G,识别关键子目标
2. 对每个子目标,判断是否可原子化执行
3. 若不可,递归分解;若可,加入任务队列
4. 输出有序任务序列

Prompt 模板示例:

python 复制代码
PLAN_PROMPT = """
你是一个任务规划专家。请将以下目标分解为具体可执行的步骤。

目标:{goal}

约束条件:
1. 每个步骤应当是原子操作,不可再分
2. 步骤之间有明确的依赖关系
3. 每个步骤应当有明确的成功标准

请按以下格式输出:
Step 1: [描述] | 依赖: 无 | 成功标准: [标准]
Step 2: [描述] | 依赖: Step 1 | 成功标准: [标准]
...
"""
范式二:思维链规划(Chain-of-Thought Planning)

让模型显式输出推理过程,而非直接给出行动计划。

CoT 的数学形式化:

设问题为 QQQ,答案为 AAA,中间推理步骤为 s1,s2,...,sns_1, s_2, ..., s_ns1,s2,...,sn

传统方法:P(A∣Q)P(A|Q)P(A∣Q) ------ 直接预测答案

CoT 方法:P(s1,s2,...,sn,A∣Q)=∏i=1nP(si∣Q,s<i)⋅P(A∣Q,s1:n)P(s_1, s_2, ..., s_n, A | Q) = \prod_{i=1}^{n} P(s_i | Q, s_{<i}) \cdot P(A | Q, s_{1:n})P(s1,s2,...,sn,A∣Q)=∏i=1nP(si∣Q,s<i)⋅P(A∣Q,s1:n)

关键洞察: 显式的中间步骤 sis_isi 充当了"思维脚手架",让模型在复杂推理中不迷失方向。

范式三:树状搜索规划(Tree-of-Thought)

当任务存在多种可能路径时,用树搜索探索最优解。

复制代码
                    目标
                      │
          ┌───────────┼───────────┐
          ▼           ▼           ▼
        路径A        路径B        路径C
          │           │           │
      ┌───┴───┐   ┌───┴───┐   ┌───┴───┐
      ▼       ▼   ▼       ▼   ▼       ▼
     A1      A2  B1      B2  C1      C2
      │       │   │       │   │       │
     评分    评分 评分    评分 评分    评分
      │       │   │       │   │       │
      └───┬───┘   └───┬───┘   └───┬───┘
          ▼           ▼           ▼
        选择最优路径继续扩展...

ToT 算法伪代码:

python 复制代码
def tree_of_thought(problem, max_depth=5, beam_width=3):
    # 初始化:根节点为问题本身
    root = Node(state=problem, depth=0)
    frontier = [root]
    
    for depth in range(max_depth):
        candidates = []
        for node in frontier:
            # 生成多个可能的下一步思考
            thoughts = llm_generate_thoughts(node.state, n=beam_width)
            for thought in thoughts:
                child = Node(state=thought, parent=node, depth=depth+1)
                # 评估这个思考的质量
                child.score = llm_evaluate_thought(thought)
                candidates.append(child)
        
        # 保留 top-k 高分节点继续扩展
        frontier = sorted(candidates, key=lambda x: x.score)[:beam_width]
        
        # 检查是否找到解
        if any(is_solution(node) for node in frontier):
            return backtrack_solution(node)
    
    return best_path(frontier)

1.3 规划的挑战与解决方案

挑战 描述 解决方案
规划幻觉 模型生成了不可执行的步骤 添加步骤可行性验证器
依赖错误 步骤顺序违反依赖关系 用 DAG 建模依赖,拓扑排序
规划僵化 执行中遇到意外无法调整 引入动态重规划机制
粒度不当 步骤过大或过细 自适应粒度控制

二、ReAct(推理-行动循环):Agent 的"认知引擎"

2.1 ReAct 的诞生

ReAct(Reason + Act)由 Yao et al. 在 2023 年的论文《ReAct: Synergizing Reasoning and Acting in Language Models》中提出。

核心思想:让模型在"思考"和"行动"之间交替,形成推理-行动循环

2.2 ReAct 的形式化框架

状态定义:

  • ttt:当前时间步
  • oto_tot:第 ttt 步的观察(Observation,来自环境)
  • ata_tat:第 ttt 步的行动(Action,对环境的操作)
  • τt\tau_tτt:第 ttt 步的思考(Thought,内部推理)

ReAct 循环:

复制代码
初始化:context = 用户输入
循环直到任务完成:
    1. 思考:τ_t = LLM(context + 历史轨迹)
    2. 决策:a_t = extract_action(τ_t)
    3. 执行:o_t = Environment.execute(a_t)
    4. 更新:context = context + τ_t + a_t + o_t
    5. 判断:若 τ_t 包含 "任务完成",退出循环

2.3 ReAct 的完整实现

python 复制代码
import re
from typing import List, Tuple, Optional
from dataclasses import dataclass

@dataclass
class ReActStep:
    thought: str        # 思考内容
    action: Optional[str] = None   # 行动名称
    action_input: Optional[str] = None  # 行动参数
    observation: Optional[str] = None   # 观察结果

class ReActAgent:
    def __init__(self, llm, tools: dict, max_iterations: int = 10):
        self.llm = llm
        self.tools = tools
        self.max_iterations = max_iterations
        self.history: List[ReActStep] = []
    
    def build_prompt(self, question: str) -> str:
        """构建 ReAct Prompt"""
        prompt = f"""
你是一个使用 ReAct 范式解决问题的 AI Agent。

可用工具:
{self._format_tools()}

问题:{question}

请按以下格式思考和行动:
Thought: [你的思考过程]
Action: [工具名称]
Action Input: [工具输入参数]

或者当你认为问题已解决时:
Thought: [最终思考]
Final Answer: [最终答案]

历史轨迹:
{self._format_history()}

现在请继续:
"""
        return prompt
    
    def parse_response(self, response: str) -> ReActStep:
        """解析 LLM 响应,提取 Thought/Action/Observation"""
        step = ReActStep(thought="")
        
        # 提取 Thought
        thought_match = re.search(r'Thought:\s*(.+?)(?=Action:|Final Answer:|$)', 
                                   response, re.DOTALL)
        if thought_match:
            step.thought = thought_match.group(1).strip()
        
        # 提取 Action
        action_match = re.search(r'Action:\s*(.+?)\n', response)
        if action_match:
            step.action = action_match.group(1).strip()
        
        # 提取 Action Input
        input_match = re.search(r'Action Input:\s*(.+?)(?=\n|$)', response)
        if input_match:
            step.action_input = input_match.group(1).strip()
        
        # 提取 Final Answer
        final_match = re.search(r'Final Answer:\s*(.+?)$', response, re.DOTALL)
        if final_match:
            step.observation = f"FINAL: {final_match.group(1).strip()}"
        
        return step
    
    def execute_action(self, step: ReActStep) -> str:
        """执行工具调用"""
        if step.action and step.action in self.tools:
            tool = self.tools[step.action]
            try:
                result = tool(step.action_input)
                return f"Observation: {result}"
            except Exception as e:
                return f"Observation: Error - {str(e)}"
        return "Observation: Invalid action"
    
    def run(self, question: str) -> str:
        """运行 ReAct 循环"""
        for i in range(self.max_iterations):
            # 1. 构建 Prompt 并获取 LLM 响应
            prompt = self.build_prompt(question)
            response = self.llm(prompt)
            
            # 2. 解析响应
            step = self.parse_response(response)
            self.history.append(step)
            
            # 3. 检查是否完成
            if step.observation and step.observation.startswith("FINAL:"):
                return step.observation[6:].strip()
            
            # 4. 执行行动并获取观察
            if step.action:
                observation = self.execute_action(step)
                step.observation = observation
            
            print(f"[Step {i+1}] Thought: {step.thought[:50]}...")
            if step.action:
                print(f"          Action: {step.action}({step.action_input})")
                print(f"          {observation[:100]}...")
        
        return "达到最大迭代次数,任务未完成"

# 使用示例
def search_tool(query: str) -> str:
    # 模拟搜索
    return f"搜索结果:关于 '{query}' 的相关信息..."

def calculate_tool(expression: str) -> str:
    try:
        result = eval(expression)
        return f"计算结果:{result}"
    except:
        return "计算错误"

tools = {
    "search": search_tool,
    "calculate": calculate_tool,
}

# agent = ReActAgent(llm=your_llm, tools=tools)
# result = agent.run("2024年世界杯冠军是谁?他们赢了多少场比赛?")

2.4 ReAct vs Chain-of-Thought vs Plan-and-Execute

维度 Chain-of-Thought Plan-and-Execute ReAct
交互性 无外部交互 先规划后执行 边推理边交互
适应性 静态推理 静态规划 动态调整
错误恢复 无法恢复 需重规划 自动反思调整
适用场景 纯推理问题 结构化任务 开放式任务
计算成本

2.5 ReAct 的关键设计原则

  1. 思考先行:每次行动前必须有显式的 Thought,防止盲目行动
  2. 观察驱动:每次行动后必须等待 Observation,基于反馈决策下一步
  3. 轨迹记忆:完整保留历史 Thought-Action-Observation,避免重复
  4. 终止条件:明确的 Final Answer 或最大迭代次数,防止死循环

三、Memory(记忆模块):Agent 的"长期记忆系统"

3.1 为什么 Agent 需要记忆?

没有记忆的 Agent 就像金鱼------每轮对话都从零开始,无法:

  • 记住用户偏好和历史上下文
  • 从过往经验中学习和改进
  • 在多步任务中保持状态一致性

3.2 记忆的三层架构

复制代码
┌─────────────────────────────────────────────────────────┐
│                    Agent Memory System                   │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  ┌─────────────────────────────────────────────────┐    │
│  │  Sensory Memory (瞬时记忆)                        │    │
│  │  • 当前输入的原始感知                              │    │
│  │  • 存活时间:毫秒级                                │    │
│  │  • 实现:直接传入 LLM Context                     │    │
│  └─────────────────────────────────────────────────┘    │
│                         │                                │
│                         ▼                                │
│  ┌─────────────────────────────────────────────────┐    │
│  │  Working Memory (工作记忆)                        │    │
│  │  • 当前任务相关的上下文                            │    │
│  │  • 存活时间:当前会话                              │    │
│  │  • 实现:Conversation Buffer / Sliding Window    │    │
│  └─────────────────────────────────────────────────┘    │
│                         │                                │
│                         ▼                                │
│  ┌─────────────────────────────────────────────────┐    │
│  │  Long-Term Memory (长期记忆)                      │    │
│  │  • 跨会话的持久化知识                              │    │
│  │  • 存活时间:永久                                  │    │
│  │  • 实现:Vector DB + Embedding 检索              │    │
│  └─────────────────────────────────────────────────┘    │
│                                                          │
└─────────────────────────────────────────────────────────┘

3.3 工作记忆的实现

方案一:固定窗口(Fixed Window)
python 复制代码
class FixedWindowMemory:
    def __init__(self, max_messages: int = 10):
        self.max_messages = max_messages
        self.messages = []
    
    def add(self, role: str, content: str):
        self.messages.append({"role": role, "content": content})
        # 超过限制时,保留系统消息 + 最近的 N 条
        if len(self.messages) > self.max_messages:
            system_msgs = [m for m in self.messages if m["role"] == "system"]
            other_msgs = [m for m in self.messages if m["role"] != "system"]
            self.messages = system_msgs + other_msgs[-(self.max_messages - len(system_msgs)):]
    
    def get_context(self) -> list:
        return self.messages
方案二:Token 预算(Token Budget)
python 复制代码
class TokenBudgetMemory:
    def __init__(self, max_tokens: int = 4000, tokenizer=None):
        self.max_tokens = max_tokens
        self.tokenizer = tokenizer  # tiktoken 或类似
        self.messages = []
    
    def count_tokens(self, messages: list) -> int:
        text = " ".join(m["content"] for m in messages)
        return len(self.tokenizer.encode(text))
    
    def add(self, role: str, content: str):
        self.messages.append({"role": role, "content": content})
        self._trim()
    
    def _trim(self):
        """从旧到新删除消息,直到符合 token 预算"""
        while self.count_tokens(self.messages) > self.max_tokens and len(self.messages) > 1:
            # 删除最早的非系统消息
            for i, msg in enumerate(self.messages):
                if msg["role"] != "system":
                    self.messages.pop(i)
                    break
方案三:摘要压缩(Summary Compression)
python 复制代码
class SummaryMemory:
    def __init__(self, llm, max_tokens: int = 4000):
        self.llm = llm
        self.max_tokens = max_tokens
        self.raw_messages = []
        self.summary = ""
    
    def add(self, role: str, content: str):
        self.raw_messages.append({"role": role, "content": content})
        
        # 当超过 token 限制时,压缩旧消息
        if self._estimate_tokens() > self.max_tokens:
            self._compress()
    
    def _compress(self):
        """将旧消息压缩为摘要"""
        to_compress = self.raw_messages[:-4]  # 保留最近 4 条
        keep = self.raw_messages[-4:]
        
        prompt = f"""请将以下对话历史压缩为简洁的摘要,保留关键信息:

对话历史:
{self._format_messages(to_compress)}

当前摘要:
{self.summary}

请输出更新后的摘要:"""
        
        self.summary = self.llm(prompt)
        self.raw_messages = keep
    
    def get_context(self) -> list:
        """返回摘要 + 最近消息"""
        context = []
        if self.summary:
            context.append({"role": "system", "content": f"[历史摘要] {self.summary}"})
        context.extend(self.raw_messages)
        return context

3.4 长期记忆的实现

长期记忆的核心是语义检索:用向量相似度找到与当前查询最相关的历史记忆。

完整实现:基于 Chroma 的长期记忆
python 复制代码
import chromadb
from chromadb.config import Settings
from typing import List, Optional
import uuid

class VectorLongTermMemory:
    def __init__(self, 
                 persist_directory: str = "./memory_db",
                 collection_name: str = "agent_memory",
                 embedding_function=None):
        # 初始化 Chroma 客户端
        self.client = chromadb.PersistentClient(path=persist_directory)
        self.collection = self.client.get_or_create_collection(
            name=collection_name,
            embedding_function=embedding_function  # 默认用 Chroma 的
        )
    
    def save(self, 
             content: str, 
             metadata: Optional[dict] = None,
             memory_type: str = "episodic") -> str:
        """
        保存一条记忆
        
        Args:
            content: 记忆内容
            metadata: 元数据(如时间戳、任务ID、重要性等)
            memory_type: 记忆类型(episodic=情景, semantic=语义)
        
        Returns:
            记忆ID
        """
        memory_id = str(uuid.uuid4())
        
        if metadata is None:
            metadata = {}
        
        metadata["memory_type"] = memory_type
        metadata["timestamp"] = datetime.now().isoformat()
        
        self.collection.add(
            ids=[memory_id],
            documents=[content],
            metadatas=[metadata]
        )
        
        return memory_id
    
    def recall(self, 
               query: str, 
               n_results: int = 5,
               where: Optional[dict] = None) -> List[dict]:
        """
        检索相关记忆
        
        Args:
            query: 查询文本
            n_results: 返回数量
            where: 元数据过滤条件
        
        Returns:
            相关记忆列表
        """
        results = self.collection.query(
            query_texts=[query],
            n_results=n_results,
            where=where
        )
        
        memories = []
        for i, doc in enumerate(results["documents"][0]):
            memories.append({
                "content": doc,
                "metadata": results["metadatas"][0][i],
                "id": results["ids"][0][i],
                "distance": results["distances"][0][i] if "distances" in results else None
            })
        
        return memories
    
    def forget(self, memory_id: str):
        """删除一条记忆"""
        self.collection.delete(ids=[memory_id])
    
    def update(self, memory_id: str, new_content: str, new_metadata: Optional[dict] = None):
        """更新一条记忆"""
        self.collection.update(
            ids=[memory_id],
            documents=[new_content],
            metadatas=[new_metadata] if new_metadata else None
        )

# 使用示例
memory = VectorLongTermMemory(persist_directory="./agent_memory")

# 保存情景记忆
memory.save(
    content="用户偏好使用 Python 进行数据分析,熟悉 pandas 和 numpy",
    metadata={"category": "user_preference", "importance": "high"},
    memory_type="episodic"
)

# 保存语义记忆(知识)
memory.save(
    content="ReAct 是一种让 LLM 在推理和行动之间交替的范式,由 Yao et al. 2023 提出",
    metadata={"category": "technical_knowledge", "source": "paper"},
    memory_type="semantic"
)

# 检索相关记忆
relevant = memory.recall("用户喜欢用什么编程语言?", n_results=3)
for m in relevant:
    print(f"- {m['content']} (distance: {m['distance']:.3f})")

3.5 记忆的遗忘机制

不是所有记忆都值得永久保留。智能遗忘机制至关重要:

python 复制代码
class ForgettingMechanism:
    """基于 Ebbinghaus 遗忘曲线的记忆衰减"""
    
    def __init__(self, decay_rate: float = 0.3):
        self.decay_rate = decay_rate
    
    def compute_retention(self, 
                          initial_strength: float,
                          time_elapsed_hours: float,
                          recall_count: int = 0) -> float:
        """
        计算记忆保留强度
        
        R = S * e^(-t/d) * (1 + boost * recall_count)
        
        Args:
            initial_strength: 初始记忆强度 (0-1)
            time_elapsed_hours: 距离上次访问的小时数
            recall_count: 被回忆的次数(强化因子)
        
        Returns:
            当前保留强度 (0-1)
        """
        import math
        
        # Ebbinghaus 遗忘曲线
        decay = math.exp(-time_elapsed_hours / (24 * self.decay_rate))
        
        # 回忆强化
        boost = 0.1 * recall_count
        
        retention = initial_strength * decay * (1 + boost)
        return min(retention, 1.0)  # 上限为 1
    
    def should_forget(self, 
                      memory: dict, 
                      threshold: float = 0.1) -> bool:
        """判断是否应该遗忘"""
        retention = self.compute_retention(
            initial_strength=memory.get("initial_strength", 0.5),
            time_elapsed_hours=memory.get("hours_since_access", 0),
            recall_count=memory.get("recall_count", 0)
        )
        return retention < threshold

四、Tool Use(工具调用):Agent 的"行动能力"

4.1 工具调用的本质

Tool Use 让 Agent 突破"只输出文本"的限制,能够:

  • 获取实时信息(搜索、API 调用)
  • 执行计算和代码
  • 操作文件和数据库
  • 与外部系统交互

4.2 工具调用的两种范式

范式一:Function Calling(结构化调用)

OpenAI、Anthropic Claude、国产大模型普遍支持的方式。

工作流程:

复制代码
1. 用户定义工具 schema
2. LLM 输出结构化的函数调用参数
3. Agent 执行函数调用
4. 将结果返回 LLM 继续推理

工具 Schema 定义:

python 复制代码
tools_schema = [
    {
        "type": "function",
        "function": {
            "name": "search_web",
            "description": "搜索互联网获取实时信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "搜索关键词"
                    },
                    "num_results": {
                        "type": "integer",
                        "description": "返回结果数量",
                        "default": 5
                    }
                },
                "required": ["query"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "execute_python",
            "description": "执行 Python 代码进行计算或数据处理",
            "parameters": {
                "type": "object",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "要执行的 Python 代码"
                    }
                },
                "required": ["code"]
            }
        }
    }
]

完整调用流程:

python 复制代码
import openai

def run_with_tools(user_message: str, tools: list, tool_implementations: dict):
    messages = [{"role": "user", "content": user_message}]
    
    while True:
        # 1. 调用 LLM
        response = openai.chat.completions.create(
            model="gpt-4-turbo",
            messages=messages,
            tools=tools,
            tool_choice="auto"
        )
        
        message = response.choices[0].message
        messages.append(message)
        
        # 2. 检查是否需要工具调用
        if not message.tool_calls:
            # 无工具调用,返回最终答案
            return message.content
        
        # 3. 执行工具调用
        for tool_call in message.tool_calls:
            function_name = tool_call.function.name
            function_args = json.loads(tool_call.function.arguments)
            
            print(f"调用工具: {function_name}({function_args})")
            
            # 执行实际的工具函数
            if function_name in tool_implementations:
                result = tool_implementations[function_name](**function_args)
            else:
                result = f"错误:未知工具 {function_name}"
            
            # 4. 将结果返回给 LLM
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": str(result)
            })

# 工具实现
def search_web(query: str, num_results: int = 5) -> str:
    # 实际搜索逻辑
    return f"关于 '{query}' 的搜索结果..."

def execute_python(code: str) -> str:
    try:
        # 安全的代码执行(实际应用需要沙箱)
        local_vars = {}
        exec(code, {"__builtins__": {}}, local_vars)
        return str(local_vars.get("result", "执行成功"))
    except Exception as e:
        return f"执行错误: {e}"

tool_implementations = {
    "search_web": search_web,
    "execute_python": execute_python
}

# 运行
result = run_with_tools(
    "帮我搜索最新的 AI Agent 论文,并统计有多少篇",
    tools_schema,
    tool_implementations
)
范式二:Prompt-based Tool Use(ReAct 风格)

不依赖模型的 Function Calling 能力,通过 Prompt 引导模型输出工具调用。

Prompt 模板:

python 复制代码
TOOL_USE_PROMPT = """
你是一个可以使用多种工具的 AI Agent。

可用工具:
{tool_descriptions}

使用工具的格式:
Action: [工具名称]
Action Input: [JSON 格式的参数]

示例:
Action: search_web
Action Input: {{"query": "AI Agent 最新进展", "num_results": 5}}

现在请处理用户的请求:
{user_request}

请先思考,然后决定是否需要使用工具。
"""

4.3 工具设计最佳实践

原则一:单一职责

每个工具只做一件事,职责清晰。

python 复制代码
# ❌ 不好:一个工具做太多事
def process_data(action: str, data: any) -> any:
    if action == "read":
        return read_file(data)
    elif action == "write":
        return write_file(data)
    elif action == "transform":
        return transform(data)
    # ... 职责混乱

# ✅ 好:每个工具单一职责
def read_file(path: str) -> str:
    """读取文件内容"""
    pass

def write_file(path: str, content: str) -> bool:
    """写入文件"""
    pass

def transform_data(data: any, operation: str) -> any:
    """数据转换"""
    pass
原则二:明确的 Schema

工具的参数、返回值、错误情况都要有清晰的文档。

python 复制代码
def search_web(
    query: str,
    num_results: int = 5,
    site: Optional[str] = None
) -> List[SearchResult]:
    """
    搜索互联网获取信息
    
    Args:
        query: 搜索关键词,不能为空
        num_results: 返回结果数量,1-20
        site: 限定搜索站点,如 "github.com"
    
    Returns:
        SearchResult 列表,每个包含 title, url, snippet
    
    Raises:
        ValueError: query 为空或 num_results 超出范围
        NetworkError: 网络请求失败
    """
    pass
原则三:错误处理与降级

工具调用可能失败,需要优雅处理。

python 复制代码
class ToolExecutor:
    def __init__(self, tools: dict, max_retries: int = 3):
        self.tools = tools
        self.max_retries = max_retries
    
    def execute(self, tool_name: str, **kwargs) -> ToolResult:
        if tool_name not in self.tools:
            return ToolResult(
                success=False,
                error=f"未知工具: {tool_name}",
                fallback="请检查工具名称是否正确"
            )
        
        tool = self.tools[tool_name]
        
        for attempt in range(self.max_retries):
            try:
                result = tool(**kwargs)
                return ToolResult(success=True, result=result)
            except Exception as e:
                if attempt == self.max_retries - 1:
                    return ToolResult(
                        success=False,
                        error=str(e),
                        fallback=self._get_fallback(tool_name, e)
                    )
                time.sleep(2 ** attempt)  # 指数退避
    
    def _get_fallback(self, tool_name: str, error: Exception) -> str:
        """根据错误类型提供降级建议"""
        if "timeout" in str(error).lower():
            return f"工具 {tool_name} 超时,建议稍后重试或使用替代方案"
        elif "permission" in str(error).lower():
            return f"权限不足,请检查 {tool_name} 的访问权限"
        else:
            return f"工具 {tool_name} 执行失败,请尝试其他方法"
原则四:权限控制

工具调用必须有权限边界,防止滥用。

python 复制代码
class PermissionController:
    """工具调用权限控制器"""
    
    def __init__(self):
        self.permissions = {
            "read_file": ["~/Documents/**", "~/Desktop/**"],  # 只允许读取特定目录
            "write_file": ["~/Documents/output/**"],  # 只允许写入输出目录
            "execute_python": ["safe_functions"],  # 只允许安全函数
            "search_web": ["*"],  # 无限制
        }
    
    def check_permission(self, tool_name: str, **kwargs) -> bool:
        """检查是否有权限执行"""
        if tool_name not in self.permissions:
            return False
        
        allowed = self.permissions[tool_name]
        
        if tool_name == "read_file":
            path = kwargs.get("path", "")
            return self._match_path(path, allowed)
        
        elif tool_name == "execute_python":
            code = kwargs.get("code", "")
            return self._is_safe_code(code)
        
        return True  # 其他情况默认允许
    
    def _match_path(self, path: str, patterns: list) -> bool:
        """检查路径是否匹配允许的模式"""
        import fnmatch
        expanded = os.path.expanduser(path)
        for pattern in patterns:
            expanded_pattern = os.path.expanduser(pattern)
            if fnmatch.fnmatch(expanded, expanded_pattern):
                return True
        return False
    
    def _is_safe_code(self, code: str) -> bool:
        """检查代码是否安全(简化版)"""
        dangerous = ["import os", "import subprocess", "eval(", "exec(", "__import__"]
        return not any(d in code for d in dangerous)

4.4 MCP:工具调用的新范式

MCP(Model Context Protocol) 是 Anthropic 在 2024 年底开源的工具调用协议,正在成为 AI Agent 工具生态的事实标准。

MCP 的核心优势:

特性 传统 Function Calling MCP
协议标准化 各厂商自定义 统一开放协议
工具发现 手动定义 schema 自动 discovery
跨模型兼容 仅特定模型支持 任何支持 MCP 的模型
生态复用 各自为战 共享工具生态

MCP 架构:

复制代码
┌─────────────────┐      MCP Protocol      ┌─────────────────┐
│   MCP Client    │ ◄─────────────────────► │   MCP Server    │
│   (AI Agent)    │                         │   (Tool Host)   │
├─────────────────┤                         ├─────────────────┤
│ • 发起请求      │                         │ • 提供工具列表   │
│ • 接收响应      │                         │ • 执行工具调用   │
│ • 管理连接      │                         │ • 返回结果      │
└─────────────────┘                         └─────────────────┘

五、四大模块的协同:构建完整的 Agent

5.1 模块协作流程

python 复制代码
class CompleteAgent:
    def __init__(self, llm, tools, memory_system):
        self.llm = llm
        self.tools = tools
        self.memory = memory_system  # 包含工作记忆 + 长期记忆
        self.planner = Planner(llm)
        self.executor = ToolExecutor(tools)
    
    def run(self, goal: str) -> str:
        # 1. Planning:分解目标
        plan = self.planner.decompose(goal)
        
        # 2. 检索相关长期记忆
        relevant_memories = self.memory.long_term.recall(goal)
        context = self._build_context(relevant_memories)
        
        results = []
        for step in plan:
            # 3. ReAct 循环
            while not step.completed:
                # 思考
                thought = self._think(step, context, results)
                
                # 决定行动
                if thought.needs_tool:
                    # Tool Use
                    action_result = self.executor.execute(
                        thought.tool_name, 
                        **thought.tool_args
                    )
                    results.append(action_result)
                
                # 更新工作记忆
                self.memory.working.add("assistant", thought.content)
                
                # 检查步骤是否完成
                step.completed = self._check_completion(step, results)
            
            # 4. 保存重要结果到长期记忆
            if step.important:
                self.memory.long_term.save(
                    content=step.summary,
                    metadata={"step": step.name, "goal": goal}
                )
        
        return self._synthesize_results(results)

5.2 模块间的信息流

复制代码
用户输入
    │
    ▼
┌─────────────────────────────────────────────────────────┐
│  Planning Module                                        │
│  输入:用户目标 + 长期记忆检索结果                        │
│  输出:任务分解计划                                      │
└────────────────────────┬────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────┐
│  ReAct Loop (for each task)                             │
│                                                         │
│  ┌─────────┐   ┌─────────┐   ┌─────────┐              │
│  │ Thought │──▶│ Action  │──▶│Observe  │              │
│  └────┬────┘   └────┬────┘   └────┬────┘              │
│       │             │             │                     │
│       │             ▼             │                     │
│       │      ┌────────────┐      │                     │
│       │      │ Tool Use   │      │                     │
│       │      └────────────┘      │                     │
│       │             │             │                     │
│       └─────────────┴─────────────┘                     │
│                     │                                   │
│                     ▼                                   │
│            ┌──────────────┐                             │
│            │ Working Mem  │ ◄── 更新上下文              │
│            └──────────────┘                             │
└────────────────────────┬────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────┐
│  Long-Term Memory                                       │
│  • 保存重要经验                                          │
│  • 更新知识库                                            │
│  • 记录任务结果                                          │
└─────────────────────────────────────────────────────────┘
                         │
                         ▼
                    最终输出

六、总结与展望

6.1 四大模块的核心要点

模块 核心问题 关键技术 最佳实践
Planning 如何分解目标? CoT、ToT、Plan-and-Solve 动态重规划、可行性验证
ReAct 如何边推理边行动? Thought-Action-Observation 循环 思考先行、观察驱动
Memory 如何保持上下文? 工作记忆 + 长期记忆 + 向量检索 智能遗忘、摘要压缩
Tool Use 如何与外部交互? Function Calling、MCP 单一职责、权限控制

6.2 未来趋势

  1. Planning:从静态规划到动态自适应规划,引入强化学习优化策略
  2. ReAct:与多模态结合,支持图像/视频理解和行动
  3. Memory:更高效的压缩算法、跨 Agent 的共享记忆
  4. Tool Use:MCP 生态爆发、工具自动发现与组合

6.3 学习路径建议

复制代码
入门阶段
  ├── 理解 ReAct 原理,阅读原始论文
  ├── 用 LangChain 实现简单的 Tool Use
  └── 搭建基础的对话记忆系统

进阶阶段
  ├── 实现 ToT 规划算法
  ├── 集成向量数据库构建长期记忆
  └── 学习 MCP 协议,搭建 MCP Server

高级阶段
  ├── 设计多 Agent 协作架构
  ├── 实现自适应规划和动态重规划
  └── 优化记忆检索效率,引入遗忘机制

参考资料

  1. Yao, S., et al. "ReAct: Synergizing Reasoning and Acting in Language Models" (ICLR, 2023)
  2. Wei, J., et al. "Chain-of-Thought Prompting Elicits Reasoning in Large Language Models" (NeurIPS, 2022)
  3. Yao, S., et al. "Tree of Thoughts: Deliberate Problem Solving with Large Language Models" (NeurIPS, 2023)
  4. Shinn, N., et al. "Reflexion: Language Agents with Verbal Reinforcement Learning" (NeurIPS, 2023)
  5. Anthropic. "Model Context Protocol (MCP)" --- https://modelcontextprotocol.io
  6. LangChain Documentation --- Memory Module
  7. CrewAI Documentation --- Agent Architecture
相关推荐
陕西企来客1 小时前
陕西旅游酒店 GEO 服务市场深度调查:AI 搜索优化格局与真实服务真相
大数据·人工智能·旅游
薛定猫AI1 小时前
【深度解析】Hermes Agent Velocity Release:长期记忆、自进化技能与多智能体任务编排实践
网络·人工智能
五月君_2 小时前
继 React、Vue 之后,Three.js 也有 Skills 了!AI 写 3D 终于不“晕”了
javascript·vue.js·人工智能·react.js·3d
小崽崽12 小时前
如何实现React 19+Vite+TypeScript技术栈告别高薪主播!从零打造 24 小时“AI 销冠”:星云数字人直播间全链路实战
人工智能·react.js·typescript
土星云SaturnCloud2 小时前
基于铁塔基站的反无人机系统应用场景分析:边缘计算重构低空防御体系
服务器·人工智能·ai·边缘计算
zhang_adrian2 小时前
【使用Github Copilot自动按规范文档生成全部代码】
人工智能·github·copilot
薛定猫AI2 小时前
【深度解析】Claude Opus 编码模型的工程化使用:长上下文、Agent 工作流与代码审查实战
人工智能
MRDONG12 小时前
从机器学习到大语言模型:一文讲清 AI、Transformer、Embedding 和向量数据库
人工智能·机器学习·语言模型