序:Agent 的”失忆症”
你还记得三天前的午餐吃了什么吗?大概率不记得。
但如果我问你”你的名字是什么””你的技术栈偏好是什么””你的项目目录结构是怎样的”,你应该能立刻回答。因为这些信息已经进入了你的长期记忆。
现在的 AI Agent 恰恰相反。它就像一个患有严重顺行性遗忘症的病人——每次对话都是全新开始,对话结束就忘得一干二净。
在上一篇文章中,我们构建了一个覆盖前后端的 AI 开发团队:PM Agent 拆解需求,前端和后端 Agent 并行编码,QA Agent 审查,DevOps Agent 部署。整套流程跑下来很顺畅,但有一个致命的问题:
每次你重新打开终端,Agent 都不认识你了。
它不记得你用的是 React 还是 Vue,不记得你偏好 pnpm 还是 npm,不记得上次写到一半的任务卡在哪里。更致命的是,当你构建一个客服 Agent或个人助手时,它需要对用户的偏好、历史提问、项目上下文有持续的记忆。没有记忆的 Agent,就像一个每次都重新投简历的”新员工”。
记忆不是 Agent 的附加功能,它是 Agent 从”工具”进化到”伙伴”的核心基础设施。
本篇是《前端 + AI Agent 开发实战》系列的第四篇。我们将深入探讨 Agent 的记忆系统——从概念到架构,从代码到优化,让你构建的 Agent 真正”记住”该记住的东西。
一、记忆的分类体系:三层记忆模型
在认知科学中,人类记忆被分为感觉记忆 → 短时记忆 → 长时记忆。Agent 的记忆系统借鉴了同样的分层思想,但用计算机的术语重新定义了每一层:
1 | ┌─────────────────────────────────────────────────┐ |
1.1 短期记忆:上下文窗口(Context Window)
这是最直接的记忆形式。LLM 的上下文窗口——GPT-4o 的 128K、Claude 的 200K——就是 Agent 的短期记忆。
1 | // 短期记忆的本质:消息数组 |
优势:所有信息即时可用,LLM 可以直接读取,无需检索。
劣势:窗口有限,满了就得丢掉旧内容;对话结束后全部丢失。
短期记忆就像你手机上的”最近应用”——方便快速切换,但数量有限,重启后就清空了。
1.2 工作记忆:会话级状态(Working Memory / Session State)
工作记忆是 Agent 在当前会话中维护的结构化状态。它不同于短期记忆——短期记忆是对话的”原文”,工作记忆是 Agent 从中提取出来的”要点”。
1 | // 工作记忆:结构化的会话状态 |
优势:结构化、可查询、可更新,不受上下文窗口限制。
劣势:会话结束后丢失,除非显式持久化。
1.3 长期记忆:跨会话持久化(Long-term Memory)
这是真正让 Agent 拥有”身份”和”经验”的记忆层。长期记忆分为两类:
| 类型 | 含义 | 示例 | 存储方式 |
|---|---|---|---|
| 语义记忆 (Semantic) | 知识、事实、偏好 | “用户偏好 React + TypeScript””项目使用 pnpm monorepo” | 键值存储 / 结构化数据库 |
| 情节记忆 (Episodic) | 历史对话、事件 | “昨天用户修改了支付模块的 bug””上周 QA Agent 指出了3个常见错误” | 向量数据库 / 全文搜索 |
1 | // 长期记忆的数据模型 |
类比理解:短期记忆是你正在看的这本书的这一页,工作记忆是你对本章内容的理解笔记,长期记忆是整本书以及你读过的所有其他书。
二、短期记忆管理:上下文窗口的艺术
短期记忆虽然是”最低级”的记忆形式,但它的管理却是最直接影响 Agent 输出质量的环节。因为 LLM 的输出质量与上下文中信息的相关性和密度高度正相关。
2.1 上下文窗口的三大难题
1 | // 难题一:窗口溢出 |
2.2 上下文压缩策略
1 | // 策略一:工具结果摘要化 |
2.3 Vercel AI SDK 的上下文管理
如果你使用的是 Vercel AI SDK(系列第一篇推荐的工具链),它其实内置了一些上下文管理机制:
1 | import { generateText, trimMessages } from 'ai'; |
但 trimMessages 的策略过于简单粗暴——直接截断。对于需要精细管理上下文的应用,需要自定义策略。
三、工作记忆:结构化会话状态
工作记忆是 Agent 在会话期间的”草稿纸”。短期记忆记录的是”对话原文”,工作记忆记录的是 Agent 从中提取和推断出的”结构化认知”。
3.1 工作记忆的核心职责
1 | // 工作记忆管理器 |
3.2 LangGraph 的状态机:工作记忆的最佳实践
在前一篇中,我们使用了 LangGraph 的 Annotation.Root 作为多 Agent 系统的共享状态。这本质上就是工作记忆的实现:
1 | import { Annotation, StateGraph } from '@langchain/langgraph'; |
关键设计原则:LangGraph 的
reducer定义了状态的合并策略。messages字段使用concatreducer,新消息追加到末尾;而userPreferences使用默认 reducer(替换),新值完全覆盖旧值。
3.3 工作记忆的”遗忘”策略
工作记忆虽然理论上可以无限大,但全部加载到内存既不现实也不高效。你需要一个选择性遗忘策略:
1 | // 工作记忆压缩器 |
四、长期记忆:跨越会话的”元认知”
这是本文的核心。让 Agent 记住这一会话之前发生的事情——这才是真正的”记忆”。
4.1 长期记忆的存储选型
1 | 存储需求分析: |
为什么需要两种存储:
语义记忆(偏好、规范)是精确的——用户用的就是 TypeScript,不是”类似 TypeScript 的语言”。这类数据用 PostgreSQL 或 KV 存储,直接 key-value 查询。
情节记忆(对话、事件)是模糊的——“上次那个支付模块的 bug 是怎么修来着?”你需要找到语义上最接近的历史记录,而不是精确匹配某个关键词。这类数据用向量数据库存储,通过 embedding 相似度检索。
4.2 长期记忆的基础实现
1 | // src/memory/long-term-memory.ts |
4.3 记忆的生命周期管理
记忆不能无限制地堆积。每存储一条记忆都有成本(存储成本+检索噪音)。你需要记忆的生命周期管理:
1 | // src/memory/memory-lifecycle.ts |
五、记忆系统架构设计
现在我们把三层记忆整合起来,设计一个完整的记忆系统。
5.1 整体架构图
1 | ┌──────────────────────────────────────────────────────┐ |
5.2 记忆编排器实现
1 | // src/memory/memory-orchestrator.ts |
5.3 记忆注入时机
记忆不是在”用户问了才去查”——好的记忆系统是主动的。在以下时机自动注入记忆:
1 | // 记忆注入的触发点 |
六、LangGraph 记忆机制深入
如果你在上一篇中使用了 LangGraph 来编排多 Agent 系统,那么你很幸运——LangGraph 有内置的记忆持久化机制。
6.1 MemorySaver:会话内记忆
MemorySaver 是 LangGraph 最简单的 checkpoint 机制。它在内存中保存状态的快照,会话内可用,进程重启后丢失。
1 | import { MemorySaver } from '@langchain/langgraph'; |
MemorySaver 的核心价值在于断点续跑:
1 | // 如果 Agent 在一个长任务中卡住了(比如超时) |
6.2 PostgresSaver:跨会话持久化
PostgresSaver 把 checkpoint 持久化到 PostgreSQL。这意味着——
Agent 关掉重启后依然记得对话状态。
1 | import { PostgresSaver } from '@langchain/langgraph-checkpoint-postgres'; |
6.3 LangGraph Store:原生的长期记忆 API
LangGraph 0.2+ 引入了 Store 接口,专门用于长期记忆:
1 | import { InMemoryStore } from '@langchain/langgraph'; |
Store 的 namespace 设计很巧妙——它天然支持多租户和多维度:
1 | // 用户维度的记忆 |
6.4 将 LangGraph Store 与向量搜索结合
InMemoryStore 适合精确 key-value 查询,但它不支持语义检索。对于情节记忆的检索,你需要将 Store 和向量数据库结合:
1 | class LangGraphMemoryStore { |
七、实战:为多 Agent 团队添加记忆
现在我们把记忆系统集成到上一篇文章构建的 AI 开发团队中。
7.1 改造目标
将上一篇的”失忆”流水线改造为”有记忆”的智能团队:
| 改造前 | 改造后 |
|---|---|
| 每次新项目从零开始 | PM Agent 记住历史项目的需求模式 |
| 前端 Agent 不记得之前的组件 | 自动检索相似的已有组件,复用而非重写 |
| QA Agent 无历史参考 | 基于历史审查记录,优先检查高频错误 |
| DevOps Agent 每次都从零写配置 | 基于历史配置模板快速生成 |
7.2 创建记忆感知的 Agent 工厂
1 | // src/agents/memory-aware-agent-factory.ts |
7.3 记忆感知的 QA Agent
QA Agent 是最能从记忆中受益的角色——它可以记住高频错误模式:
1 | // src/agents/memory-aware-qa-agent.ts |
7.4 集成后的流水线
1 | // src/orchestrator-memory-aware.ts |
八、记忆压缩与检索优化
记忆系统面临一个核心矛盾:记得越多,检索越慢,噪音越大。如果不加控制,记忆系统最终会变成一个”什么都记得但什么都找不到”的信息沼泽。
8.1 分级记忆缓存
1 | // 三级缓存策略:热 → 温 → 冷 |
8.2 增量式记忆摘要
1 | // 将原始对话"蒸馏"为分层摘要 |
8.3 基于时间衰减的记忆权重
1 | // 艾宾浩斯遗忘曲线启发的记忆权重计算 |
8.4 检索效率优化
1 | // 向量检索的几个优化技巧 |
九、总结与未来展望
9.1 核心要点回顾
| 层次 | 是什么 | 怎么实现 | 生命周期 |
|---|---|---|---|
| 短期记忆 | 上下文窗口中的消息 | 消息数组管理 + 压缩 | 单次对话 |
| 工作记忆 | 会话中的结构化状态 | LangGraph State / 自定义状态 | 单次会话 |
| 语义记忆 | 偏好、规范、知识 | PostgreSQL / KV 存储 | 永久(手动更新) |
| 情节记忆 | 历史对话、事件、决策 | pgvector / 向量数据库 | 永久(自动衰减) |
五个核心设计原则:
- 分层存储:不要把所有记忆塞进上下文窗口。短期、工作、长期各司其职。
- 主动注入:记忆不是等用户问才查,而是在关键时机自动注入。
- 结构化+语义化双模式:偏好用精确查询,历史用语义检索。
- 生命周期管理:记忆需要冷却、合并、淘汰,否则会变成信息沼泽。
- LangGraph 加持:如果使用多 Agent 编排,LangGraph 的 Store + PostgresSaver 是最快上手的选择。
9.2 什么时候该用哪种记忆?
1 | 用户说:"帮我创建一个登录页面" |
9.3 从记忆到”认知”
记忆是 Agent 智能化的基础,但它不是终点。在记忆之上,还有更高层的认知能力:
1 | 记忆(Memory) |
9.4 系列文章路线图
本系列已发布和计划中的文章:
| 篇 | 主题 | 状态 |
|---|---|---|
| 一 | 从 AI 补全到自主开发:前端工程师的范式跃迁 | ✅ 已发布 |
| 二 | Agent 工具设计模式:如何为你的项目定制工具集 | ✅ 已发布 |
| 三 | 多 Agent 编排实战:构建 AI 开发团队 | ✅ 已发布 |
| 四 | Agent 的记忆与状态管理(本文) | ✅ 已发布 |
| 五 | Agent 的安全与权限控制 | 🔜 即将发布 |
| 六 | 从开发到生产:Agent 应用的部署与监控 | 📋 规划中 |
9.5 写在最后
如果你正在构建一个 Agent 应用,我建议你不要等到”需要记忆”时才去设计记忆系统。就像你不会等到用户数据丢失了才去设计数据库——记忆系统应该从一开始就作为 Agent 的基础设施来规划。
一个简单的起步建议:
- 第一周:实现语义记忆(用户偏好 + 项目规范),用 PostgreSQL 存储
- 第二周:加入情节记忆(历史对话摘要),用 pgvector 做语义检索
- 第三周:优化生命周期管理(合并、衰减、淘汰)
- 第四周:整合到 LangGraph 的多 Agent 流水线中
记忆不是 Agent 的”附加功能”。就像没有海马体的人类无法形成新的记忆一样,没有记忆系统的 Agent 永远无法成为真正的”智能体”。
本文所有代码可在真实环境中运行。如果你在实践过程中遇到问题,欢迎在评论区讨论。下一篇我们将深入探讨 Agent 的安全与权限控制——当 Agent 可以执行代码、读写文件、访问网络时,如何确保它不会成为安全漏洞的来源。