大模型记忆实战
Day07大模型记忆实战——给你的 AI 装上三层记忆前言世界上最聪明的失忆症患者大模型就像一个智商 180 但只有 5 秒记忆的人。你跟他聊了一下午讲了你的项目叫星火计划、你团队有 8 个人、你的技术栈是 Python FastAPI。他听得很认真回答得很专业。你心想这个 AI 真懂我。然后你关掉窗口第二天重新打开。你好我叫什么我的项目是什么它一脸无辜抱歉我不知道你在说什么。这不是段子。这是 2026 年大模型的现状——GPT-4o 能写代码、能做数学证明但它记不住你昨天说过的一句话。上一篇 Day06 讲了 RAG解决了模型不知道你的私有数据。但 RAG 管的是外部知识——公司文档、产品手册。有一个问题它管不了模型记不住你说过什么。没有记忆的 AI 助手永远是个聪明的陌生人——每次对话都要从头自我介绍用户没有归属感产品没有粘性。这篇文章干四件事讲透三层记忆架构——短期、中期、长期各管什么讲 FIFO 机制怎么保证记忆实时性不被过时信息干扰给你一个可运行的三层记忆系统 demoPython直接跑工程落地的实战经验——踩过什么坑怎么避读完你会发现给大模型装记忆不是把所有对话存下来那么简单——它需要像人脑一样知道什么该记、什么该忘、什么该更新。PART 01三层记忆架构——短期、中期、长期先想一个问题人是怎么记忆的你跟同事聊了 30 分钟项目方案。聊完你记住了什么刚刚说的几句话——精确到原文他说 API 限流改成 200 次/分钟今天讨论的几个要点——大意记得原文忘了他提了个缓存方案大致是 Redis TTL这个同事是谁——结构化事实他叫老王负责后端偏好 Go这三种记忆对应大模型记忆系统的三层短期记忆最近 N 轮对话原样保留定义当前会话中最近 K 轮对话的原始内容。这就是模型的工作台——正在聊什么一目了然。实现最简单就是把最近的消息原封不动塞进 prompt。容量由上下文窗口决定。GPT-4o 是 128K tokens大约能装 128~256 轮对话。但实际项目中你不会用满——token 越多API 成本越高响应也越慢。实际设定一般保留最近 5~10 轮10~20 条消息大约 2K~5K tokens。够模型理解当前在聊什么就行。核心价值精确。原文一字不差不存在信息损失。中期记忆对话摘要压缩存储定义超出短期窗口的历史对话被 LLM 压缩为摘要后存储。当对话越来越长早期的消息被挤出短期窗口。直接丢掉太可惜——里面可能有重要信息。所以用一个折中方案让 LLM 把旧对话总结成一段摘要存起来。触发时机短期记忆满 K 轮时自动触发。把被挤出的对话交给 LLM 做摘要摘要结果存入中期记忆。核心价值省 token。一段 10 轮对话可能 5K tokens压缩成摘要只要 200~500 tokens。信息密度提升 10 倍以上。代价有细节损失。摘要保留了主旨但可能丢掉具体数字、精确措辞。这是可接受的折中——大多数场景下知道他提了个缓存方案就够了不需要记住原文。长期记忆用户画像持久存储定义从对话中提取的结构化事实——用户是谁、做什么、偏好什么。这是最高级的记忆。它不是存对话原文也不是存摘要而是提取出关于用户的关键信息像用户画像一样存着。提取方式每次对话结束后用 LLM 从对话中抽取关键事实姓名、职业、公司项目名、技术栈偏好、习惯喜欢用 Python、不喜欢 Java重要决策决定用 Redis 做缓存核心价值跨会话、不衰减。关掉窗口再打开模型依然认识你。这是让 AI 从工具变成伙伴的关键。三层对比总结维度短期记忆中期记忆长期记忆存什么最近 N 轮原文对话摘要用户特征/偏好容量5~10 轮数十条摘要数十条事实精确度100%原文80%主旨95%结构化生命周期会话内跨会话可更新跨会话持久token 消耗高原文中摘要低JSONPART 02FIFO 机制——保证记忆的实时性三层记忆搭好了但有个问题记忆不是越多越好。想象一下用户三个月前说我在做电商项目今天说我转做短视频了。如果你的长期记忆里还存着做电商模型会给出电商相关的建议——完全过时了。过时的记忆不是资产是噪音。这就是 FIFOFirst In, First Out的价值——让记忆系统保持新鲜及时淘汰过时信息。短期记忆严格 FIFO满了就丢短期记忆最简单——滑动窗口新消息进来旧消息挤出。消息流[msg1, msg2, msg3, ..., msg10, msg11, msg12] 窗口 K5保留最近 5 轮 10 条消息 → [msg3, msg4, ..., msg12] # msg1, msg2 被挤出被挤出的消息不是直接丢掉——它们会被送入中期记忆做摘要压缩。这样既控制了短期窗口的大小又不丢失历史信息。中期记忆合并 LRU旧摘要被新摘要替代中期记忆不是简单堆叠。同一个话题的多次摘要应该合并而不是追加。举个例子第 1 次摘要讨论了 API 限流方案决定用令牌桶算法第 2 次摘要同一个话题讨论了 API 限流方案的具体实现确定限流阈值 200 次/分钟这两条应该合并为API 限流方案令牌桶算法阈值 200 次/分钟。淘汰策略LRULeast Recently Used。如果一条摘要长期没被引用用户再也没提过相关话题它的优先级降低。当摘要数量超过上限时低优先级的先被清理。长期记忆Update不是 Append这是最容易踩坑的地方。长期记忆不是堆积信息而是更新画像。用户说我在做电商→ 长期记忆存{project: 电商}。三个月后用户说我转做短视频了→ 长期记忆应该更新为{project: 短视频}而不是追加成{project: 电商, 短视频}。关键区别Append追加所有历史事实堆在一起 → 过时信息干扰判断Update更新同一实体的最新状态覆盖旧状态 → 永远是最新画像# 错误做法追加 long_term_memory.append({key: project, value: 短视频}) # 结果[{key: project, value: 电商}, {key: project, value: 短视频}] # 正确做法更新 long_term_memory.update(project, 短视频) # 结果[{key: project, value: 短视频}]三层淘汰策略对比层策略触发条件处理方式短期严格 FIFO超出 K 轮挤出 → 送入中期做摘要中期LRU 合并同话题重复 / 超上限合并同类摘要清理低频长期Update 覆盖新事实与旧事实冲突用新值覆盖旧值PART 03一个可运行的三层记忆系统 demo理论讲完了下面给一个完整的、可以直接跑的三层记忆系统。 Day07 三层记忆系统完整 demo 短期记忆FIFO滑动窗口 中期记忆对话摘要 长期记忆用户画像 依赖pip install openai 环境变量OPENAI_API_KEY import os import json import time from openai import OpenAI client OpenAI(api_keyos.getenv(OPENAI_API_KEY)) # 短期记忆FIFO 滑动窗口 class ShortTermMemory: 短期记忆保留最近 K 轮对话原文 def __init__(self, max_rounds: int 5): self.messages: list[dict] [] self.max_messages max_rounds * 2 def add(self, role: str, content: str) - list[dict]: 添加消息返回被挤出的消息 self.messages.append({role: role, content: content}) evicted [] while len(self.messages) self.max_messages: evicted.append(self.messages.pop(0)) return evicted def get_context(self) - str: if not self.messages: return return \n.join(f{m[role]}: {m[content]} for m in self.messages) # 中期记忆对话摘要存储 class MidTermMemory: 中期记忆将被挤出的对话压缩为摘要 def __init__(self, max_summaries: int 20): self.summaries: list[dict] [] self.max_summaries max_summaries self.buffer: list[dict] [] def add_evicted(self, messages: list[dict]): self.buffer.extend(messages) if len(self.buffer) 4: self._summarize() def _summarize(self): if not self.buffer: return conversation \n.join(f{m[role]}: {m[content]} for m in self.buffer) prompt f请将以下对话总结为简洁摘要200字以内保留主题、关键结论、具体数字和名称\n{conversation}\n请输出摘要 resp client.chat.completions.create( modelgpt-4o-mini, messages[{role: user, content: prompt}], temperature0.3, ) self.summaries.append({ content: resp.choices[0].message.content.strip(), created_at: time.time(), access_count: 0, }) self.buffer [] if len(self.summaries) self.max_summaries: self.summaries.sort(keylambda s: s[access_count]) self.summaries self.summaries[-self.max_summaries:] def get_context(self) - str: if not self.summaries: return lines [] for s in self.summaries: s[access_count] 1 lines.append(f- {s[content]}) return [对话历史摘要]\n \n.join(lines) # 长期记忆用户画像 class LongTermMemory: 长期记忆提取并维护用户画像 def __init__(self): self.facts: dict[str, str] {} def extract_and_update(self, user_message: str): current_profile json.dumps(self.facts, ensure_asciiFalse) if self.facts else 空 prompt f从以下用户消息中提取需要长期记住的关键事实。 如果新事实与已有画像冲突输出 update 操作。如果没有新事实输出空 JSON。 当前画像{current_profile} 用户消息{user_message} 输出 JSON{{facts: {{key: value}}, updates: {{key: new_value}}, deletes: [key]}} 只输出 JSON resp client.chat.completions.create( modelgpt-4o-mini, messages[{role: user, content: prompt}], temperature0, ) try: result json.loads(resp.choices[0].message.content.strip()) for k, v in result.get(facts, {}).items(): self.facts[k] v for k, v in result.get(updates, {}).items(): self.facts[k] v for k in result.get(deletes, []): self.facts.pop(k, None) except (json.JSONDecodeError, KeyError): pass def get_context(self) - str: if not self.facts: return return f[用户画像]\n{json.dumps(self.facts, ensure_asciiFalse, indent2)} # 记忆管理器 class MemoryManager: def __init__(self, short_rounds: int 5): self.short_term ShortTermMemory(max_roundsshort_rounds) self.mid_term MidTermMemory() self.long_term LongTermMemory() def process(self, role: str, content: str): if role user: self.long_term.extract_and_update(content) evicted self.short_term.add(role, content) if evicted: self.mid_term.add_evicted(evicted) def build_prompt(self, new_message: str) - str: parts [] long_ctx self.long_term.get_context() if long_ctx: parts.append(long_ctx) mid_ctx self.mid_term.get_context() if mid_ctx: parts.append(mid_ctx) short_ctx self.short_term.get_context() if short_ctx: parts.append(f[最近对话]\n{short_ctx}) parts.append(fuser: {new_message}) return \n\n.join(parts)跑完你会看到这样的流转过程阶段短期记忆中期记忆长期记忆第 1 轮后1 轮原文空{name: 张明, project: 星火计划}填充 10 轮后最近 3 轮2~3 条摘要不变第 12 轮回忆命中 ✅摘要可参考name张明, project星火计划第 13 轮更新最新新增摘要project 更新为 短视频核心要点三层记忆各司其职——短期保证正在聊什么、中期保证之前聊过什么、长期保证用户是谁。FIFO 贯穿三层保证信息不过时。PART 04工程落地——记忆系统的实战经验demo 能跑通但真正上线会遇到很多坑。分享几个我在实战中踩过的。坑一事实提取不准确——把闲聊也存进了长期记忆最常见的问题。用户开玩笑说我是个外星人提取器就存了{identity: 外星人}。解法在提取 prompt 中明确约束EXTRACT_PROMPT 从用户消息中提取需要长期记住的事实。 规则 1. 只提取明确的、严肃的个人信息姓名、职业、项目、技术偏好 2. 忽略闲聊、玩笑、一次性问题、测试内容 3. 如果不确定是否值得记住不提取宁可漏掉不可错记 4. 如果新事实与旧事实冲突标记为 update关键是第三条——宁可漏掉不可错记。记忆污染比记忆缺失更影响体验。坑二摘要丢细节——关键数字被省略LLM 做摘要时经常省略具体数字。比如原文API 限流改成 200 次/分钟摘要变成讨论了 API 限流调整——关键数字丢了。解法在摘要 prompt 中强制要求保留实体——必须保留具体数字、人名、项目名、技术名称。坑三长期记忆更新冲突用户说我不喜欢 Python 了转 Go 了。你希望长期记忆从{language: Python}变成{language: Go}。解法在提取 prompt 中明确区分update覆盖旧值和append新增属性以及delete append否定旧信息时。与 RAG 整合统一检索架构Day06 讲的 RAG 是检索外部文档。长期记忆本质上也可以存入向量库——检索用户是谁和检索公司退货政策用的是同一套技术。RAG 和 Memory 共用一套向量基础设施运维成本更低。性能考量控制额外 LLM 调用三层记忆系统每条消息可能触发事实提取1 次 gpt-4o-mini 摘要压缩溢出时触发 回答生成主模型。额外成本大约主调用的 20%~30%。事实提取和摘要都用gpt-4o-mini便宜、快摘要不要每轮都触发积累到阈值再压缩长期记忆提取可以异步执行——不阻塞用户响应结尾记忆是 AI 从工具变伙伴的分水岭回头看这篇文章的核心三层记忆短期最近 N 轮原文→ 中期对话摘要→ 长期用户画像FIFO 流转短期满了挤出去做摘要摘要中提取事实更新画像——信息逐层沉淀不是堆积淘汰策略短期严格 FIFO、中期合并 LRU、长期 Update 覆盖——保持记忆新鲜为什么这套架构重要因为记忆是 AI 从工具变成伙伴的分水岭。一个没有记忆的 AI每次对话都像跟失忆的天才聊天——它很聪明但它不认识你。一个有三层记忆的 AI它知道你是谁、之前聊过什么、现在在讨论什么——这种感觉才叫我的 AI 助手。大模型最缺的不是算力是记忆——一个没有记忆的 AI永远是个聪明的陌生人。互动时间你的 AI 应用里记忆系统是怎么搭的三层都上了还是只用了短期踩过什么坑欢迎评论区聊聊。下一篇 Day08 预告大模型 MCP 实战——让大模型不只生成文本还能调用你的工具和服务。关注小刘檀木不错过每一篇。我是小刘檀木一个从二本摸爬滚打到上市公司 AI 负责人的普通人。关注我把 AI 学进简历。— END —小刘檀木 · 帮普通人把 AI 学进简历