Agent架构设计:规划器、工具、记忆、评估器如何协同工作

Agent架构设计:规划器、工具、记忆、评估器如何协同工作

说实话,我见过太多团队在搭Agent系统时踩的坑------上来就硬编一个"LLM+Tools"的玩具demo,然后期望它能搞定生产级任务。现实是,这种简单架构在面对复杂任务流时,会出现规划混乱、工具调用爆炸、记忆丢失、结果无法收敛等一系列问题。

真正工程化的Agent架构,绕不开四个核心组件:规划器(Planner)、工具(Tools)、记忆(Memory)、评估器(Evaluator)。今天聊聊它们各自负责什么,以及怎么让它们真正协同起来。


一、规划器:Agent的"大脑",决定做什么

规划器是Agent的核心决策层,负责理解任务目标、拆解执行步骤、决定下一步行动。

主流的规划策略有两种:

1.1 ReAct(Reasoning + Acting)

ReAct的思路很简单:思考 → 行动 → 观察 → 再思考。每一步都让LLM先推理一下当前状态,再决定做什么。

python 复制代码
import json

class ReActPlanner:
    def __init__(self, llm):
        self.llm = llm
    
    def plan(self, task: str, max_steps: int = 10):
        history = []
        observation = ""
        
        for step in range(max_steps):
            # 让LLM推理下一步
            prompt = self._build_prompt(task, history, observation)
            response = self.llm.generate(prompt)
            
            # 解析出 action 和 action_input
            action, action_input = self._parse_response(response)
            
            if action == "finish":
                return action_input
            
            # 执行action
            observation = self._execute(action, action_input)
            history.append({
                "step": step,
                "action": action,
                "action_input": action_input,
                "observation": observation
            })
        
        return "规划失败:超过最大步数"
    
    def _build_prompt(self, task, history, observation):
        return f"""任务:{task}

执行历史:
{json.dumps(history, ensure_ascii=False)}

当前观察:{observation}

下一步行动(thinking + action + action_input):
"""

1.2 Chain-of-Thought(CoT)规划

CoT更适合复杂推理场景,让LLM显式输出推理链,逐步拆解任务。

python 复制代码
def cot_plan(task: str, llm):
    """Chain-of-Thought 规划模式"""
    prompt = f"""任务:{task}

请逐步推理出执行计划,每一步都要明确:
1. 当前要解决什么问题
2. 下一步具体做什么
3. 如何判断这一步完成

推理:
"""
    reasoning = llm.generate(prompt)
    
    # 将推理结果转换为可执行步骤
    plan_prompt = f"""基于以下推理过程,列出具体执行步骤:

{reasoning}

执行步骤:
"""
    steps = llm.generate(plan_prompt)
    return steps

规划器设计的坑

坑1:规划器太"聪明" ,导致行动太空泛。比如LLM说"调用搜索API搜索相关信息",但没有指定关键词、时间范围、结果数量。工具调用参数必须精确,规划器要学会生成结构化的action_input

坑2:没有停止条件 。很多实现忘了加finish action,导致规划陷入死循环。一定要设置max_steps,并且在每个循环里检查是否已达到目标。


二、工具层:Agent的"手脚"

工具是Agent与外部世界交互的接口。设计好工具系统,是Agent能真正干活的关键。

2.1 工具描述的写法

工具描述是LLM理解"能做什么"的唯一来源。很多团队随便写两句,结果LLM调用时参数乱七八糟。

好的工具描述

python 复制代码
tools = [
    {
        "name": "search_news",
        "description": "搜索指定主题的最新新闻。
        输入参数:
          - keyword: str, 搜索关键词,必填
          - days: int, 搜索最近N天的新闻,默认7
          - limit: int, 返回结果数量,默认10,最大50
        返回:新闻列表,每条包含标题、URL、发布时间、摘要",
        "parameters": {
            "type": "object",
            "properties": {
                "keyword": {"type": "string", "description": "搜索关键词"},
                "days": {"type": "integer", "default": 7},
                "limit": {"type": "integer", "default": 10, "maximum": 50}
            },
            "required": ["keyword"]
        }
    },
    {
        "name": "send_email",
        "description": "发送电子邮件。
        输入参数:
          - to: str, 收件人邮箱地址,必填
          - subject: str, 邮件主题,必填
          - body: str, 邮件正文,必填
        返回:发送结果(成功/失败)",
        "parameters": {
            "type": "object",
            "properties": {
                "to": {"type": "string", "format": "email"},
                "subject": {"type": "string"},
                "body": {"type": "string"}
            },
            "required": ["to", "subject", "body"]
        }
    }
]

关键原则 :description要自包含,LLM看到description就知道能干什么、该传什么参数。不要写得太抽象,也不要写得太细节------给LLM足够的上下文来做出正确决策。

2.2 工具执行与错误处理

工具执行时要考虑:超时、重试、参数校验、结果解析

python 复制代码
import asyncio
from typing import Any, Callable

class ToolExecutor:
    def __init__(self, max_retries: int = 2, timeout: float = 30.0):
        self.max_retries = max_retries
        self.timeout = timeout
    
    async def execute(self, tool: Callable, params: dict) -> dict:
        """带重试和超时的工具执行"""
        for attempt in range(self.max_retries + 1):
            try:
                result = await asyncio.wait_for(
                    tool(**params),
                    timeout=self.timeout
                )
                return {"status": "success", "result": result}
            except asyncio.TimeoutError:
                return {"status": "error", "error": f"超时({self.timeout}s)"}
            except Exception as e:
                if attempt == self.max_retries:
                    return {"status": "error", "error": str(e)}
                # 重试前等待指数退避
                await asyncio.sleep(2 ** attempt)
        
        return {"status": "error", "error": "重试次数耗尽"}

2.3 工具选择的艺术

不是所有任务都需要调用工具。有时候LLM自己就能回答,有时候需要组合多个工具。工具选择的策略决定了Agent的效率。

python 复制代码
def select_tools(task: str, available_tools: list, llm) -> list:
    """让LLM决定用哪些工具"""
    tool_names = [t["name"] for t in available_tools]
    prompt = f"""任务:{task}
可用工具:{tool_names}
请决定需要调用哪些工具(可多选)。直接列出工具名称,用逗号分隔。
如果不需要工具,返回"无需工具"。"""
    
    response = llm.generate(prompt).strip()
    
    if response == "无需工具":
        return []
    
    selected = [t.strip() for t in response.split(",")]
    return [t for t in available_tools if t["name"] in selected]

三、记忆系统:Agent的"海马体"

没有记忆的Agent,每次任务都从零开始。有记忆的Agent,才能在多轮对话中保持上下文一致性,在长程任务中积累信息。

3.1 记忆的三层架构

复制代码
用户输入 → 感官记忆(当前轮对话)
              ↓
         工作记忆(短期记忆,当前任务上下文)
              ↓
         长期记忆(向量数据库,跨任务知识)

感官记忆:直接存储用户当前输入,通常不做处理。

工作记忆:当前任务的执行上下文,包括:

  • 已执行的步骤和结果
  • 当前的中间目标和状态
  • 最近的LLM输出
python 复制代码
class WorkingMemory:
    def __init__(self, max_history: int = 20):
        self.max_history = max_history
        self.history = []
        self.context = {}
    
    def add_turn(self, role: str, content: str):
        self.history.append({"role": role, "content": content})
        if len(self.history) > self.max_history:
            self.history.pop(0)
    
    def get_context(self) -> list:
        return self.history[-self.max_history:]
    
    def set_context(self, key: str, value: Any):
        self.context[key] = value
    
    def get_context_value(self, key: str) -> Any:
        return self.context.get(key)

长期记忆:用向量数据库存储历史交互、领域知识、用户偏好。检索时用Embedding匹配相关记忆。

python 复制代码
from datetime import datetime

class LongTermMemory:
    def __init__(self, vector_store):
        self.vector_store = vector_store  # Chroma / Milvus / FAISS 等
    
    def store(self, text: str, metadata: dict = None):
        """存储记忆到向量库"""
        embedding = self._embed(text)
        self.vector_store.add(
            ids=[str(datetime.now().timestamp())],
            embeddings=[embedding],
            documents=[text],
            metadatas=[metadata or {}]
        )
    
    def retrieve(self, query: str, top_k: int = 5) -> list:
        """基于语义检索记忆"""
        query_embedding = self._embed(query)
        results = self.vector_store.query(
            query_embeddings=[query_embedding],
            n_results=top_k
        )
        return results
    
    def _embed(self, text: str) -> list:
        # 用 embedding model 获取向量
        return embedding_model.encode(text)

3.2 记忆何时写入?

这是个设计选择问题。太频繁写入会增加开销,太少则丢失关键信息。

推荐策略

  • 每轮对话结束时:写入用户query和Agent响应摘要
  • 关键决策点:写入Agent做出重要判断的推理过程
  • 任务完成时:写入任务整体执行摘要,供后续参考
python 复制代码
class MemoryManager:
    def __init__(self, working: WorkingMemory, long_term: LongTermMemory):
        self.working = working
        self.long_term = long_term
    
    def on_turn_end(self, user_query: str, agent_response: str):
        """每轮结束时写入记忆"""
        # 写入工作记忆
        self.working.add_turn("user", user_query)
        self.working.add_turn("assistant", agent_response)
        
        # 关键内容写入长期记忆
        if self._is_significant(user_query, agent_response):
            summary = self._summarize(user_query, agent_response)
            self.long_term.store(
                text=summary,
                metadata={"type": "turn_summary", "timestamp": datetime.now().isoformat()}
            )
    
    def _is_significant(self, query: str, response: str) -> bool:
        """判断是否是重要内容"""
        # 例如:包含用户偏好、关键决策、错误修复等
        keywords = ["喜欢", "偏好", "不要", "记住", "修复", "问题"]
        return any(kw in query or kw in response for kw in keywords)

四、评估器:Agent的"质检员"

评估器负责判断当前状态是否已达到目标、是否需要调整策略。没有评估器的Agent,就像没有质检的工厂------可能在错误的道路上狂奔到底。

4.1 结果评估

最基础的评估:判断任务是否完成。

python 复制代码
def evaluate_completion(task: str, result: str, llm) -> dict:
    """评估任务是否完成"""
    prompt = f"""任务:{task}
执行结果:{result}

请判断任务是否成功完成:
- 如果结果完全满足任务要求,返回 {{"status": "success", "reason": "..."}}
- 如果结果不满足要求,返回 {{"status": "failed", "reason": "缺少XX,YY有问题"}}
- 如果结果部分满足,返回 {{"status": "partial", "reason": "..."}}"""
    
    response = llm.generate(prompt)
    return json.loads(response)

4.2 过程评估(Early Stopping)

不是所有任务都能在预设步数内完成,但要避免Agent在错误方向上浪费步数。过程评估在每步执行后判断:继续走下去是否有意义?

python 复制代码
def evaluate_progress(task: str, history: list, llm) -> dict:
    """评估当前进度是否值得继续"""
    prompt = f"""任务:{task}
执行历史:{json.dumps(history, ensure_ascii=False)}

请判断:
- 如果继续执行有望完成任务,返回 {{"continue": true, "reason": "..."}}
- 如果当前路径不太可能成功,返回 {{"continue": false, "reason": "应尝试XX方向"}}
"""
    response = llm.generate(prompt)
    return json.loads(response)

4.3 多维度评估

实际系统中,评估可能涉及多个维度:正确性、效率、成本、用户体验

python 复制代码
from dataclasses import dataclass

@dataclass
class EvaluationResult:
    success: bool
    correctness: float  # 0-1,正确性评分
    efficiency: float   # 0-1,效率评分(用时/期望用时)
    cost: float         # 实际成本
    feedback: str       # 详细反馈

def multi_dimension_evaluate(
    task: str,
    result: str,
    expected_time: float,
    expected_cost: float,
    llm
) -> EvaluationResult:
    # ... 多维度评估逻辑
    pass

五、四大组件如何协同

说了这么多独立组件,关键是它们怎么串联起来工作。

复制代码
用户输入/任务
    ↓
规划器(Planner)→ 理解任务,拆解步骤,决定下一步action
    ↓
工具层(Tools)→ 执行action,获取结果
    ↓
评估器(Evaluator)→ 判断结果,决定是否继续/调整策略
    ↓
记忆(Memory)→ 写入执行记录,支持下一轮规划
    ↓
循环,直到任务完成或放弃

用一个完整的执行循环来串联:

python 复制代码
class Agent:
    def __init__(self, llm, tools: list, memory_manager, evaluator):
        self.llm = llm
        self.tools = {t["name"]: t for t in tools}
        self.memory = memory_manager
        self.evaluator = evaluator
    
    async def run(self, task: str, max_steps: int = 10):
        """Agent主运行循环"""
        self.memory.working.set_context("task", task)
        history = []
        
        for step in range(max_steps):
            # 1. 规划:决定下一步
            context = self.memory.working.get_context()
            action = self.llm.plan(task, context, history)
            
            if action["name"] == "finish":
                return {"status": "success", "result": action["input"]}
            
            # 2. 执行工具
            if action["name"] in self.tools:
                tool_result = await self.memory.tool_executor.execute(
                    self.tools[action["name"]],
                    action["input"]
                )
                observation = tool_result.get("result", tool_result.get("error"))
            else:
                observation = f"未知工具: {action['name']}"
            
            history.append({
                "step": step,
                "action": action,
                "observation": observation
            })
            
            # 3. 评估:判断是否继续
            eval_result = self.evaluator.evaluate_progress(task, history)
            if not eval_result["continue"]:
                # 策略调整:让LLM重新规划
                task = f"{task}(上条路径不可行,建议:{eval_result['reason']})"
            
            # 4. 写入记忆
            self.memory.on_step_complete(action, observation)
        
        return {"status": "failed", "reason": "超过最大步数"}

写在最后

设计Agent架构,核心是让四个组件各司其职、协同工作。规划器做决策,工具执行动作,记忆存储上下文,评估器控制质量。

但我想泼一盆冷水:现在的Agent系统,远没有达到"智能"的水平。规划依赖LLM的推理能力,而LLM的推理是不稳定的;工具调用依赖准确的参数描述,但现实中的工具往往是遗留系统,描述质量参差不齐;记忆的检索和写入策略,没有统一标准,全靠团队经验。

真正的挑战不在于"能不能搭起来",而在于"搭起来之后能不能稳定跑、出了故障能不能排查、效果不好能不能优化"。这是工程问题,不是算法问题。

你目前在做的Agent项目,遇到的最大瓶颈是什么?规划失控、工具报错、还是记忆丢失?


相关推荐
Claw开发者2 小时前
Hermes 接 LiteLLM 缓存不生效踩坑记录
人工智能·agent
齿轮2 小时前
Agent 管理范式演进:从管一句话到管整个系统
人工智能·后端
AIGCmagic社区2 小时前
AI多模态理论基础高频考点
人工智能
珹洺2 小时前
C++AI多模型聊天系统(三)AI多模型(豆包/Kimi/千问)接入与实现
开发语言·c++·人工智能
啷咯哩咯啷2 小时前
纯本地运行的私人文档知识库
前端·人工智能·后端
FrontAI2 小时前
深入浅出 LangGraph —— 第7章:持久化与检查点机制
人工智能·langchain·ai agent·langgraph
探物 AI2 小时前
【感知·车道线检测】UFLDv2车道线检测与车道偏离预警(LDWS)实战
人工智能·算法·目标检测·计算机视觉
Swilderrr2 小时前
学术研读报告:MEM1面向长视距智能体的记忆 - 推理协同框架
人工智能
aLTttY2 小时前
Spring Boot整合AI大模型实现智能问答系统实战
人工智能·spring boot·后端