想象你是一家街角小餐馆的领班“老王”。一个周五晚上,门口排着长队,老王右手心捏着五张皱巴巴的点菜单——那是正在出菜的订单,必须立刻盯住;腰带挂着一个小笔记本,上面记着熟客的口味偏好,比如“张姐不吃香菜”“刘叔要少油”,这是攒了几周的经验总结;而店后的储物间里,还有一本翻旧了的菜谱,记录着每一道菜的完整做法和老王学到的烹饪心得。 老王为什么能同时干好这些活?因为他有三套“记忆系统”:手心的菜单是短期工作记忆,容量小却转得快,菜一出完就撕掉;腰间的笔记本是情景记忆,记录具体发生过的事;而储物间的菜谱是长期向量记忆,存放沉淀下来的结构化知识,按“语义”而非表面文字来查。AI Agent 的记忆系统设计,恰恰复刻了老王的这套本领——让 AI 既能专注当下对话,又能积累长期知识,还能从过往经历中学习。

岗位关联

对 AI 从业者而言,记忆系统是 Agent 从“一次性的问答机器”进化为“有成长能力的伙伴”的关键分水岭。掌握三层记忆架构,你就能设计出真正能持续对话、积累知识的生产级 AI 应用。

目录
  1. 可视化演示
  2. 三层记忆总览
  3. 短期工作记忆
  4. 长期向量记忆
  5. 情景记忆
  6. 存取与检索策略
  7. 上下文窗口管理
  8. 遗忘与整合机制
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示AI Agent的三层记忆架构:工作记忆(WM)处理当前对话上下文、向量记忆(VM)存储长期知识、情景记忆(EM)记录历史交互序列,层间通过检索和巩固机制联动。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Agent记忆系统 WM:短期工作记忆,存储当前对话上下文,容量有限但访问极快 VM:长期向量记忆,通过embedding检索相关历史知识 score = cos(E_query, E_mem) EM:情景记忆,记录完整交互序列,支持时间线回溯

三层记忆总览

老王能在周五晚高峰同时应对十几桌客人,靠的不是“记性好”这种玄学,而是一套明确的分工体系。手心的便签、腰间的客史笔记本、储物间的菜谱库,各司其职,互不干扰又相互配合。AI Agent 的记忆系统设计,正是这样一套三层架构:短期工作记忆、长期向量记忆、情景记忆。

在认知科学中,人类记忆本就分为感觉记忆、工作记忆和长期记忆。AI Agent 借鉴了这一分层思想:短期工作记忆负责当前正在处理的对话上下文,它由大语言模型的上下文窗口承载;长期向量记忆负责存储沉淀后的知识,以向量的形式保存在外部数据库中,按需检索调取;情景记忆负责记录具体发生过的事件序列,包括时间、场景、结果,为 Agent 提供“经验”层面的支撑。

这三层记忆并非孤立存在。短期记忆是“前台”,处理和呈现信息;长期记忆是“后台仓库”,提供知识支撑;情景记忆则是“经验簿”,告诉 Agent 类似的情况以前是怎么处理的。一个完整的记忆系统设计,核心目标就是让这三层高效协同:信息从短期流入长期、经验从情景提炼为知识,需要时再精准地检索回来。

理解了三层架构的分工,后面的每一节都会深入一层,最后串成完整的设计方案。就像老王先想清楚“便签、笔记本、菜谱各干什么”,再去琢磨每样东西怎么记、怎么查、怎么更新。

Agent Memory=Mshort(t)⊕Mlong(v)⊕Mepisodic(e)\text{Agent Memory} = M_{\text{short}}(t) \oplus M_{\text{long}}(\mathbf{v}) \oplus M_{\text{episodic}}(e)
公式表示 Agent 的记忆系统由三部分共同构成:随时间变化的短期工作记忆 M_short、基于向量 v 检索的长期记忆 M_long,以及基于事件 e 的情景记忆 M_episodic。⊕ 表示三者协同组合,而非简单相加。
  1. Agent Memory(Agent 记忆系统)这是我们要设计的整体架构,相当于老王“店里的全部信息管理方式”。
    Agent Memory=Mshort⊕Mlong⊕Mepisodic\text{Agent Memory} = M_{\text{short}} \oplus M_{\text{long}} \oplus M_{\text{episodic}}
  2. 短期工作记忆分量(M_short(t))带时间参数 t,说明它是动态变化的,就像老王手心便签上的订单不断更替。
    Mshort=Mshort(t)M_{\text{short}} = M_{\text{short}}(t)
  3. 长期向量记忆分量(M_long(v))带向量参数 v,说明它以向量形式存储,检索是靠语义向量的相似度匹配。
    Mlong=Mlong(v)M_{\text{long}} = M_{\text{long}}(\mathbf{v})
  4. 情景记忆分量(M_episodic(e))带事件参数 e,说明它按事件组织,每一段记忆对应一段具体经历。
    Mepisodic=Mepisodic(e)M_{\text{episodic}} = M_{\text{episodic}}(e)

短期工作记忆

忙起来的老王,手心最多能捏六七张便签,再多就握不住了。这就是短期工作记忆最核心的特征:容量有限,贴近当下。AI Agent 的短期工作记忆正是大模型的上下文窗口——模型一次能“看到”的全部 token 数量。

为什么叫“工作”记忆?因为它不是用来长久保存的,而是用来处理当前任务的。就像老王手里的订单便签,作用只是让他记住“3 号桌要的是红烧肉,5 号桌要的是清蒸鱼”,菜一出完便签就该扔掉了。在 Agent 中,当前对话轮次、系统提示词、工具调用的中间结果,都属于短期工作记忆的范畴。

Token 预算是管理短期记忆的核心手段。每个模型的上下文窗口有固定的 token 上限,比如 8K、32K 甚至 128K。Agent 要在有限的预算内,决定保留哪些信息、舍弃哪些信息。最常用的策略是滑动窗口:保持最近 N 轮对话为“全量记忆”,更早的内容则被截断或压缩。

设计短期工作记忆时,核心准则是“给最重要的内容分配最多的 token”。最近几轮的对话通常包含用户最新的意图,应当保留全量;早期的寒暄则可以被压缩为一句摘要。这样,Agent 既不会“失忆”,又不会让旧信息挤占新信息的空间。

Budget=Tsystem+Thistory+Tcurrent+Treserved≤Tmax\text{Budget} = T_{\text{system}} + T_{\text{history}} + T_{\text{current}} + T_{\text{reserved}} \leq T_{\text{max}}
公式说明上下文窗口的预算分配:系统提示词 T_system、历史对话 T_history、当前输入 T_current 各占一部分,还要留出 T_reserved 给模型生成输出,总和不能超过窗口上限 T_max。
  1. 总预算(Budget)一次推理中所有 token 的总和,如同老王手心里的全部便签数。
    Budget=Tsystem+Thistory+Tcurrent+Treserved\text{Budget} = T_{\text{system}} + T_{\text{history}} + T_{\text{current}} + T_{\text{reserved}}
  2. 系统提示词占用(T_system)Agent 的角色设定和行为规则所占的 token,如同便签上“本店规矩”那一栏。
    Tsystem=len(system_prompt)T_{\text{system}} = \text{len}(\text{system\_prompt})
  3. 历史对话占用(T_history)之前多轮对话占用的 token,如同已点但未上菜的订单记录。
    Thistory=∑i=1nlen(msgi)T_{\text{history}} = \sum_{i=1}^{n} \text{len}(\text{msg}_i)
  4. 输出保留(T_reserved)要给模型生成回复预留的空间,如同留出握拳的余地,不能捏太满。
    Treserved=Tmax−Tsystem−Thistory−TcurrentT_{\text{reserved}} = T_{\text{max}} - T_{\text{system}} - T_{\text{history}} - T_{\text{current}}

长期向量记忆

老王为什么能把菜谱记得那么牢?因为他不是一字一句背下来的,而是理解了“宫保鸡丁”和“鱼香肉丝”在调味逻辑上的相通之处——都讲究“小荔枝口”的酸甜微辣。这种按语义关联来组织知识的方式,正是长期向量记忆的精髓。

向量嵌入是把文本变成一组数字的过程。一个句子“宫保鸡丁是川菜名品”经过嵌入模型,会变成一个几百维的向量。语义相近的文本,向量距离就近;语义无关的文本,向量距离就远。老王脑子里的“调味逻辑图”就是天然嵌入——“糖醋味”附近簇拥着宫保鸡丁、糖醋里脊、鱼香茄子。

检索时,Agent 把当前的问题也转成向量,然后去向量数据库里做相似度搜索:找到与当前问题语义最接近的记忆片段。这比关键词搜索高明得多——用户问“有什么不辣又下饭的菜”,即使菜谱里从未出现“不辣”二字,系统也能通过语义相似度找到番茄炒蛋、麻婆豆腐的减辣变体版。

长期向量记忆的存储介质是向量数据库,如 FAISS、Pinecone、Milvus。它们专为高维向量的快速近邻搜索而优化,支持千万级数据的毫秒级检索。设计时还要考虑索引与分区:按业务领域建多个集合,给向量附加元数据标签(如来源、时间、权限),检索时先用元数据粗筛,再做向量精排,效率和准确率兼得。

sim(q,d)=q⋅d∥q∥⋅∥d∥=cos⁡(θ)\text{sim}(\mathbf{q}, \mathbf{d}) = \frac{\mathbf{q} \cdot \mathbf{d}}{\|\mathbf{q}\| \cdot \|\mathbf{d}\|} = \cos(\theta)
公式是余弦相似度,衡量查询向量 q 与记忆向量 d 之间的夹角余弦值。值越接近 1,表示两条记忆的语义越接近,就像“糖醋”和“酸甜”在老王脑中天然相连。
  1. 查询向量(q)用户当前问题经过嵌入模型转换成的向量,如同老王听到“来点开胃的”,脑子自动提取出“开胃”这个语义特征。
    q=Embedding(query)\mathbf{q} = \text{Embedding}(\text{query})
  2. 记忆向量(d)长期存储中某条记忆的向量表示,如同一道菜在老王脑中的“味道坐标”。
    d=Embedding(doc)\mathbf{d} = \text{Embedding}(\text{doc})
  3. 点积运算(q·d)两个向量逐维相乘再求和,比较它们在各维度上的一致性。
    q⋅d=∑i=1nqi×di\mathbf{q} \cdot \mathbf{d} = \sum_{i=1}^{n} q_i \times d_i
  4. 模长归一化(||q||·||d||)除以两个向量的长度,消除文本长短带来的偏差,只看方向是否一致。
    cos⁡(θ)=∑i=1nqidi∑qi2⋅∑di2\cos(\theta) = \frac{\sum_{i=1}^{n} q_i d_i}{\sqrt{\sum q_i^2} \cdot \sqrt{\sum d_i^2}}

情景记忆

老王腰间的客史笔记本,记的不是“张姐不吃香菜”这种静态偏好——那属于菜谱库该管的事。笔记本上写的是具体的事件:“上周四张姐带客户来吃饭,点了剁椒鱼头,专门叮嘱少放盐,最后多给了小费。”这就是情景记忆:对具体事件的记录,包含时间、人物、经过和结果。

为什么需要情景记忆?因为很多知识不是“事实”而是“经验”。事实性知识可以写进菜谱(长期向量记忆):“剁椒鱼头是湘菜,辣度四星。”但经验性知识必须来自事件:“上次张姐带客户来,她特意点了贵价菜,说明是商务宴请,应该推荐招牌菜品。”这种“当时发生了什么、结果如何”的叙事结构,恰恰是情景记忆的核心价值。

在设计上,情景记忆通常组织为事件序列,每条记录包含:时间戳、事件描述、参与者、情绪/满意度标签、结果反馈。它既不是简单的文本存储,也不是纯向量索引,而是一种“结构化 + 向量化”的混合体——事件文本被向量化以便语义检索,同时保留结构化字段以便按时间、按人物、按结果筛选。

情景记忆的最高价值在于经验反思。定期对近期事件进行总结,从具体事件中提炼通用规则——“连续三次午餐时段客人在意上菜速度,说明午市要优先推套餐”——这条规律从情景记忆上升为长期向量记忆中的知识。这模拟了人类“吃一堑长一智”的学习过程,让 Agent 越用越聪明。

E={e1,e2,…,en},ei=(ti,desci,tagsi,ri)E = \{ e_1, e_2, \ldots, e_n \}, \quad e_i = (t_i, \text{desc}_i, \text{tags}_i, r_i)
公式表示情景记忆是一个事件流 E,每个事件 e_i 包含时间戳 t_i、事件描述 desc_i、结构化标签 tags_i 和结果反馈 r_i。这相当于老王的客史笔记本上每一行记录包含的信息列。
  1. 事件流(E)全部情景记忆的有序集合,如同客史笔记本按时间先后排列的记录。
    E={e1,e2,…,en}E = \{ e_1, e_2, \ldots, e_n \}
  2. 时间戳(t_i)事件发生的时间,是情景记忆的纵向坐标,用来回答“什么时候发生的”。
    ti=timestamp(ei)t_i = \text{timestamp}(e_i)
  3. 事件描述(desc_i)事件的文本描述,记录“发生了什么”,会被向量化以支持语义检索。
    desci→embeddingvi\text{desc}_i \xrightarrow{\text{embedding}} \mathbf{v}_i
  4. 结果反馈(r_i)事件的结果或用户反馈,如满意度评分、任务是否成功,是后续反思的原料。
    ri=outcome(ei)r_i = \text{outcome}(e_i)

存取与检索策略

老王每天打烊后有一套固定流程:先翻手心的便签,把有用的信息抄进客史笔记本;再从笔记本里挑出重复出现的规律,提炼后更新菜谱;第二天开店前,根据今天要接待的客人类型,提前从菜谱里调出相关菜品知识。这套流程,就是记忆系统的写入、整合、读取策略。

写入流程要解决“什么值得记”的问题。不是所有对话都值得存入长期记忆——用户随口说的“今天天气不错”过眼即忘,但“我是项目经理,下周要组织评审会”就是重要信息。写入策略通常包含:重要性判断(情感强度、任务相关性)、信息抽取(提取实体、用户偏好、任务状态)、结构化存储(转为向量 + 元数据入库)。

读取流程的核心是“在合适的时机调出合适的记忆”。读取发生于每次对话之前或之中:Agent 先接收当前用户输入,生成查询向量,同时构造元数据过滤条件,从向量数据库和事件存储中检索候选记忆,经过排序筛选后,将最相关的记忆拼接进上下文窗口。

好的检索策略讲究“漏斗式过滤”:第一层用元数据(时间范围、领域标签、权限)快速排除,第二层用向量相似度粗筛出 Top 100,第三层用上述加权公式精排取 Top 5-10。这样既保证响应速度,又保证召回质量。老王的经验也如此:先想“今天都是些什么客人”,再想“他们以前爱点什么”,最后才决定推荐什么。

Retrieval(q)=TopK(α⋅sim(q,d)+β⋅recency(d)+γ⋅importance(d))\text{Retrieval}(q) = \text{TopK}\left( \alpha \cdot \text{sim}(\mathbf{q}, \mathbf{d}) + \beta \cdot \text{recency}(d) + \gamma \cdot \text{importance}(d) \right)
公式是混合检索的评分公式:候选记忆的最终得分由三部分加权合成——与查询的语义相似度 sim、时间近因 recency、记忆自身的重要性 importance。加权求和后取 TopK 条返回。
  1. 语义相似度(sim(q,d))查询与记忆向量的余弦相似度,是最主要的得分来源,如同“这道菜像不像客人要的口味”。
    sim(q,d)=cos⁡(q,d)\text{sim}(\mathbf{q}, \mathbf{d}) = \cos(\mathbf{q}, \mathbf{d})
  2. 时间近因(recency(d))越近的记忆权重越高。如同老王优先参考最近几条客史,三年前的记录仅供参考。
    recency(d)=e−λ(tnow−td)\text{recency}(d) = e^{-\lambda (t_{\text{now}} - t_d)}
  3. 重要性权重(importance(d))每条记忆维护一个重要性分,重要信息(如用户身份)永远优先于闲聊内容。
    score(d)=αsin⁡(⋅)+β⋅rec+γ⋅imp\text{score}(d) = \alpha \sin(\cdot) + \beta \cdot \text{rec} + \gamma \cdot \text{imp}
  4. TopK 截断按综合分数降序排列,只取前 K 条,防止无关记忆污染上下文。
    Retrieval(q)={d1,d2,…,dK}\text{Retrieval}(q) = \{ d_1, d_2, \ldots, d_K \}

上下文窗口管理

老王的便签在高峰期会不够用。他的解决办法是:字写小一点(压缩)、只记关键的菜名和桌号(筛选)、把已上菜的单子快速撕掉(淘汰)。上下文窗口管理,就是这“小、筛、撕”三招的工程化实现。

Token 分配策略是窗口管理的第一招。给定一个 32K 的上下文窗口,合理的分配可能是:系统提示词 4K,检索到的记忆 8K,历史对话 12K,当前输入 + 预留输出 8K。Agent 需要按照任务的复杂度动态调整这个比例——执行代码时多给工具调用留空间,做长文档分析时多给文档内容留空间。

摘要压缩是第二招。当历史对话超过预算时,不再简单截断,而是用大模型把早期对话压缩为一两句摘要:“用户在开头询问了项目背景,随后在讨论技术选型时倾向于 Python 栈。”这样既保留了高层次的语义信息,又大幅节省了 token。

重要性评分是第三招。给每条历史消息打一个重要性分:用户的明确指令 > 用户提供的背景信息 > 模型自己的生成内容 > 寒暄客套。淘汰时优先丢弃低分内容,保留高分内容。这比“最早进的先出”的先进先出策略更智能,因为最早的对话有时恰恰是最重要的——比如用户一开始就说了“我是财务,对技术不熟”。

动态拼接是窗口管理的最终执行:每当新消息到来,Agent 重新计算所有候选内容的权重,排序、截断、拼接,组装出最终的 prompt 发送给模型。整个过程像老王的便签整理仪式——高峰期每几十秒就发生一次,但每次都保持“最重要的信息永远在手边”的状态。

Weight(mi)=wtype(mi)×wrecency(i)×wrelevance(mi,u)\text{Weight}(m_i) = w_{\text{type}}(m_i) \times w_{\text{recency}}(i) \times w_{\text{relevance}}(m_i, u)
公式表示每条消息 m_i 在窗口中的保留权重等于三重因素的乘积:消息类型权重(指令 > 背景 > 寒暄)、时间远近权重(越近越高)、与当前用户意图的相关性权重。乘积越小,越优先被淘汰。
  1. 消息类型权重(w_type(m_i))不同类型的消息预设不同的基础权重。用户指令是 1.0,闲聊只有 0.2。
    wtype∈{1.0,0.6,0.2}w_{\text{type}} \in \{ 1.0, 0.6, 0.2 \}
  2. 时间衰减(w_recency(i))位置越靠后的消息权重越大,因为通常更接近当前意图。
    wrecency(i)=inw_{\text{recency}}(i) = \frac{i}{n}
  3. 相关性(w_relevance(m_i,u))计算消息与当前用户问题的语义相似度,与当前话题无关的旧消息优先级最低。
    wrelevance=sim(mi,u)w_{\text{relevance}} = \text{sim}(\mathbf{m}_i, \mathbf{u})
  4. 三因子乘积三项权重相乘得到综合保留分,按分数从低到高依次淘汰,直到满足 token 预算。
    drop order =argsort(Weight(mi))\text{drop order } = \text{argsort}(\text{Weight}(m_i))

遗忘与整合机制

老王的客史笔记本并不是无限厚的。每年年底他会换一个新本子,把旧本子上的信息重新誊抄一遍:重要的往新本子抄,次要的浓缩成几句摘要,没用的直接丢掉。这就是遗忘与整合——记忆系统不能只增不减,否则存储成本膨胀、检索噪声增大,最终拖垮整个系统。

遗忘曲线是人类记忆研究的重要发现:信息遗忘的速度随时间递减,刚学完忘得最快,越往后忘得越慢。AI Agent 的遗忘机制可以模拟这一曲线:记忆的权重随时间指数衰减,距当前时间越久远的记忆,在检索中的得分越低,最终被归档或删除。

冷热数据归档是工程上的落地手段:近期高频访问的记忆属于“热数据”,存放在快速存储中;长期未被访问的记忆属于“冷数据”,迁移到廉价存储或压缩存储中。当冷数据在更长时间内仍未被访问、且重要度低于阈值,就彻底删除。这和“老王的笔记本誊抄”在本质上是一致的——重要的留下,次要的浓缩,无用的丢弃。

记忆整合是遗忘的正面镜像。每隔一定时间或事件数,Agent 对近期积累的记忆做一次“复盘”:把支持同一结论的多个具体事件,合并为一条抽象知识;把过时的、互相矛盾的记忆做冲突消解;把冗长的历史记录压缩为摘要。经过整合,记忆中“知识”的比例提升,“琐事”的比例下降,系统在存储开销不变的情况下变得更聪明。这就像老王每年誊抄笔记本时,会突然悟出“原来下雨天客人更爱点热汤”这样的规律——这正是整合提炼的力量。

P(recall∣Δt)=P0×e−Δtτ×S(d)P(\text{recall} \mid \Delta t) = P_0 \times e^{-\frac{\Delta t}{\tau}} \times S(d)
公式表示记忆被成功回忆的概率随三个因素变化:初始记忆强度 P0、时间间隔 Δt 的指数衰减(遗忘曲线)、记忆稳定性系数 S(d)。S(d) 越大说明这条记忆越重要/越常被强化,衰减越慢。
  1. 初始强度(P0)记忆刚写入时的强度,写入时越重要、越深刻,P0 越大。
    P0=importance_score(memory)P_0 = \text{importance\_score}(\text{memory})
  2. 时间指数衰减Δ 时间间隔越久,被回忆的概率按指数下降。τ 是衰减常数,控制遗忘速度。
    e−Δtτ→Δt→∞0e^{-\frac{\Delta t}{\tau}} \xrightarrow{\Delta t \to \infty} 0
  3. 稳定性系数(S(d))经过多次强化(被检索到、被引用)的记忆,衰减更慢。如同老王反复开张时提到的熟客口味,记得格外牢。
    S(d)=1+k×hit_count(d)S(d) = 1 + k \times \text{hit\_count}(d)
  4. 检索概率综合三项乘在一起,决定了这条记忆在检索排序中的基础分。定期给记忆“加热”(命中次数 +1)可以对抗遗忘。
    Precall=P0⋅e−Δt/τ⋅S(d)P_{\text{recall}} = P_0 \cdot e^{-\Delta t / \tau} \cdot S(d)

AI 应用场景

场景一:智能客服助手

阶段:记忆写入与检索

解决的问题:传统客服机器人每次对话都“从零开始”,用户换个说法问同样的问题,它就不认识了。更糟糕的是,用户上一轮刚说过“我是会员,卡号 8888”,下一轮就忘了。通过三层记忆系统,Agent 将用户身份、历史工单存入长期向量记忆,将最近几轮交互存入短期工作记忆,将“上次投诉处理过程”存入情景记忆——当用户再次来访时,Agent 能在 0.5 秒内调出全部相关上下文,实现“老客户归来”的连贯服务体验。

具体案例:某电商平台客服接入三层记忆架构后,用户在首轮说“我上周买的手机壳裂了”,Agent 从情景记忆检索到上周的订单事件,从向量记忆调出该用户的售后政策,从短期记忆保留当前会话意图,直接生成包含订单号、补偿方案的完整回复,客户满意度提升了 37%。

场景二:个人知识管理助手

阶段:记忆整合与上下文管理

解决的问题:个人知识库助手需要处理用户持续几个月的文档上传和问答。如果不做记忆分层,所有文档都塞进上下文窗口,很快 token 爆炸。采用三层记忆设计后,文档先摘要存入向量记忆,用户的问答历史攒成情景记忆,近期高频的话题保留为短期工作记忆。

具体案例:一位研究生使用 AI 助手管理文献。实验阶段 Agent 记住了他关注的三个研究方向;写论文时,Agent 从向量记忆中检索相关文献,从情景记忆中调出三个月前导师提的修改意见,配合短期记忆中的当前写作进度,自动生成“按导师意见修改第二章”的方案。

场景三:自动化研究助手

阶段:情景记忆与经验反思

解决的问题:研究型 Agent 在执行多步骤任务(如“爬取竞品数据并生成分析报告”)时,经常在同类环节反复失败。通过情景记忆记录每次执行的事件序列和结果,Agent 可以总结出“步骤 3 的 XPath 选择器经常失效,需要加一层重试逻辑”的经验,并在下次执行前自动加载。

具体案例:某量化团队的 AI 研究员在每天凌晨自动执行数据采集任务。情景记忆记录了连续三天的失败模式,整合机制提炼出“数据源每周三凌晨维护,需切换到备份接口”的知识。第四天起,Agent 自动绕开维护时段,任务成功率从 68% 提升到 99%。

Python 演示

python92 行
import mathimport timefrom collections import deque  def simple_vector(text):    """将文本转为一个简易向量:按字符出现频率统计。"""    vec = [0.0] * 32    for ch in text.lower():        if ch.isalpha():            vec[ord(ch) % 32] += 1.0    norm = math.sqrt(sum(v * v for v in vec)) or 1.0    return [v / norm for v in vec]  def cosine_sim(v1, v2):    """计算两个向量的余弦相似度。"""    return sum(a * b for a, b in zip(v1, v2))  class MemorySystem:    """三层记忆系统:短期工作记忆 + 长期向量记忆 + 情景记忆。"""     def __init__(self, window_size=4):        self.window_size = window_size        self.short_term = deque(maxlen=window_size)   # 短期:滑动窗口        self.long_term_list = []                      # 长期:向量记忆库        self.long_term_text = []        self.episodic_list = []                       # 情景:事件流        self.episodic_x = 0     def add_short_term(self, text):        self.short_term.append(text)        if len(self.short_term) >= self.window_size:            self.consolidate_to_long_term()     def consolidate_to_long_term(self):        while self.short_term:            text = self.short_term.popleft()            vec = simple_vector(text)            self.long_term_list.append(vec)            self.long_term_text.append(text)     def add_episodic_event(self, desc, result):        self.episodic_x += 1        self.episodic_list.append({"time": time.time(), "desc": desc, "result": result, "id": self.episodic_x})     def retrieve_long_term(self, query, top_k=2):        q_vec = simple_vector(query)        scored = []        for idx, vec in enumerate(self.long_term_list):            score = cosine_sim(q_vec, vec) * (0.9 + 0.1 * math.exp(-0.01 * (len(self.long_term_list) - idx)))            scored.append((score, self.long_term_text[idx]))        scored.sort(key=lambda x: x[0], reverse=True)        return [text for _, text in scored[:top_k]]     def forget_old_episodes(self, max_events=10):        if len(self.episodic_list) > max_events:            self.episodic_list = self.episodic_list[-max_events:]            print("情景记忆中最早的事件已被归档遗忘")     def show_status(self):        print(f"短期记忆({len(self.short_term)}条): {list(self.short_term)}")        print(f"长期记忆({len(self.long_term_list)}条): {self.long_term_text[-3:]}")        print(f"情景记忆({len(self.episodic_list)}条): 最近事件 -> {self.episodic_list[-1] if self.episodic_list else '无'}")  def main():    mem = MemorySystem(window_size=3)    mem.add_short_term("用户是产品经理")    mem.add_short_term("项目名称为Alpha")    mem.add_short_term("用户偏好Python技术栈")    mem.add_short_term("用户需要每周一汇报进度")     mem.add_episodic_event("用户上周一说Alpha进展顺利", "用户满意度高")    mem.add_episodic_event("用户周三反馈文档缺失", "已补充文档")     print("=== 短期记忆被挤满,自动整合到长期记忆 ===")    mem.show_status()     query = "客户用什么语言"    print(f"\n=== 查询: {query} ===")    results = mem.retrieve_long_term(query, top_k=2)    print("检索到长期记忆:", results)     mem.forget_old_episodes(max_events=10)    print("\n=== 遗忘机制检查 ===")    mem.show_status()  if __name__ == "__main__":    main()
目的:演示三层记忆系统的核心机制——短期记忆的滑动窗口与自动整合写入长期记忆、基于向量相似度的语义检索、情景记忆的事件记录与遗忘归档。
  1. self.short_term = deque(maxlen=window_size)使用 deque 限制长度的方式实现短期记忆的“滑动窗口”,新消息进入、旧消息自动挤出,对应老王手心便签的替换逻辑。
  2. if len(self.short_term) >= self.window_size:当短期记忆达到容量上限时触发整合,模拟“短期信息固化到长期记忆”的过程。
  3. self.long_term_list.append(vec)将文本转为向量后存入长期记忆库,向量化是语义检索的基础。
  4. cosine_sim(q_vec, vec)计算查询向量与每条长期记忆的余弦相似度,实现“语义检索”而非“关键词匹配”。
  5. scored.append((score, ...))将每个记忆片段与当前查询的相关性打分并保存,后续按分数排序取 TopK。
  6. math.exp(-0.01 * ...)时间近因加权,越晚写入的长期记忆获得微小的加成,模拟近期记忆更易被回忆。
  7. self.episodic_list.append({"time": time.time(), ...})以事件为单位记录情景记忆,保存时间戳、描述和结果反馈。
  8. forget_old_episodes(max_events=10)当事件数超过上限时丢弃最早的事件,实现“遗忘机制”对存储的兜底控制。

常见误区

误区给模型的上下文窗口设大一点,比如 128K token,Agent 的“记忆力”不就解决了吗?多轮对话都给全量历史不就行了?

正解上下文窗口只是短期工作记忆的载体,它有三个致命限制:一是 token 成本随对话长度线性增长;二是模型对超长上下文的注意力会稀释(即“大海捞针”难题),中间内容容易被忽略;三是它无法跨会话保留——新会话从零开始。真正的记忆系统必须包含外部存储(向量库 + 事件库),让信息超过窗口容量后仍能按需找回。

为何常见:大模型的上下文窗口越来越大,厂商宣传时也强调“能处理长文档”,导致开发者误以为窗口容量就等于记忆能力。但窗口是“工作台”不是“仓库”,工作台再大,下班后还是要清空的。

误区只要搭一个向量数据库,把所有历史对话都存进去,每次查询做向量相似度搜索,就是完美的长期记忆了。

正解向量检索擅长“语义相近”的内容召回,但它的缺点是:对精确事实和数字的匹配不可靠(“用户卡号 8888”和“用户卡号 8889”的向量可能很接近);无法表达事件的时间先后关系;检索质量高度依赖嵌入模型的表达能力和 chunk 切分策略。因此生产系统需要“向量检索 + 元数据过滤 + 重排序”的混合方案,情景记忆则需要单独的结构化存储。

为何常见:向量数据库近年来是技术热点,RAG(检索增强生成)架构深入人心,很容易让人把“记忆 = 向量检索”画上等号。

误区所有历史信息都是有用的,统统存起来,总比“丢失”好。删除记忆意味着丢失信息,这是不可接受的。

正解没有遗忘的记忆系统会劣化。存储成本膨胀只是表象,更严重的是检索噪声增加——与当前任务无关的旧记忆被检索出来,污染上下文,导致模型输出质量下降。遗忘不是“删除信息”,而是“管理信息生命周期”:重要信息通过整合提炼升级为知识,冷数据归档降级,无用细节彻底清理。

为何常见:直觉上我们觉得“记得越多越好”,但人类的大脑尚且需要睡眠来清理垃圾突触,Agent 的记忆同样需要“整理”。设计师把遗忘看作失败,其实是没认识到遗忘是系统健康的必要环节。

误区短期工作记忆管当前对话,长期向量记忆管历史知识,两条线互不干涉,各存各的。

正解三层记忆是深度协同的:短期记忆的内容通过“整合机制”固化写入长期记忆;长期记忆通过检索被召回后注入短期窗口;情景记忆经过反思提炼升级为长期知识。一次完整的“记忆活动”通常跨越三层——用户说了一句话(短期)→ 触发检索旧知识(长期)→ 结合过往类似事件(情景)→ 生成回答 → 将新信息写回长期记忆。设计时必须打通三层之间的流转管道。

为何常见:分层架构的图示通常把三层画成三个独立盒子,给人“各管各”的错觉。实际上架构图中还应该有箭头——向上的写入、向下的检索、横向的联动,这些流转才是设计精髓。

面试题

Q1. Agent 的三层记忆架构中,短期工作记忆最核心的载体是什么?

单选题 · easy

  • A.向量数据库中的嵌入向量
  • B.大语言模型的上下文窗口← 正确答案
  • C.磁盘上的日志文件
  • D.外部知识图谱

答案:B。短期工作记忆对应的是当前对话中模型“能看到”的全部内容,即上下文窗口。向量数据库属于长期记忆的载体,日志文件只是持久化记录,知识图谱与短期记忆无直接关系,就像老王手心的便签是当下订单的唯一载体。

Q2. 长期向量记忆的检索方式基于什么原理?

单选题 · easy

  • A.字符串精确匹配
  • B.正则表达式匹配
  • C.语义向量相似度← 正确答案
  • D.随机抽样

答案:C。长期向量记忆将文本编码为向量,检索时计算查询向量与记忆向量的余弦相似度,按语义而非字面匹配。字符串精确匹配是传统数据库的等值查询,无法理解“开胃的菜”和“酸辣口”之间的语义关联,老王正是靠“语义图谱”而非死记菜名来联想推荐。

Q3. 关于滑动窗口策略在短期记忆中的作用,以下说法正确的是?

单选题 · mid

  • A.将对话历史全部保留以最大化信息
  • B.保留最近的 N 轮对话,丢弃或压缩更早内容← 正确答案
  • C.只保留系统提示词
  • D.将对话历史随机采样后保留

答案:B。滑动窗口策略维持最近 N 轮对话为全量内容,超出窗口的部分被截断或摘要化。这是 token 预算管理的直接体现——窗口有上限,只能保留最贴近当前意图的内容。全部保留会超出预算,随机采样会丢失关键上下文。

Q4. 在混合检索评分公式中,以下哪项不属于常见的加权因素?

单选题 · mid

  • A.语义相似度
  • B.时间近因
  • C.记忆的重要性
  • D.记忆存储的物理硬盘品牌← 正确答案

答案:D。混合检索的评分公式通常综合语义相似度(内容像不像)、时间近因(够不够新)、重要性(重不重要)三个因素,部分系统还引入多样性惩罚。存储硬盘品牌属于硬件细节,不影响检索逻辑,就像老王推荐菜品不会考虑菜谱纸的产地。

Q5. 情景记忆与长期向量记忆的关键区别是什么?

单选题 · mid

  • A.情景记忆存文本,向量记忆存图片
  • B.情景记忆记录带有时间和结果的事件序列,向量记忆存储抽象知识← 正确答案
  • C.情景记忆容量更大
  • D.两者没有区别

答案:B。情景记忆的本质是“经历”,以事件为单位,包含时间戳、经过和结果,关注叙事结构;长期向量记忆的本质是“知识”,以向量为单位,关注语义关联。老王“张姐上周四带客户点了贵菜”是情景记忆,“张姐有商务宴请需求”是提炼后的知识。

Q6. 以下哪些策略属于上下文窗口管理的有效手段?

多选题 · mid

  • A.用摘要压缩早期历史对话← 正确答案
  • B.按消息类型分配不同保留权重← 正确答案
  • C.无限扩大窗口长度
  • D.根据 token 预算动态拼接 prompt← 正确答案

答案:ABD。上下文窗口管理的核心手段包括摘要压缩(把早期对话浓缩成要点)、重要性评分(区分指令和寒暄)、动态拼接(按预算组装 prompt)。无限扩大窗口不是“管理手段”,它绕开了问题而非解决问题,成本和注意力稀释依然存在,就如同把便签换成无限大的桌子并不能让老王找单子更快。

Q7. 关于记忆遗忘机制的设计,以下说法正确的有?

多选题 · mid

  • A.遗忘可以帮助降低检索噪声← 正确答案
  • B.时间衰减因子让越旧的记忆权重越低← 正确答案
  • C.记忆整合可以把多个具体事件提炼为一条抽象知识← 正确答案
  • D.遗忘意味着永久删除所有相关数据,不可恢复

答案:ABC。遗忘机制的价值包括控制噪声、模拟时间衰减(旧记忆权重降低)、通过整合提炼新知识。但遗忘不等于暴力删除——工程实践中通常先归档降级、再逐步清理,冷数据可能被压缩保存。正如老王年底誊写笔记:旧信息不会马上一键清空,而是分级处理。

Q8. 在设计 Agent 记忆系统的写入策略时,以下哪些做法是合理的?

多选题 · hard

  • A.对重要度高的对话内容自动转存到长期向量记忆← 正确答案
  • B.从对话中抽取用户偏好、身份等结构化信息单独存储← 正确答案
  • C.所有对话内容不管重不重要,一律全量写入向量库
  • D.对用户明确表达的重要指令执行强制记忆← 正确答案

答案:ABD。合理的写入策略具备选择性:按重要度筛选(A)、抽取结构化信息(B)、识别用户的显式记忆指令(D)。全量写入(C)会导致向量库噪声膨胀、检索质量下降,相当于老王把每句闲聊都誊进菜谱,真正的知识反而被淹没了。

Q9. 在记忆整合过程中,“反思总结”环节的主要作用是?

单选题 · hard

  • A.压缩存储空间以减少成本
  • B.从多个情景事件中提炼通用规则并升级为长期知识← 正确答案
  • C.加快检索响应速度
  • D.删除所有冲突的记忆

答案:B。反思总结的核心价值是从具体事件中抽象规律——“连续三次午市顾客催单 → 午市应主推套餐”。这实现了情景记忆向长期知识的升级。压缩空间和加快检索是副产品,冲突消解只是整合的一个环节而非全部,删除所有冲突记忆更是粗暴做法。

Q10. Token 预算管理中,T_reserved 的设计需要考虑哪些因素?

多选题 · extreme

  • A.模型输出序列的最大长度← 正确答案
  • B.当前任务的复杂度与预期回复长度← 正确答案
  • C.是否涉及工具调用的参数序列化开销← 正确答案
  • D.用户的网络延迟

答案:ABC。T_reserved 是为模型生成输出预留的 token 空间,必须覆盖最大输出长度(A),根据任务复杂度调整(B),代码生成、工具调用等场景还需包含结构化输出如 JSON 的参数序列化开销(C)。网络延迟属于传输层问题,与 token 预算无关。预留空间不够,Agent 会被“腰斩”——像老王刚写一半菜单便签就没了。