把 Agent 拆成”感知、决策、执行、记忆”四个组件,几乎已经是工程上的事实标准——任何主流 Agent 框架(LangGraph、CrewAI、AutoGen、Semantic Kernel)都能在这个四元模型里找到对应模块。在做智能客服 Agent 的第一个版本时,我把所有逻辑塞进一个大语言模型调用里,结果它既记不住用户偏好,也不会主动调用工具;拆成这四个组件后,每个模块都能独立替换和测试,问题定位时间从半天压到十几分钟。下文把这四个组件的职责边界、典型实现和协作流程拆开讲清,重点是工程团队最关心的”谁管什么、谁不该越界”。
一、感知层:Agent 与外部世界的输入接口
感知层负责把环境信号(用户输入、工具返回、其它 Agent 的消息、文件变化)转成 LLM 能消费的标准化结构。
工程上它至少要完成三件事:
- 格式归一化:用户的自然语言、工具的结构化 JSON、其它 Agent 的富文本消息,统一规整成 messages 数组。
- 安全清洗:拦截 prompt 注入(把可疑指令降级为数据)、过滤超长输入(超过上下文预算的截断或摘要)。
- 上下文打包:把当前可用的工具描述、记忆片段、系统提示词打包成 LLM 下一步推理所需的完整 prompt。
在多模态场景下,感知层还要做图片/音频/视频的预处理——把它们转成 token 化的描述或多模态 embedding。
二、决策层:LLM 的推理与规划中枢
决策层是 Agent 的”大脑”,通常由一个大语言模型承担,负责把感知层的输入转成”下一步该做什么”的决策。
它一般要解决三类问题:
- 意图理解:用户到底想要什么?是查订单、投诉、还是闲聊?
- 任务规划:要把这个意图拆成几步?每一步依赖什么前置结果?
- 行动选择:这一步该调用哪个工具、还是直接给答案、还是询问用户?
决策层的输出通常是一个结构化的”行动计划”——可能是”调用 weather_api(参数:北京)”,也可能是”先把任务拆成 3 步:查库存、查价格、查物流”。
三、执行层:把决策落到真实环境
执行层是 Agent 的”手脚”,负责把决策层的计划真实地跑起来——调用 API、写文件、跑命令、发消息。
执行层在工程上有几个关键设计点:
- 工具注册表:所有可用工具集中注册,每个工具有 name、description、parameters schema。LLM 只能从这个白名单里选,避免幻觉调用。
- 参数校验:LLM 输出的参数必须按 schema 校验后再执行,缺字段、类型错、值越界全部拦截。
- 超时与重试:每次调用有上限(比如 30 秒),失败有退避策略,连续失败 N 次升级为人类接管。
- 副作用控制:写操作要二次确认、关键路径要走人工审批、危险操作(rm、删表)要 dry-run 预览。
四、记忆层:让 Agent 拥有”前因后果”
记忆层负责存储和检索跨会话、跨任务的状态信息,通常分三层:
- 工作记忆:当前会话的对话历史,存在上下文窗口里,会话结束清空。
- 短期记忆:单个任务内的中间结果(比如多步推理的中间变量、工具返回值),存在 Redis 或内存里,任务结束清空。
- 长期记忆:跨会话的用户偏好、知识库、历史任务摘要,存在向量库 + 关系数据库里,几乎不删除。
四层组件的协作流程可以这样表示:
| 阶段 | 感知层 | 决策层 | 执行层 | 记忆层 |
|---|---|---|---|---|
| 用户发来消息 | 接收并清洗 | — | — | 检索相关长期记忆 |
| 思考该做什么 | 提供当前上下文 | 推理、规划 | — | 提供历史偏好 |
| 决定调用工具 | — | 输出工具名+参数 | — | — |
| 执行工具调用 | 接收工具返回 | 解析返回、判断下一步 | 真正调用外部 API | 记录调用结果到短期记忆 |
| 生成最终回答 | — | 综合所有信息生成 | 渲染输出格式 | 把本轮摘要写入长期记忆 |
| 用户继续对话 | 新一轮输入 | — | — | 检索更新后的记忆 |
五、四个组件的协作流程
典型的 Agent 循环(ReAct 风格)是这样跑的:
- 感知层接收用户消息,打包成 prompt;
- 决策层推理出 Thought、Action、Action Input;
- 执行层调用工具,拿到 Observation;
- 感知层把 Observation 加到上下文,回到步骤 2;
- 决策层判定”任务完成”,输出 Final Answer;
- 记忆层把本轮对话和关键结果摘要写入长期记忆。
循环的关键是谁也不能单独决定下一步——感知层不能擅自调用工具,决策层不能绕开执行层直接动环境,执行层不能改写记忆层。
六、常见的设计误区
把这四个组件当”必须严格分文件/分模块”的项目,通常会过度设计;把它们当”可以随便塞一起”的项目,通常会迅速腐化。两个常见反模式:
- 决策层吞所有逻辑:把工具调用、记忆读写、副作用控制都塞进 LLM 的 prompt,让它”自己看着办”。结果是 prompt 越来越长,LLM 越来越不可控。
- 执行层做决策:在工具内部做条件分支、状态机、决策树。结果是 Agent 失去了灵活规划的能力,变成一个写死的状态机。
下面是一段最小化代码,展示一个”四组件协作”的 Agent 循环:
class SimpleAgent:
def __init__(self, llm, tools, memory):
self.llm = llm # 决策层
self.tools = tools # 执行层
self.memory = memory # 记忆层
def step(self, user_msg):
# 感知层: 接收 + 检索相关记忆
context = self.memory.retrieve(user_msg)
prompt = f"用户:{user_msg}\n相关记忆:{context}"
# 决策层: 推理下一步
action = self.llm.decide(prompt, self.tools.schema)
# 执行层: 调用工具
if action.tool:
obs = self.tools.call(action.tool, action.params)
else:
obs = action.answer
# 记忆层: 写回
self.memory.store(user_msg, obs)
return obs
把四个组件各自做成可替换的接口,是后续做单元测试和性能优化的基础。
常见问题(FAQ)
Q1:四个组件必须分四个进程吗?
不需要。同一进程内不同模块即可,关键是职责边界清晰;只有需要横向扩展时才拆服务。
Q2:记忆层一定要向量库吗?
不一定。短期记忆用 Redis 就够,只有跨会话检索需求时才上向量库。
Q3:决策层必须用 LLM 吗?
绝大多数场景是,但简单分类/路由任务可以用规则引擎+小模型,反而更稳。