Agent记忆能力全解析:从记忆管理器到记忆感知智能体
2026/9/8 4:58:08 网站建设 项目流程

先问大家一个问题:你在开发 Agent 的时候,是不是经常遇到这种情况——同一个用户上次已经明确说过“我在北京,通勤靠地铁”,下次你再问天气时,又把推荐方案重新按开车生成一遍?又或者多轮对话里只要超过几轮,模型就开始“失忆”,前后逻辑对不上?

这其实是 Agent 开发里最容易被忽略、又最影响体验的短板:记忆能力。很多人花大量时间调 prompt、调工具调用,却忽略了让 Agent“记住该记住的、忘掉该忘掉的”这套系统工程。

本文围绕 Agent 记忆这一核心能力展开,重点拆解记忆管理器(Memory Manager)、记忆感知智能体(Memory-Aware Agent)的设计思路,并结合用一个可运行的 Python 示例,带你完整走一遍“记忆从写入、存储、检索到更新”的闭环。文章不追求大而全的框架罗列,重点是帮你建立一套可落地的记忆架构认知。

内容适合以下读者:

  • 正在用 LangChain、LlamaIndex 或自研框架做 Agent 开发的工程师;
  • 需要一个更稳定的多轮对话 / 个性化推荐方案的产品开发者;
  • 刚接触 Agent,想系统理解“智能体记忆”到底是什么的新手。

读完这篇文章,你将能:

  1. 说清楚短期记忆、长期记忆、工作记忆的区别;
  2. 画出记忆管理器在 Agent 主循环里的位置;
  3. 实现一个带记忆管理器的“记忆感知智能体”最小原型;
  4. 排查 Agent 记忆丢失、记忆污染、上下文爆炸等常见问题。

开始之前先说明一点:本文不绑定任何特定付费课程,代码基于通用思路实现,你可以在 LangChain、自研框架或任何 Python Agent 项目里迁移使用。

1. 为什么 Agent 需要记忆能力

1.1 没有记忆的 Agent,等于“每次都在面试”

我们先从最直观的场景说起。

假设你正在做一个“个人健康助手”Agent。用户第一轮说:

我最近在减脂,晚餐尽量控制在 500 大卡以内。

第二轮说:

帮我推荐今晚吃什么。

如果 Agent 没有记忆,它完全不知道“减脂”“500 大卡”这些背景信息,只会按通用逻辑推荐一个普通食谱。用户就会觉得:这个 Agent 不太聪明,聊过就忘。

再换一个更贴近开发的场景:你在用 Agent 做测试用例生成。第一轮你已经告诉它“项目使用 Spring Boot 3 + Maven,接口返回格式统一是 Result ”,后续如果 Agent 每次都忘记这些约定,就会生成一堆不符合项目风格的测试代码。

在 Agent 技术体系里,这种“丢失前文信息”的问题,核心原因就是记忆能力缺失。

1.2 记忆能力的专业定义

在智能体领域,记忆并不仅仅是“把聊天记录塞进上下文”。更准确地说,记忆是 Agent 对交互历史、用户偏好、任务状态和环境信息的持久化表示,它帮助 Agent 在时间维度上保持一致性。

从架构角度看,Agent 记忆通常分三个层次:

层级英文术语特点典型实现
短期记忆Short-Term Memory当前会话内有效,容量有限,随上下文窗口变化对话历史列表、上下文窗口管理
工作记忆Working Memory当前任务执行过程中的临时状态,任务结束可清理任务堆栈、中间结果缓存
长期记忆Long-Term Memory跨会话持久化,可长期积累用户画像、偏好、知识向量数据库、KV 存储、SQLite

在实操中,短期记忆和工作记忆往往交织在一起。比如 Agent 在调用工具时,工具返回的中间结果需要被临时保存,这就是工作记忆;而用户上一轮说的话,属于短期记忆。长期记忆则是在多个会话之间共享的“沉淀”。

1.3 记忆不是“聊天记录”这么简单

这里有一个容易混淆的点:很多刚入门的人以为“记忆 = 把 messages 数组一直往后拼接”。实际上,如果只拼接消息,一旦上下文超出模型窗口,你必须截断或丢弃旧消息,这时用户早期的偏好、约定就丢了。

真正的记忆管理器要做的是:

  • 判断哪些信息值得记住(信息抽取与筛选);
  • 决定存在哪里(短期还是长期);
  • 在合适的时候把记忆重新取出来(检索);
  • 当信息过期或冲突时进行更新和遗忘。

所以,记忆能力本质上不是一个存储功能,而是一个管理功能。这也是“记忆管理器”存在的意义。

2. 记忆体系在 Agent 整体架构中的位置

2.1 Agent 主循环中的记忆协作

一个典型的 Agent 执行流程可以简化如下:

用户输入 ↓ Agent 主循环(Reasoning-Acting) ↓ 调用 LLM 生成决策 调用工具/外部API 观察工具结果 ↓ 输出响应

记忆在这个循环中不是孤立组件,而是同时服务于多个环节:

  • 输入解析阶段:从当前用户输入 + 检索到的历史记忆中提取关键信息;
  • 决策阶段:LLM 需要结合用户偏好、历史任务、领域知识来做推理;
  • 工具调用阶段:记忆中的参数、约定、上下文可以帮助 Agent 更准确地生成工具入参;
  • 结果回写阶段:工具返回的重要结果可以写入记忆,供后续会话使用。

打个比方:记忆管理器就像 Agent 的“笔记本”。Agent 在干活前翻阅笔记本,干活时记录草稿,干完活把重要结论归档。

2.2 记忆基座(Memory Backend)分层

从实现角度看,我会把记忆体系拆成三个基础层:

  1. LLM 层记忆:模型上下文窗口内的信息,也就是 messages 数组里的内容。
  2. 框架层记忆:Agent 框架提供的 Memory 模块,例如 LangChain 的ConversationBufferMemoryConversationSummaryMemory等抽象。
  3. 接入层记忆:外部存储服务,如 Redis、SQLite、PostgreSQL、向量数据库(Chromadb、FAISS、Milvus 等)。

很多 Agent 项目的记忆问题,根源在于只用了“LLM 层记忆”(也就是纯上下文拼接),没有在框架层做提炼、在接入层做持久化。

2.3 记忆管理与 RAG 的区别

Agent 记忆和检索增强生成(RAG)经常被放在一起讨论,但两者的侧重不同:

  • RAG:面向“静态知识库”,解决的是“模型不知道某类知识”的问题,通常是先离线建索引,再在线检索。
  • Agent 记忆:面向“动态状态”,解决的是“模型记不住上下文、用户、任务状态”的问题,需要不断写入、更新、遗忘。

在实际产品中,两者常配合使用。比如一个企业客服 Agent,企业的规章制度文档走 RAG,用户个人的投诉记录走长期记忆,当前对话的情绪和上下文走短期记忆。

理解了这一点,我们下文讨论的所有设计,都聚焦在“Agent 记忆”部分,不展开 RAG 的索引和检索细节。

3. 记忆管理器(Memory Manager)核心设计

3.1 记忆管理器的职责

记忆管理器不是一个简单的类,而是一组策略的组合。我建议把它的职责拆成四块:

  1. 写入(Write):从对话中抽取值得记录的信息;
  2. 存储(Store):按类型写入不同存储介质;
  3. 读取(Read):根据当前场景检索相关记忆;
  4. 更新 / 遗忘(Update / Forget):处理记忆冲突、过期和遗忘。

之所以强调“策略”,是因为不同业务场景对记忆的需求差异极大。比如:

  • 电商导购 Agent 需要长期保存用户偏好(尺码、风格、价格区间);
  • 数据分析 Agent 可能只需要短期保存当前分析任务状态;
  • 客服 Agent 需要保存工单处理进度,但不能保存与业务无关的隐私信息。

因此,不要直接照搬一套通用的记忆管理代码就上线,建议先明确你的 Agent 要记住什么、不记什么。

3.2 记忆写入:从对话中抽取关键信息

记忆写入最容易踩的坑是“什么都存”。如果把每一轮对话原文都存入长期记忆,检索时会产生大量噪声,真正有用的用户偏好反而不突出。

更合理的做法是:设计一个抽取模块,把对话内容转化为结构化的记忆条目。

举例:

用户输入: 我平时上下班都是坐地铁,不太开车。 抽取结果: - type: user_preference content: 日常通勤主要乘坐地铁 entity: 用户 time: 2025-01-10 10:23:00

这种结构化条目在后续检索和更新时会非常方便。你可以用 LLM 来做抽取,也可以基于规则,甚至混合。

这里给一个简单的抽取提示词示例(不是完整代码,仅示意思路):

你是记忆抽取助手。请从用户输入中抽取需要长期记住的用户偏好、事实、约定。 输出JSON数组,格式如下: [{"type": "preference|fact|constraint", "content": "...", "entity": "..."}] 不需要抽取寒暄、无关内容。

3.3 记忆存储:不同记忆用不同介质

存储层建议遵循“短期轻量、长期可靠”的原则:

记忆类型推荐存储原因
短期记忆内存列表 / Redis读取快,会话结束可释放
工作记忆内存对象 / 任务上下文只在任务执行期间有效
长期记忆SQLite / PostgreSQL / 向量库需要持久化,支持检索
记忆索引向量数据库适合语义检索

如果你只是做原型,SQLite + JSON 就是很好的方案。不需要一开始就上 Milvus。等到记忆量超过几万条、需要语义相似度检索时,再引入向量数据库也不迟。

3.4 记忆读取:按需召回,不是全量灌入

很多人会把所有记忆拼进 prompt,这是很危险的做法。原因有两个:

  1. Token 成本高,你的上下文会被记忆占满;
  2. 信息噪声,大量不相关的记忆会干扰 LLM 生成质量。

正确的思路是“按需召回”。在每次用户产生新输入时,先根据当前输入与记忆的相关性,召回 Top-K 条最相关的记忆,再注入到上下文中。

召回方式可以简单可以复杂:

  • 简单方式:按用户 ID 拉取最近 N 条记忆;
  • 进阶方式:向量检索 + 关键词过滤 + 时间衰减权重。

3.5 记忆更新与遗忘

记忆不是一成不变的。用户可能修正自己的偏好,任务状态也会变化。你需要设计:

  • 更新策略:当新的用户偏好与旧记忆冲突时,以最新为准;
  • 遗忘策略:超过一定时间未使用的记忆,降低权重或归档;
  • 删除策略:用户主动要求删除或涉及隐私的数据,必须支持删除。

举例:用户之前说“我喜欢喝美式”,一个月后说“最近胃不好,改喝拿铁了”。如果记忆管理器不更新,后续推荐还会继续推美式,体验就很差。

在实际代码中,可以用优先级 + 时间戳 + 冲突检测来实现基础更新。

4. 从零实现一个轻量记忆管理器

下面我们进入实战环节。我将用 Python 实现一个基于 SQLite + JSON 的轻量记忆管理器,不依赖任何重型框架,方便你理解原理后再迁移。

4.1 示例目标

我们要实现以下功能:

  1. 支持短期对话历史记录;
  2. 支持从对话中抽取并保存长期记忆;
  3. 支持按用户 ID 检索相关记忆;
  4. 支持删除和简单更新。

这个示例不涉及向量检索,使用关键词匹配 + 时间排序,便于你理解核心流程。

4.2 项目结构

memory_agent_demo/ ├── memory_manager.py # 记忆管理器 ├── memory_agent.py # 记忆感知智能体 └── main.py # 运行入口

4.3 记忆管理器实现(memory_manager.py)

# 文件路径:memory_agent_demo/memory_manager.py import json import sqlite3 from datetime import datetime from typing import List, Dict, Optional class MemoryManager: """轻量级记忆管理器:短期记忆在内存,长期记忆存 SQLite""" def __init__(self, db_path: str = "agent_memory.db"): self.db_path = db_path # 短期记忆:使用字典保存每个会话最近的对话记录 # key: session_id, value: list of message dict self.short_term_memory: Dict[str, List[Dict]] = {} self._init_db() def _init_db(self): """初始化 SQLite 数据库表""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() cursor.execute(""" CREATE TABLE IF NOT EXISTS long_term_memory ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT NOT NULL, memory_type TEXT NOT NULL, content TEXT NOT NULL, entity TEXT, importance INTEGER DEFAULT 1, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ) """) conn.commit() conn.close() def add_short_term(self, session_id: str, role: str, content: str) -> None: """添加短期记忆(当前会话对话记录)""" if session_id not in self.short_term_memory: self.short_term_memory[session_id] = [] self.short_term_memory[session_id].append({ "role": role, "content": content, "time": datetime.now().isoformat() }) def get_short_term(self, session_id: str, limit: int = 10) -> List[Dict]: """获取短期记忆,默认返回最近 N 条""" messages = self.short_term_memory.get(session_id, []) return messages[-limit:] def clear_short_term(self, session_id: str) -> None: """清空短期记忆""" self.short_term_memory[session_id] = [] def add_long_term( self, user_id: str, memory_type: str, content: str, entity: Optional[str] = None, importance: int = 1 ) -> int: """写入长期记忆,返回记忆 ID""" now = datetime.now().isoformat() conn = sqlite3.connect(self.db_path) cursor = conn.cursor() cursor.execute(""" INSERT INTO long_term_memory (user_id, memory_type, content, entity, importance, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?) """, (user_id, memory_type, content, entity, importance, now, now)) conn.commit() memory_id = cursor.lastrowid conn.close() return memory_id def search_long_term( self, user_id: str, query: str, limit: int = 5 ) -> List[Dict]: """检索长期记忆。 这里为了演示简单,使用关键词包含匹配。 实际项目中可以替换为向量检索或混合检索。 """ conn = sqlite3.connect(self.db_path) cursor = conn.cursor() # 使用 LIKE 实现简单匹配 cursor.execute(""" SELECT id, memory_type, content, entity, importance, created_at, updated_at FROM long_term_memory WHERE user_id = ? AND content LIKE ? ORDER BY importance DESC, updated_at DESC LIMIT ? """, (user_id, f"%{query}%", limit)) rows = cursor.fetchall() conn.close() results = [] for row in rows: results.append({ "id": row[0], "memory_type": row[1], "content": row[2], "entity": row[3], "importance": row[4], "created_at": row[5], "updated_at": row[6] }) return results def delete_long_term(self, memory_id: int) -> None: """删除指定长期记忆""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() cursor.execute("DELETE FROM long_term_memory WHERE id = ?", (memory_id,)) conn.commit() conn.close() def update_long_term( self, memory_id: int, new_content: str, memory_type: Optional[str] = None ) -> None: """更新长期记忆内容""" now = datetime.now().isoformat() conn = sqlite3.connect(self.db_path) cursor = conn.cursor() if memory_type: cursor.execute(""" UPDATE long_term_memory SET content = ?, memory_type = ?, updated_at = ? WHERE id = ? """, (new_content, memory_type, now, memory_id)) else: cursor.execute(""" UPDATE long_term_memory SET content = ?, updated_at = ? WHERE id = ? """, (new_content, now, memory_id)) conn.commit() conn.close() def get_all_long_term(self, user_id: str, limit: int = 50) -> List[Dict]: """获取用户全部长期记忆(调试用)""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() cursor.execute(""" SELECT id, memory_type, content, entity, importance, created_at, updated_at FROM long_term_memory WHERE user_id = ? ORDER BY updated_at DESC LIMIT ? """, (user_id, limit)) rows = cursor.fetchall() conn.close() return [ { "id": row[0], "memory_type": row[1], "content": row[2], "entity": row[3], "importance": row[4], "created_at": row[5], "updated_at": row[6] } for row in rows ]

这段代码的核心思路是:短期记忆保存在内存中,速度快;长期记忆持久化到 SQLite,支持按用户查询、更新、删除。实际项目中,你可以把search_long_term里的 LIKE 检索替换成向量检索,以支持语义匹配。

4.4 记忆抽取与注入

接下来,我们写一个简单的记忆抽取函数。这个函数模拟 LLM 抽取,这里用一个规则示例代替:

# 文件路径:memory_agent_demo/memory_agent.py from memory_manager import MemoryManager def simple_extract_memory(user_input: str) -> list: """简单规则抽取记忆。 真实项目可以改为调用 LLM,让模型输出结构化记忆条目。 """ memory_candidates = [] preference_markers = ["我喜欢", "我习惯", "我平时", "我住在", "我常用"] for marker in preference_markers: if marker in user_input: content = user_input.strip() memory_candidates.append({ "memory_type": "user_preference", "content": content, "entity": "user" }) break return memory_candidates

当然,这只是演示。真实项目中,你更可能用一段 LLM 抽取 prompt:

def llm_extract_memory(user_input: str, llm_func) -> list: """使用 LLM 抽取记忆条目""" prompt = f""" 从以下用户输入中抽取值得长期记住的信息。 只返回 JSON 数组,不要额外解释。 格式:[{{"type": "preference|fact|constraint", "content": "..."}}] 用户输入:{user_input} """ result = llm_func(prompt) # 这里需要解析 JSON import json return json.loads(result)

4.5 记忆感知智能体主逻辑

现在我们把记忆管理器接入一个简单的 Agent 主循环:

# 文件路径:memory_agent_demo/memory_agent.py def build_prompt_with_memory(user_input: str, short_memories: list, long_memories: list) -> str: """把短期记忆和长期记忆包装成 prompt 上下文""" prompt_parts = [] if short_memories: recent_context = "\n".join( f"{m['role']}: {m['content']}" for m in short_memories ) prompt_parts.append(f"【最近对话】\n{recent_context}") if long_memories: long_context = "\n".join( f"- {m['content']}" for m in long_memories ) prompt_parts.append(f"【长期记忆】\n{long_context}") prompt_parts.append(f"【当前输入】\n{user_input}") prompt_parts.append("请基于以上信息回答用户问题。") return "\n\n".join(prompt_parts) class MemoryAwareAgent: """一个简单的记忆感知智能体""" def __init__(self, llm_func): self.memory = MemoryManager() self.llm_func = llm_func # 这是一个接收 prompt 返回字符串的函数 def chat(self, user_id: str, session_id: str, user_input: str) -> str: # 1. 写入短期记忆 self.memory.add_short_term(session_id, "user", user_input) # 2. 抽取长期记忆候选 extracted = simple_extract_memory(user_input) for item in extracted: self.memory.add_long_term( user_id=user_id, memory_type=item["memory_type"], content=item["content"], entity=item["entity"] ) # 3. 获取短期记忆和长期记忆 short_memories = self.memory.get_short_term(session_id, limit=6) long_memories = self.memory.search_long_term(user_id, query=user_input, limit=3) # 4. 构造 prompt prompt = build_prompt_with_memory(user_input, short_memories, long_memories) # 5. 调用 LLM response = self.llm_func(prompt) # 6. 写回短期记忆 self.memory.add_short_term(session_id, "assistant", response) return response

这里的主循环非常好理解,对应了我们前面说过的记忆流程:

  1. 用户输入先写入短期记忆;
  2. 尝试抽取长期记忆;
  3. 检索历史记忆;
  4. 拼接成 prompt;
  5. 调用 LLM;
  6. 响应写回短期记忆。

4.6 运行入口与验证

我们写一个 main.py 来模拟完整交互:

# 文件路径:memory_agent_demo/main.py from memory_agent import MemoryAwareAgent def mock_llm(prompt: str) -> str: """模拟 LLM,实际使用时请替换为真实模型调用""" # 实际项目中这里是 OpenAI / 本地模型 / 其他 LLM API return f"[模拟回答] 已收到你的信息,并处理完成。" if __name__ == "__main__": agent = MemoryAwareAgent(llm_func=mock_llm) user_id = "u_1001" session_id = "s_20250110" # 第一轮:用户透露偏好 r1 = agent.chat(user_id, session_id, "我喜欢喝美式咖啡,平时通勤坐地铁") print("第一轮回答:", r1) # 第二轮:提问,看看记忆是否生效 r2 = agent.chat(user_id, session_id, "我平时怎么上班?") print("第二轮回答:", r2) # 查看长期记忆 all_memory = agent.memory.get_all_long_term(user_id) print("长期记忆内容:") for m in all_memory: print(f"- {m['memory_type']}: {m['content']}")

运行后,你可以看到长期记忆表里保存了用户偏好,第二轮对话时search_long_term能检索到相关内容并注入 prompt。完整代码中,mock_llm只是演示,真正使用时你应该替换为 OpenAI、通义千问、文心、本地 Ollama 等模型的调用。

4.7 升级方向:引入向量检索

上面的示例用LIKE做记忆检索,用户输入“我平时出行方式是什么?”时,能匹配“我平时通勤坐地铁”里的“我平时”,从而命中。但如果用户换一种问法:“介绍一下我的通勤习惯”,LIKE 就匹配不上了。

解决方案是引入向量化:

  1. 对每条长期记忆生成 embedding 向量,存入向量数据库;
  2. 每次用户输入时,计算输入 embedding,检索最相似的 Top-K 条记忆;
  3. 将命中的记忆内容注入 prompt。

实现方式有很多,比如:

  • 使用chromadbFAISS本地向量库;
  • 使用 OpenAI Embedding API、通义 embedding 接口等生成向量。

伪代码示意如下:

# 伪代码示例:使用向量检索替换关键词检索 import chromadb from chromadb.utils import embedding_functions client = chromadb.PersistentClient(path="./chroma_db") collection = client.get_or_create_collection( name="agent_memory", embedding_function=embedding_functions.DefaultEmbeddingFunction() ) # 写入记忆 collection.add( ids=[str(memory_id)], documents=[content], metadatas=[{"user_id": user_id, "memory_type": memory_type}] ) # 检索记忆 results = collection.query( query_texts=[user_input], n_results=3, where={"user_id": user_id} )

引入向量检索后,记忆的召回效果会明显提升,这也是目前主流 Agent 记忆方案的基础做法。

5. 记忆感知智能体:从“能记住”到“会使用”

5.1 记忆感知智能体的行为闭环

一个真正“感知记忆”的 Agent,不只是把记忆塞进 prompt,而是要让记忆影响决策路径。常见的行为模式包括:

  1. 个性化生成:根据用户偏好调整回答风格、推荐内容;
  2. 状态恢复:用户重新进入会话时,自动恢复上次任务进度;
  3. 主动提醒:根据长期记忆中的约束,主动提醒遗漏信息;
  4. 冲突消解:当新信息与旧记忆冲突时,能主动澄清或更新。

5.2 用记忆增强 Agent 决策

以一个“旅行规划 Agent”为例:

  • 短期记忆中保存了用户当前对话里提到的目的地、出行日期;
  • 长期记忆中保存了用户过去说过的“不喜欢赶景点”“带小孩出行”“预算中等”三类偏好;
  • 工具调用层可以根据这些记忆,调整查酒店时的筛选条件,比如优先亲子房型;
  • 最终生成方案时,会主动避开“特种兵式”行程。

这些效果,仅靠 prompt 工程是做不到的,因为模型每次生成时都看不到历史会话。只有记忆管理器把“相关记忆”重新拉回上下文,模型才有机会基于完整信息做推理。

5.3 记忆感知的进阶技巧

在实际项目中,有几个值得实践的进阶技巧:

技巧一:记忆摘要化

当短期记忆超过一定长度时,不再简单丢弃,而是让 LLM 生成一段摘要,存入“会话摘要记忆”。下次会话开始时,把摘要注入替代原始长对话。

技巧二:记忆置信度

每条长期记忆可以附带置信度(confidence)和来源(source)。比如用户明确说“我住在杭州”置信度高,而“我可能在杭州待一段时间”置信度低。低置信度记忆在辅助决策时权重更低。

技巧三:按记忆类型分流

不要把用户偏好、任务状态、知识条目混在一起。推荐在记忆条目中加入“类型”和“用途”字段,不同用途的记忆在检索时的优先级不同。

6. 常见问题与排查思路

在开发 Agent 记忆功能时,你可能会遇到下面这些问题。我整理成了表格,方便快速定位。

问题现象常见原因解决思路
多轮对话超过 5 轮后,模型忘记早期信息短期记忆未截断或摘要,超长后被丢弃使用对话窗口管理,重要信息提前抽取写入长期记忆
记忆检索结果不相关,回答质量变差使用关键词检索,语义匹配能力不足引入向量检索,或使用混合检索(关键词 + 向量)
用户改了偏好,但 Agent 仍按旧偏好回答记忆更新策略缺失,旧记忆未删除或降权增加冲突检测,新记忆覆盖旧记忆,或降低旧记忆置信度
Token 成本增长过快每次全量灌入记忆,未做筛选按需召回 Top-K,使用摘要压缩长对话
用户隐私数据被持久化未做敏感信息过滤接入层过滤手机号、身份证等敏感字段,支持删除
Agent 在执行长任务时 “agent execution terminated due to error.”工作记忆状态丢失或上下文溢出将任务中间状态写入工作记忆存储,异常时恢复最近状态
长期记忆表数据越来越多,检索变慢表数据膨胀,未分批/未索引增加索引、定期归档陈旧记忆、设置记忆 TTL

7. 最佳实践与工程建议

7.1 记忆设计先于功能开发

很多 Agent 项目先写功能,最后才考虑记忆,导致后期需要大改。更合理的顺序是:

  1. 明确 Agent 的服务对象和业务场景;
  2. 列出必须记住的信息类型;
  3. 设计记忆条目的数据结构;
  4. 再开始写功能代码。

7.2 写入时过滤,好过检索时过滤

在记忆写入阶段就做“重要性判断”,比存储所有内容再靠检索过滤要省事得多。对明显无关的信息(寒暄、临时语气词、重复内容)不做持久化。

7.3 给记忆加时间戳和来源

所有长期记忆条目都应该包含:

  • created_at:创建时间;
  • updated_at:最近更新时间;
  • source:来源,比如“用户显式声明”“Agent 推断”“工具结果回写”;
  • confidence:置信度。

有了这些字段,后续做记忆更新和冲突消解才有依据。

7.4 设计记忆遗忘机制

记忆不是越多越好,遗忘是记忆系统不可或缺的部分。可以设计两种遗忘机制:

  • 主动遗忘:用户说“忘掉我之前说的咖啡偏好”,Agent 删除相关记忆。
  • 被动遗忘:超过 90 天未命中的记忆,降低重要性或归档。

7.5 记忆隔离与安全

如果你的 Agent 服务多个用户,长期记忆表必须带user_id隔离,任何检索都要带用户条件,防止数据串号。

这一点在做记忆功能时经常被忽视。回头检查代码,很多新手在接入向量数据库时,只把记忆存进 collection,忘了按 user_id 做过滤,结果用户 A 的偏好被用户 B 检索到,这是非常严重的安全事故。

7.6 测试记忆闭环

记忆功能的测试不能只测单轮对话。建议建立一套“记忆回归用例”:

场景:用户告知偏好 → 验证长期记忆表是否写入正确条目 场景:用户再次提问相关问题 → 验证检索结果是否包含相关记忆 场景:用户修改偏好 → 验证旧记忆是否被更新或降权 场景:用户要求删除记忆 → 验证对应记录是否被删除

把这套用例固化到 CI 里,可以避免后续迭代时记忆逻辑被无意破坏。

8. 总结与下一步学习路线

这篇文章围绕“Agent 记忆”这个主题,从概念到代码完整走了一遍。核心知识点总结如下:

  1. Agent 记忆分为短期记忆、工作记忆和长期记忆,各自的存储和生命周期不同;
  2. 记忆管理器负责写入、存储、读取、更新和遗忘,不是简单的消息拼接;
  3. 记忆检索推荐用向量化召回,但原型阶段用关键词匹配也可以跑通流程;
  4. 记忆感知智能体的关键是让记忆影响决策,需要设计记忆结构化、更新和冲突消解策略;
  5. 生产环境必须考虑记忆隔离、遗忘、隐私删除和测试闭环

如果你正在学习 Agent 开发,下一步可以按这个顺序深入:

  1. 先把本文中的 SQLite 版记忆管理器跑通,理解数据流;
  2. 引入一个向量数据库,把关键词检索替换为向量检索;
  3. 用真实 LLM 替换mock_llm,测试多轮对话下的记忆效果;
  4. 学习现成框架的 Memory 模块源码,例如 LangChain 的 BaseChatMemory、LlamaIndex 的 Memory 模块;
  5. 尝试设计自己业务场景下的记忆数据结构,并写一套记忆回归测试。

写 Agent 的时间越长,越会意识到一点:记忆不是“存储”,而是“选择”。真正好的记忆系统知道什么该记住,什么该忘记,什么该在什么时候想起来。希望这篇文章能帮你把这条技术路径走通。

如果本文对你有帮助,欢迎收藏备用,也欢迎在评论区聊聊你在 Agent 记忆开发中遇到的坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询