AI Agent失忆怎么办?一文讲透记忆系统设计

AI Agent失忆怎么办?一文讲透记忆系统设计 看到“AI Agent 失忆”这个话题很多开发者第一反应是模型不够聪明或者 Prompt 写得不到位。但如果你亲手做过一个多轮对话的 Agent大概率会遇到这种场景用户第一轮告诉你“我是做电商运营的周报请用表格输出”第二轮它就开始输出大段散文用户刚说过“不要用 MySQL我用的是 PostgreSQL”下一轮它又给出 MySQL 的连接方式。你以为是模型能力不行往往不是。真正的问题在于Agent 没有一套属于自己的记忆系统。2026 年的 AI Agent 开发纯粹的 Prompt 技巧和工具调用已经很难拉开差距。大家都会写 system prompt都会接工具都能跑通一个 Demo但真正决定产品体验上限的是记忆能不能跨轮、跨会话、跨多个 Agent 被复用。这个主题对应到很多视频教程里就是所谓的“Agent 记忆”。我不太建议把“B站No.1”这类称呼太当真但“失忆”确实是 Agent 从玩具走向生产力的第一道坎。这篇文章从理论讲到实战。我会先把 Agent 记忆的分层模型讲清楚然后带你用一个基于 SQLite 的最小记忆模块跑通整个流程最后补充 Redis 共享记忆和向量检索的工程选型思路。全文代码基于 Python 标准库和常见的模型接口版本信息请以你本机的实际环境为准。读完之后你应该能回答三个问题Agent 为什么会失忆一套可落地的记忆系统由哪些组件构成自己的项目应该从哪种记忆方案开始1. Agent 失忆问题的本质不是模型不行而是没有记忆系统要解决失忆先要承认一个事实大模型本身没有传统意义上的“记忆”。每一次 API 调用模型接收的是文本输入输出的是文本结果。模型内部并没有一个数据库去保存“用户上一轮说过什么”“用户偏好是什么”“这个任务进展到哪一步了”。你可能觉得这是废话但在实际开发里很多团队都是在出了 Bug 之后才想起来查日志看是不是消息列表没有拼对或者 context 被截断了。这里有三类最常见的失忆原因。第一类对话上下文没有被完整传递。Agent 和用户聊天时后端需要把历史消息拼到 messages 数组里。一旦数组被清空、被截断或者遗漏了某个角色的消息模型自然就“忘了”。第二类上下文窗口有限。即使你把所有历史消息都传给了模型窗口长度也是有限制的。对话超过几千 token早期内容就会被挤掉。用户最开始的偏好设定、任务目标恰恰是最容易被丢弃的。第三类没有跨会话持久化。很多 Agent 只支持单轮请求或者虽然支持多轮但服务一重启就全部丢失。用户下次再来又是陌生人的状态。所以“Agent 失忆”本质上不是一个模型智商问题而是一个系统架构问题。你需要在模型之外设计一层能够读写、更新、遗忘的记忆系统把用户和任务的长期状态保存下来。这也解释了另一个常见误区有人以为“上下文越长Agent 记忆力越强”。实际上盲目拉长 context 只会让模型的注意力被稀释还会让请求变慢、成本变高。正确做法是把“需要长期记住的信息”和“临时对话信息”分开管理。这就是我们常说的记忆分层。2. 记忆的分层模型短期记忆、长期记忆与工作记忆AI Agent 的记忆目前业界没有一个 100% 统一的标准术语但大部分框架和教程都接受一个分层模型短期记忆、长期记忆、工作记忆。另外有些教程会把它概括为“双网络记忆模型”本质上也是短期/长期配合的方式。先给这三个概念做一个通俗解释。短期记忆对应的是当前对话窗口里的上下文。它不需要额外存储因为你只要把 messages 传给模型模型就能够“看到”最近几轮的内容。缺点是窗口有限超过长度就会溢出。长期记忆对应的是跨会话、跨任务需要持久化的信息。比如用户的姓名、职业、使用偏好、项目历史结论。它通常落到数据库、文件、Redis、向量数据库中在需要时检索出来重新注入到上下文里。工作记忆对应的是 Agent 正在执行当前任务时产生的中间状态。例如一个多步骤任务执行到第几步、刚刚调用的工具返回了什么结果、下一步要做什么。这部分不需要永久保存但必须在任务执行期间随时可访问。用一个表格来对比会清楚一些记忆类型生命周期存储位置典型实现失效场景短期记忆当前对话或任务期间messages 上下文内存、对话窗口会话结束、上下文被截断长期记忆跨会话、跨任务外部存储SQLite、Redis、向量数据库没有持久化或遗忘机制工作记忆单个任务执行期间运行时状态Agent 内部状态对象任务结束、进程重启需要特别注意这里说的“长期记忆”和深度学习里的 LSTM 长短期记忆网络并不是一回事。LSTM 是循环神经网络的一种结构主要解决 RNN 处理长序列时的梯度消失问题而 Agent 记忆是系统层面上的数据存储与检索设计。两者都可以叫“记忆”但应用层次完全不同。如果你在搜资料时看到 LSTM 相关的内容不要直接套到 LLM Agent 上。从工程实现来看短期记忆通常不需要你额外写代码只要把 messages 列表管理好即可。真正需要设计的是长期记忆和工作记忆。大多数 Agent 项目的问题都出在“什么信息该进入长期记忆、什么信息只需要留在短期记忆”没有想清楚。3. 一套记忆系统需要哪些能力理解了分层模型之后我们再往前一步如果让你自己设计一个记忆模块它至少要有四种能力。写入能力Agent 每完成一轮对话或任务要把值得记住的信息抽取出来并写入存储。注意不是把所有原始文本都塞进去而是要去重、清洗、提取关键结论。存储能力这是最容易被想到的部分。你可以用关系型数据库、键值数据库、向量数据库甚至 JSON 文件。存储方案会直接影响后续的检索效果和扩展性。检索能力这是记忆系统的核心。用户提出新问题时Agent 要从长期记忆中找出与之相关的历史信息再注入到 Prompt 里。检索策略决定了“记忆到底用得上用不上”。更新与遗忘能力记忆不是只增不改。用户的偏好会变化旧的任务结论会过期甚至用户会主动要求删除某些信息。一个没有遗忘机制的记忆系统会在运行一段时间后积累大量噪声反而降低模型表现。很多教程只强调“把历史消息存起来”这其实是错误的理解。如果每次对话都把全部历史消息塞进长期记忆那和把 context 拉长没有本质区别。真正的长期记忆应该是经过筛选、去重、索引的信息库而不是对话流水账。用一个类比来说短期记忆像你手上正在读的草稿纸工作记忆像你脑子里当前要完成的几件事长期记忆像你存放在图书馆里的笔记。你需要写笔记更需要知道如何快速找到对应的那一页。不要总想着把所有东西都背下来那是低效的。4. 环境准备与依赖安装进入实战之前先检查环境。本文的示例代码以 Python 为主官方支持的版本建议使用 3.10 或更高版本。如果你用的是 3.8 或 3.9大部分代码也能运行但遇到类型注解或新语法时需要做小调整。需要准备以下内容Python 3.10已配置好 pipSQLite 3Python 3 自带 sqlite3 模块无需额外安装Redis 服务可选用于多 Agent 共享记忆演示一个模型服务。可以是 OpenAI 兼容接口也可以是本地部署的模型服务。如果只是先跑通记忆模块本身其实不需要安装第三方包因为 sqlite3 是 Python 标准库。但如果你要接入模型建议安装 OpenAI 的 Python SDK或者使用任何与 OpenAI 兼容的 request 封装。pip install openai如果要把记忆存到 Redis再安装 redis 客户端pip install redis这里不写死版本号是因为 2026 年的 SDK 版本变化很快你安装时直接使用当前最新稳定版即可。如果公司内部有固定的 Python 版本或依赖锁定机制请以项目实际约束为准。另外如果你使用本地模型例如通过 Ollama、vLLM 或 XInference 启动了一个 OpenAI 兼容服务代码中只需要修改 base_url 和 model 名称。本文后续示例会提供一个模拟模型回包的版本让你在没有模型 API 的情况下也能验证记忆逻辑是否生效。5. 实战一用 SQLite 做一个可持久化的记忆模块我们从一个最小的记忆模块开始。选用 SQLite 而不是向量数据库是为了先讲清楚记忆的读写链路避免把问题复杂化。5.1 记忆表设计新建一个文件memory_store.py内容如下# 文件路径memory_store.py import sqlite3 import time class SimpleMemory: def __init__(self, db_pathagent_memory.db): self.conn sqlite3.connect(db_path) self._init_table() def _init_table(self): self.conn.execute( CREATE TABLE IF NOT EXISTS memories ( id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT NOT NULL, memory_type TEXT NOT NULL DEFAULT long_term, created_at REAL NOT NULL, updated_at REAL NOT NULL ) ) self.conn.commit() def add_memory(self, content, memory_typelong_term): now time.time() self.conn.execute( INSERT INTO memories (content, memory_type, created_at, updated_at) VALUES (?, ?, ?, ?), (content, memory_type, now, now), ) self.conn.commit() def search_memory(self, keyword, limit10): cursor self.conn.execute( SELECT content, memory_type, updated_at FROM memories WHERE content LIKE ? ORDER BY updated_at DESC LIMIT ?, (f%{keyword}%, limit), ) return cursor.fetchall()这段代码里最关键的是 SQL 语句中的参数化查询。用户输入的内容不应该通过字符串拼接直接进入 SQL否则会引入注入风险。使用?占位符是最基本的安全习惯。memory_type字段用来区分长期记忆和短期记忆。在最小版本中你可以先统一存为long_term但建议保留这个字段方便后续扩展。5.2 写入与检索的基本流程在同一个文件末尾加一段测试入口# 文件路径memory_store.py if __name__ __main__: memory SimpleMemory(test_memory.db) memory.add_memory(用户喜欢用 Python 写自动化脚本) results memory.search_memory(Python) for content, memory_type, updated_at in results: print(content, memory_type)运行方式很简单python memory_store.py预期输出用户喜欢用 Python 写自动化脚本 long_term这个例子虽然简单但已经把“写入 - 存储 - 检索”的闭环跑通了。你可能会说这不是数据库查询吗对最小记忆系统本质上就是一个有读写能力的存储层。真正的难度在于当你接入 Agent 之后什么时候写入、检索到什么内容、怎么注入到 Prompt 里。6. 实战二把记忆接入 Agent 对话流程有了记忆模块下一步就是把记忆注入到 Agent 的对话流程中。我推荐的做法是在每轮调用模型之前先从长期记忆里检索与当前用户消息相关的历史内容放进 system prompt模型回复之后再把本轮的要点写入长期记忆。这样既不会把全部历史文本塞给模型又能让模型“想起”关键信息。6.1 模拟模型接口为了让你在没有模型 API 的情况下也能跑通演示我先写一个模拟call_model函数。它的逻辑很简单如果 system prompt 里包含“张三”就返回“我记得你叫张三”否则返回“我没有找到相关记忆”。# 文件路径agent_with_memory.py from memory_store import SimpleMemory def call_model(messages): # 仅用于本地演示生产环境请替换为真实模型接口 system_prompt messages[0][content] if messages[0][role] system else if 张三 in system_prompt: return 我记得你叫张三有什么可以帮你 return 我没有找到相关记忆。真实项目里你可以把这段替换成 OpenAI 兼容接口例如def call_model(messages): import openai client openai.OpenAI( base_urlhttp://localhost:8000/v1, api_keyEMPTY, ) response client.chat.completions.create( modelyour-model-name, messagesmessages, ) return response.choices[0].message.content这里的base_url和model需要根据你自己的模型服务调整。选“OpenAI 兼容接口”的原因是2026 年主流的本地模型服务、云端模型 API 基本都支持这套协议接入成本最低。6.2 Agent 记忆读写逻辑下面是完整的 Agent 对话类# 文件路径agent_with_memory.py class AgentWithMemory: def __init__(self, db_pathagent_memory.db): self.memory SimpleMemory(db_path) self.messages [] def chat(self, user_input): # 1. 检索相关历史记忆 relevant self.memory.search_memory(user_input) memory_text \n.join([f- {content} for content, _, _ in relevant]) # 2. 组装 system prompt system_prompt f你是 AI 助手以下是和你相关的用户长期记忆\n{memory_text}\n请结合记忆回答。 prompt_messages [{role: system, content: system_prompt}] self.messages[-5:] [ {role: user, content: user_input} ] # 3. 调用模型 response call_model(prompt_messages) # 4. 保存本轮对话到消息列表 self.messages.append({role: user, content: user_input}) self.messages.append({role: assistant, content: response}) # 5. 写入长期记忆 self.memory.add_memory(f用户说{user_input}, memory_typelong_term) return response if __name__ __main__: agent AgentWithMemory(agent_demo.db) print(agent.chat(我的名字叫张三请记住。)) print(---) print(agent.chat(我叫什么名字))这段代码有几个设计点需要说明。第 1 步的search_memory用的是简单的LIKE关键词匹配。实际使用时关键词匹配非常脆弱因为用户表达同一个意思可能用完全不同的词语。后面我会讲到怎么升级为向量检索。第 2 步只把最近 5 条消息传给模型这是对短期记忆做滑动窗口。很多开源框架的默认做法类似并不需要把所有历史消息都传进去。第 5 步写入长期记忆时我偷懒直接存了“用户说xxx”。实际项目中你应当让模型先对用户输入做一次信息抽取只保存“用户名字是张三”“用户偏好表格输出”这样的结构化结论而不是把原始对话直接存库。这可以避免长期记忆变成流水账。6.3 运行验证执行python agent_with_memory.py预期输出类似我没有找到相关记忆。 --- 我记得你叫张三有什么可以帮你第一轮没有找到相关记忆因为数据库是空的。第一轮之后“用户说我的名字叫张三请记住。”被写入了 SQLite注意实际演示代码里我们存的是整句而不是提取后的结论。第二轮检索时因为LIKE %名字%命中了这行所以 system prompt 里包含了“张三”模拟模型据此返回了记忆中的信息。这个小 Demo 已经能说明整套链路记忆写入、历史检索、Prompt 注入、模型回复。如果你把call_model换成真实模型就得到了一个最简单的带长期记忆的 Agent。7. 实战三用 Redis 实现多 Agent 共享记忆单个 Agent 有记忆之后下一个问题很自然会出现多个 Agent 之间怎么共享记忆例如一个团队有负责数据分析的 Agent有负责报告生成的 Agent它们需要知道同一个项目的背景和结论。如果各自用本地 SQLite信息就无法互通。Redis 是目前最常用的共享记忆中间件。它速度快支持键过期适合做短期共享状态也适合做多个 Agent 之间的消息总线。下面用一个最小示例演示怎么把记忆写入 Redis 并读取。# 文件路径shared_memory_demo.py import redis r redis.Redis(hostlocalhost, port6379, db0) # Agent A 写入共享记忆 r.set(memory:user_pref, 用户喜欢简洁回答结论优先) # Agent B 读取共享记忆 pref r.get(memory:user_pref) print(pref.decode(utf-8) if pref else 暂无共享记忆)Redis 可以当作一个简单的键值记忆库但如果你要按语义检索就不能只靠 key。更合理的做法是把 Redis 当作短期共享状态的存储把向量数据库或者关系型数据库当作长期记忆的主存储Redis 存任务状态、会话锁、最近 N 轮对话等热数据。多名开发者在同一个项目里使用共享记忆时还要注意命名空间。比如所有 key 都加上用户 ID 或团队 ID 前缀# 文件路径shared_memory_demo.py user_id user_10001 r.set(fmemory:{user_id}:pref, 用户喜欢表格输出)这样做可以避免不同用户、不同项目之间的记忆互相污染。生产环境还要给 Redis 设置密码并遵循最小权限原则不要随意开放公网访问。8. 进阶向量检索与长期记忆的工程选型当记忆量增长到一定规模LIKE关键词检索就远远不够了。例如用户说“我上次问过怎么部署网关”但记忆里只存了“Nginx 配置”关键词匹配可能搜不出来。这时需要做语义检索。语义检索的大致流程是先把记忆文本做向量化处理得到 embedding 向量把向量存入向量数据库查询时把用户问题也转成向量然后找出最相近的若干条记忆。你可以把它理解成从“查关键字”升级为“查意思”。在一个实际项目中长期记忆表的工程选型可以这样考虑方案适合场景优点缺点SQLite单机、少量记忆、快速验证零部署、简单可靠并发弱、难扩展Redis多 Agent 共享短期状态性能高、天然支持过期不适合复杂语义检索PostgreSQL pgvector中大型项目、需要事务和 SQL兼顾关系数据和向量需要额外部署扩展专用向量数据库海量语义检索检索能力强、水平扩展运维成本高向量检索的接入代码并不复杂大体框架是这样的# 文件路径vector_memory_demo.py # 伪代码实际 API 以你选择的向量库为准 def add_to_vector_memory(text): vector embed_model.encode(text) vector_db.insert({text: text, vector: vector}) def search_vector_memory(query, top_k5): query_vector embed_model.encode(query) results vector_db.search(query_vector, top_ktop_k) return [item[text] for item in results]关键是在写入记忆时不要只存原始文本而要存“经过提炼的结论”。如果你把几十轮对话原文都向量化存进去检索到的很可能是大量重复和无关信息。比较推荐的做法是每次对话结束后让模型用一句话总结“值得长期保存的关键信息”再存入记忆库。这里还要特别提醒不要一上来就上向量数据库。绝大多数项目在早期几百条记忆用 SQLite 的LIKE检索配合规则过滤就够用了。等用户量、记忆量、语义检索需求真正起来之后再迁移到向量方案成本反而更低。9. 常见问题与排查思路实践过程中你会遇到各种奇怪问题。我整理了一份常见的排查清单覆盖从记忆写入到模型回复的完整链路。问题现象可能原因排查方式解决方案第二轮对话仍然不记得用户信息长期记忆没有写入或写入失败检查数据库表是否有数据在 add_memory 后查询确认记忆有数据但模型回答时没用到检索结果为空或没有注入 Prompt打印 system prompt检查是否包含记忆内容优化检索关键词或改用向量检索对话越久请求越慢messages 列表无限增长检查请求 token 数量对短期记忆做滑动窗口多个 Agent 记忆互相串没有使用命名空间查看 Redis key/数据库记录在记忆 key 中增加用户维度和业务维度写入的记忆是重复的没有去重机制查看数据库中重复记录数量写入前先检索相似记忆或使用唯一约束用户要求删除记忆但还查得到没有清理接口查看删除逻辑是否真正执行实现按用户维度的删除/遗忘接口重启后记忆丢失配置了内存存储未持久化检查存储类型SQLite/Redis/数据库持久化排查时遵循一个原则先确认存储层有数据再确认检索层能查到数据最后确认 Prompt 层真的把数据给到了模型。三层链路哪一层断了都会表现为“失忆”。10. 最佳实践与工程建议到这里Agent 记忆的最小闭环已经实现了。但生产环境并不是“能跑就行”下面这些建议会直接影响长期稳定性。第一记忆要按用户维度隔离。无论是 SQLite 还是 Redis数据表或 key 中都要包含 user_id / project_id。否则把 A 用户的记忆检索给 B 用户不仅体验错误还可能造成隐私泄漏。这个风险在生产环境是最高优先级的问题。第二信息写入前必须经过提炼。不要直接把原始对话写入长期记忆而是让模型做一次“记忆抽取”只保存事实、偏好、结论。例如从“我叫张三我是运维工程师喜欢用 Python”这句话里抽取三条结构化记忆。原始日志可以另存但不要污染长期记忆。第三设计遗忘机制。用户会修改偏好旧记忆应当被更新或过期。比较简单的策略是每条记忆带 created_at 和 updated_at定期清理超过 180 天且未被命中的记录用户主动要求删除时必须提供删除接口并且删除后不能再被检索到。第四控制注入记忆的长度。检索到的记忆不是越多越好一般建议控制在 5 到 10 条总长度不超过几百 token。记忆过多会挤占模型对当前问题的注意力。第五做好观测与日志。每次记忆写入、检索命中、注入 Prompt都应该有日志。生产环境中如果用户投诉“Agent 忘了”你能回溯到某轮对话到底检索到了什么节省大量排查时间。第六测试要覆盖“遗忘”场景。很多团队只测“记忆有没有写入”却不测“用户改口之后怎么办”。例如用户先说“我喜欢简洁回答”后来说“以后请给我详细报告”记忆系统必须能更新旧偏好否则 Agent 会一直执行过期指令。11. 总结与后续学习方向Agent 记忆不是一个需要等到大模型能力进化才能解决的问题。它本质上是一个数据库加检索加 Prompt 注入的系统工程。短期记忆靠 messages 滑动窗口管理长期记忆靠外部存储和检索工作记忆靠 Agent 运行时状态对象。三个层次配合起来才是完整的记忆架构。建议你先不要急着写向量检索或多 Agent 协作而是把本文最简单的 SQLite 记忆模块跑通确认“写入、检索、注入”三件事都正常再去升级。如果你已经跑通了基础版本下一步可以深入这几个方向一是把LIKE替换成语义向量检索二是实现基于用户维度的记忆更新与遗忘接口三是用 Redis 或消息中间件打通多个 Agent 的共享记忆。真正值得警惕的是“什么都要记”的设计。记忆的价值不在于存储了多少而在于准确、及时地想起该想起的信息。先把一条完整的记忆链路跑通再考虑扩展你会少踩很多坑。