每个生产级 AI Agent 都需要的三个记忆系统
大多数 AI agent 都会以同样的方式失败:它们在演示中表现完美,但在经历十次真实对话后就会分崩离析。那个上周二还帮用户配置账单集成的 agent,今天已经完全不记得那个用户是谁了。它再次询问对方的公司名称,然后是套餐层级,接着重新解释用户已经掌握的概念。体验从“有用的助手”降级为“健忘的聊天机器人”。
直觉反应是给问题增加更多上下文 —— 将对话历史塞进 prompt 并认为问题已解决。这种做法在达到一定规模前确实有效。在大规模场景下,全上下文方案的成本高得惊人,而且更麻烦的是,随着输入量的增长,性能会下降。研究表明,即使在模型宣称的限制范围内,LLM 的准确率也会随着上下文长度的增加而明显下降。100 万 token 的上下文窗口并不是一个记忆系统。
在生产环境中运行良好的 agent 将记忆视为头等架构关注点,而不是事后才考虑的事情。而那些做对的 agent 能够区分三种根本不同的持久化信息类型 —— 每种类型都有不同的存储模式、检索策略和衰减特性。
为什么三分法区分如此重要
认知科学早就认识到,人类的记忆并非铁板一块。情景记忆(Episodic memory)处理自传式事件(“我周二开了那个会”)。语义记忆(Semantic memory)处理通用知识(“巴黎是法国的首都”)。程序性记忆(Procedural memory)处理技能(“如何骑自行车”)。这些系统的运行方式不同,衰减方式不同,失败方式也不同。
AI agent 也能从同样的分类法中受益 —— 这并非哲学练习,而是因为每种记忆类型都直接对应一个不同的工程问题。
将所有持久化信息一视同仁是一个常见的错误。如果你将所有内容作为语义事实存储在知识图谱中,你就会丢失让过去交互变得有意义的时间上下文。如果你将所有内容作为情景对话日志存储,在大规模情况下检索会变得昂贵且充满噪音。如果你没有程序性层级,你的 agent 就永远学不会停止犯同样的错误。
情景记忆:发生了什么的日志
情景记忆存储特定交互及其完整的上下文:问了什么,回答了什么,调用了哪些工具,结果如何,以及这一切发生的时间。
这种记忆类型让 agent 感觉它认识你。当一个客服 agent 回想起用户在六周前打电话咨询过账单差异并已收到退款时,这就是情景记忆。当一个编码助手记得你明确偏好使用 async/await 而不是 promise 链,并且 你在三周前的一次会话中提到过这一点时,这就是情景记忆。
实现挑战有三方面。首先,情景记忆需要时间戳 —— 时间维度是承重的。“用户说他们正在评估我们的产品”在昨天说的,与在八个月前说的,其含义完全不同。其次,情景存储会无限制增长。如果没有刻意的修剪或总结,随着信噪比的下降,检索效果会随着时间的推移而变差。第三,单个情景需要能通过语义相似性(讨论了什么话题)和时间接近性(最近发生了什么)来访问。
生产环境的实现通常将用于语义检索的向量存储与时间元数据过滤器相结合。检索查询不只是“找到与此类似的记忆”,而是“找到与此类似的记忆,偏重于最近的记忆,排除任何早于相关性阈值的记忆”。
语义记忆:超越单次对话的知识
语义记忆包含从经验中提取的事实和知识,但不再与产生它们的特定情景相关联。它回答的是“我关于这个用户/领域/实体了解什么”,而不是“发生了什么”。
考虑这种合并在实践中是如何工作的。用户在一次会话中随口提到他们正在从 AWS 迁移到 GCP。这是一个情景事件。但“该用户的基础设施基于 GCP”这一事实变成了一个语义事实,它应该为未来的每一次响应提供信息 —— 它不需要周围的情景就能发挥作用。保持它的情景性意味着每次检索都必须拖着不必要的上下文。将其提升为语义记忆会使其更轻量、更持久。
Agent 系统中的语义记忆通常实现为图数据库或键值存储中的结构 化记录。图方法特别强大,因为它能捕捉关系:“用户 A 在公司 B 工作,该公司使用工具 C,而工具 C 与集成项 D 有已知的兼容性问题”。平面的键值存储无法表示这种关系结构。
难点在于语义“事实”可能会过时。用户会换工作,公司会更换技术栈,偏好也会演变。八个月前真实的事实现在可能具有严重的误导性。这就是许多生产实现加入置信度衰减机制的地方:语义记忆的权威性会降低,除非有新的情景证据来强化它们。如果六个月内没有任何交互触及某个事实,它在检索中的权重就会降低,或者被标记为需要重新验证。
程序性记忆:学习行之有效的方法
在当前的智能体架构中,程序性记忆(Procedural Memory)是三种记忆类型中利用率最低的一种,但对于需要随时间推移而不断改进的系统来说,它可能是最有价值的。
程序性记忆存储的是“如何做事”——具体而言,是在特定上下文、特定用户或领域中被证明有效的模式。它不是关于如何编写代码的通用知识,而是特定习得的偏好:例如,这位用户总是希望在他们请求的任何函数中包含单元测试;该组织的 API 网关拒绝超过 4KB 的负载,因此务必进行分页;该客户的数据架构在所有地方都使用 snake_case。
它与语义记忆(Semantic Memory)的区别虽然细微但至关重要。“用户偏好 Python”是语义记忆——这是一个关于用户的实时事实。而“在为该用户编写数据管道代码时,使用 Polars 而不是 Pandas,因为过去使用 Pandas 的回复被标记为无用”则是程序性记忆——这是一种关于“该做什么”的习得性启发式方法。
在人类认知中,程序性记忆是隐性且自动的。对于 AI 智能体,它必须被显性化且可检索。一些实现通过强化信号来实现这一点:当用户对某个回复给予好评时,生成该回复的方法就会被编码为一个程序。另一些实现则使用自省循环(self-critique loops),智能体会定期审查其交互历史并提取可泛化的模式。
这种收益是复合的:拥有维护良好的程序性记忆的智能体,其表现会随着使用而显著提升。这就是一个简单的工具与一个能够学习你工作流的助手之间的区别。
检索问题:平衡三种竞争信号
如果你无法在负载下准确地检索,那么拥有三个记忆库也无济于事。检索层是大多数生产系统失败的地方。
朴素的向量相似度搜索——将当前查询嵌入(embed),寻找最接近的存储记忆——对于小型存储库效果尚可。随着存储量增长到数千或数百万条记录,它产生的噪声会越来越多。相关的记忆会被主题相似但上下文无关的记忆所排挤。
有效的检索结合了三种独立的信号:
相关性(Relevance)——当前上下文与存储记忆之间的语义相似度,通过嵌入余弦相似度测量。这是基准。
新近度(Recency)——记忆创建或最后一次被访问的时间。通过指数衰减(exponential decay)实现:昨天的记忆比一年前的记忆更有可能发挥作用,即使那封一年前的记忆在语 义上更相似。每小时约 0.995 的衰减因子是一个合理的起点。
重要性(Importance)——记忆形成时的显著程度。一些实现使用 LLM 在写入时为重要性评分;另一些则从用户行为中推断重要性(用户发送了三次的信息比只发送一次的信息更重要)。
将这三个信号组合成一个加权的检索评分,其表现始终优于仅基于相似度的方法。挑战在于校准权重:过多的新近度偏好会导致智能体忘记重要的长期上下文;过少则会被过时的信息干扰。
关于“记忆三难困境”(Memory Trilemma)的研究提供了一个令人清醒的数据点:在最初的 30 到 150 次对话中,简单地将所有历史记录塞进上下文窗口可以达到 70-82% 的准确率。切换到基于检索的方法最初可能会使准确率下降到 30-45%。复杂的检索系统需要时间才能体现其复杂性的价值。请先构建全上下文基准,对其进行衡量,然后针对特定的失败模式采用针对性的记忆检索,而不是从第一天起就采用复杂的架构。
关于遗忘的问题
一个只增不减的记忆系统不是记忆系统,而是一个日志。生产环境中的智能体需要有原则的遗忘。
艾宾浩斯遗忘曲线模拟了人类在没有强化的情况下如何随时间遗忘信息,在智能体记忆中也有实际的对应物。未被访问的信息会衰减,经常被检索的信息则会得到加强。这反映了有用信息在实践中保持相关性的方式:用户的活跃偏好通过交互不断得到强化,而一年前完成的项目偏好则会自然褪色。
实施衰减并不意味着删除记忆。它意味着在检索评分中降低 它们的权重,直到它们降到某个阈值以下,实际上变得“不可见”——但如果特别请求,它们仍然可以被找回。这既保证了正确性(你始终可以查阅完整历史),又防止了陈旧信息污染当前的推理。
运营上的好处还延伸到了成本。智能衰减的记忆库保持在可控范围内。一个教育平台通过实施带衰减的分层记忆,将最近的和高重要性的记忆路由到热存储,同时归档旧记忆,从而将 Token 成本降低了 40%。
务实的架构建议
三个比具体工具更重要的务实决策:
按类型分离你的存储。 将情节性日志、语义事实和程序性模式保存在不同的存储库中,并采用不同的检索策略。将它们混合在单个向量数据库中会使检索变得更困难,并掩盖了你实际拥有的信息类型。
写入时间与读取时间同样重要。 大多数团队在设计记忆系统时都是读取优先。检索的质量完全取决于存储内容的质量。投资于提取管道,在写入时从原始对话日志中提取语义事实、分配重要性评分并标记时间上下文。
在构建复杂系统之前先构建评估体系。 在实施带有加权检索和衰减功能的多存储架构之前,先针对代表性对话建立一个基准准确率指标。“记忆三难困境”效应是真实存在的——复杂性并不自动意味着更好的结果。在添加下一个组件之前,先衡量每个组件的贡献。
