大家好,我是安德斯(Anders)。作为 Oracle AI 数据库的开发者倡导者,我今天要探讨如何将智能体记忆视为一个系统问题来解决。我们将讨论如何把上下文转化为真正的记忆层,从而帮助智能体更高效地工作。当我们谈论智能体记忆时,我们指的是组成记忆检索、记忆形成以及支撑这些记忆的持久化存储。

目前大家可能都使用过不同的智能体,比如 Claude Code 或 Codex。我们看到它们在完成任务时反复阅读相同的文件,这是因为它们对过去发生的情况一无所知。上下文窗口并不是记忆;它是当前运行的输入,而非持久的经验。

假设我有一个智能体会话正在处理客户支持工单,它阅读了大量文档,运行了许多查询,复现了故障并找到了根本原因。这些工作综合出了有用的流程,非常有价值。但在会话结束时,这些信息就被丢弃了,因为没有持久化机制。

很久以后,另一个智能体接手类似任务时,必须重复所有相同的工作。它需要搜索更多文档、运行更多查询,这增加了出错和幻觉的机会,最终导致结果的准确性降低。只有当智能体的这些有用经验转化为受管状态时,记忆才真正开始发挥作用。

更大的上下文窗口也不是解决方案。我们会投入越来越多的令牌(tokens),会话变长,压缩发生,智能体获得的有用信号淹没在大量无关信息中。同样,备忘录(scratch pads)只是变通方法,比如建立大型文件层级、维基或提示词。

这些确实有帮助,但这并非受控的检索。文件在大型多租户环境中无法扩展。像 grep 这样的工具虽然对查找数据非常有用,但同样难以大规模扩展,且不具备复杂的混合检索能力。

我认为如果继续沿着在文件之上构建记忆层的逻辑走下去,我们最终是在自建数据库。既然这样,你为什么不直接使用数据库呢?本次演示旨在梳理我们从作为数据库供应商与客户合作中汲取的经验教训。

这些客户正在开发智能体记忆,利用解决实际问题并需要检索功能的智能体工作。我们看到现代智能体记忆系统正在收敛于一种模式,该模式实现了记忆形成、检索、演化和评估。

当我们形成记忆时,这些是提炼过的经验、结构化的事实,而非原始对话记录的简单转储。在检索记忆时,混合检索正成为一种主导方法。这是一种融合不同类型搜索的检索形式:向量相似度搜索、词汇搜索、基于关系对象的实体搜索、图遍历,以及对时间数据(如近期性和反馈)的不同信号分析。

这些系统还需要整合功能。因为可能会出现重复项,我们需要解决冲突,并且系统需要随时间演进,否则记忆会变得陈旧、无关且无用。记忆需要具备时效性元素:它是何时创建的?何时被访问的?有效期是多久?

某些记忆可能仅在特定的时间窗口内有效。这一切都需要纳入定期的反馈和评估中。如果我不衡量使用情况,不向记忆层发送反馈,整个系统将崩溃。

另一个重要部分是治理控制。秘密和个人信息在进入记忆层之前需要被脱敏。权限需要进行范围界定,限定于智能体、工作流、团队或用户。在多租户环境中这一点尤为重要。

我们需要适当的管理员审批和审查,并具备抑制陈旧或中毒数据的能力。当我们回顾记忆循环时:智能体会话执行工作,阅读文档、运行查询并综合有用数据。在该会话期间或之后,会创建一个事实记录。

我们通过脱敏、丰富信息并将其存储在持久化层中来记录该事实。当另一个具有相关上下文的会话到来时,它可以检索该事实并用于上下文卡片重建。这意味着利用先前任务中的事实现实来简化下一个任务的执行,从而减少后续智能体的工作量。

如果该智能体成功使用了这一事实,我们可以为该记忆添加反馈评分。这样我们就实现了随时间适应的过程:获取相关数据和新时效性,再次访问它并执行操作。

记忆由智能体运行时作为函数调用,因此需要读取、写入和存储层。你的智能体运行环境可以通过钩子(hooks)、MCP、技能或其他方法调用记忆层。

记忆层 API 暴露了读取、写入、反馈和管理接口,并与存储平台或数据库进行通信。我认为在此处选择多模型数据库特别有用,因为它们允许你在一个地方处理行、列、向量嵌入、全文搜索、关系实体、图、事件和事实。

这样你的记忆可以集中存储在一个地方,通过一个数据库查询连接即可实现各种混合搜索并返回数据。记忆长什么样?它将是类型化的,你可能在不同演示中见过这种模型或类似形式。

这一概念松散地源自人类记忆理论,可应用于智能体。我们有情景记忆(episodic memory),这是指智能体处理过的特定过去事件或对话片段。我们有语义记忆(semantic memory),涉及关于工作流、用户偏好和其他实体的具体事实。

我们有程序记忆(procedural memory),类似于我们执行特定任务或例程的方式,比如构建步骤。这些是可重用的规则,如果智能体重复类似工作,它们会反复调用这些信息。

我们还有工作状态(working state),类似于短期记忆:我们正在处理什么?这些时间数据可能仅在特定时间窗口内有效,我们可能会将其提升为其他类型的记忆。这有助于我们将数据分类到不同领域,并针对这些不同类型的记忆使用不同的搜索技术。

记忆的存储模式是什么样的?记忆是类型化对象加上查找路径。因此,我们的记忆对象将包含一个 ID

就像主键一样,它将包含文本内容、JSON 标签和文档数据。它还将拥有向量嵌入。我们会为该内容创建带有用于相似度搜索的向量索引的理想情况下,我们还应拥有文本索引以促进全文关键词搜索。这与向量搜索相结合。我们可以拥有指向不同边的图链接,记忆可以通过实体图谱相互关联。

因此,这个记忆与那个记忆相连,而那个记忆又与其他记忆相连。这是我们在搜索阶段可以检索回来的额外上下文信息。我们还可以拥有时间性事实,例如该记忆何时有效?我们上次使用它是什么时候?此外,审计事件也至关重要。谁创建了此记忆?他们用它做了什么?记录其使用方式及相关元数据,这些都应成为我们处理记忆时存储架构的一部分。

当我们创建记忆时,我们希望有意地构建它们。良好的记忆是非常有意图的产物。因此,我们需要决定生命周期、范围、不同的关系以及相关元数据。当代理运行时决定创建记忆时,我们应首先进行脱敏处理。脱敏作为第一步非常重要,因为在执行嵌入或丰富数据之前,我想剥离出个人身份信息(PII)。我不希望秘密或不相关的奇怪信息泄露到记忆层中,那是灾难的根源。因此我们先进行脱敏。

然后我们可以丰富该记忆的内容:它与什么相关?它的元数据是什么?我们可以对其应用范围限制。例如,处理此记忆的代理是谁?属于哪个团队或组织?这有助于将记忆归类到特定区域,避免在其他会话中出现与其他代理或工作流相关的混淆性记忆。接着我们可以进行嵌入操作以创建内容的向量,然后形成所谓的“片段”(episode)。

这些片段是生成记忆的转录文本切片。这对于溯源和提供额外上下文非常有益。任何组织特定的策略也可以在此应用,以满足您特定用例的需求。然后我们可以将其保存到存储层。在创建记忆时,单个记忆可以相当紧凑。我们将转录文本提炼为内容、元数据、嵌入及相关信息,同时我们也会创建这些片段。

我们通过代理转录文本进行过滤,找到适合成为片段的候选项,保存记忆记录并链接回原处。这可以通过关系数据库中的直连关系实现,也可以使用图结构。我特别喜欢使用图,因为它允许更广泛的搜索范围。当我们谈论记忆召回时,即如何记住某事?这是一个检索问题,也就是在存储层上的查询问题。

随着混合搜索作为上下文重建的主导方法逐渐兴起,这种形式的检索可以融合不同的搜索技术。我可以结合向量相似度搜索、全文关键词搜索、关系实体以及图遍历,还可以利用其他反馈信号(如记忆的重要性和有用性),从而比单一查询分支产生更全面的结果。如果仅做相似度搜索,只能根据所使用的嵌入模型获得最相似的结果,通常这还不够。

我们可以拥有所有这些不同的查询分支和不同类型的记忆,您可以决定采用哪些方式。例如对于事实类信息,您可能不需要相似度匹配,而只是想要通过精确 ID 进行匹配。我们可以将这些结果融合应用阈值、重新排序,最终得到带有评分证据的上下文卡片。例如,我们可以说该记忆在向量搜索中表现良好但在词汇搜索中稍低。

这就是记忆的溯源,即它来自哪里以及如何获取的,这也非常重要。在遍历混合搜索时,向量距离适用于语义相似的内容(如包含操作符),非常适合词汇搜索;图、表和时间数据等所有这些信息,我们将这些分支应用不同的权重。可以根据需要调整等待策略或参数组合,这是可以在混合搜索算法中调优的部分。

结果会合并为一个来自不同查询分支的总体得分,然后我们可以取总体结果的前 K 名(Top-K),例如告诉用户这是混合搜索算法得出的前三最佳结果。这就是在支持多种不同搜索方法的多模态数据库中实现混合搜索的大致流程,这种数据库能够从统一界面提供所有这些不同的搜索功能。

然而,记忆不仅仅是一个我们存入数据再取出的存储库。为了让记忆真正有用,它们需要随时间演变。同时我们也不希望每次都将所有数据强行塞入其中,否则会产生大量的记忆垃圾。这时我们可以通过整合和错误处理来闭合记忆循环。当项目曾经使用 NPM,后来决定切换到其他构建系统时,就会产生陈旧的记忆(stale memory)。

如果代理召回了那些与 NPM 相关的记忆,情况会变得棘手并可能导致错误操作。因此系统需要预期在召回过程中出现陈旧的事实或静默漂移(quiet drift)。范围错误也可能发生,即我们没有在正确的上下文中适当限定记忆的范围。这就像登录 ChatGPT 账户却看到别人的聊天记录一样,如果范围应用不当可能导致严重的数据泄露。

这种情况需要在写入和读取时都进行处理。“中毒记忆”是指不可信源在您的记忆层中植入持久化指令。这是最糟糕的情况,类似于发生了提示注入且缺乏适当的护栏、审查或控制措施导致恶意内容进入并窃取数据。因此务必通过正确的护栏和管理操作避免此类问题。

记忆冲突是指我拥有两条不同的记忆,一条说“我们要这样做任务”,另一条却说“实际上我们那样做”。因为它们都关于同一项任务,所以在检索时排名都会很高。因此您很可能在上下文卡片中遇到相同的冲突。当代理消费这些信息时会感到困惑,因为两条记忆都看似合理且相关。

你说:“我告诉你餐厅在右边,但它其实在左边。我不知道该怎么办。”因此,冲突解决中的检测审查至关重要,范围界定也同样重要。有时完成同一任务有不同的方法。随着记忆系统的增长,会出现过度召回和不相关的问题。如果我们只是把所有数据塞进去而不思考写入的内容,就会陷入过度召回的困境:大量微弱的匹配项会挤占上下文卡片的空间。这与超大上下文窗口的问题相同,我们试图塞入尽可能多的数据,结果只是令人困惑。不相关是指语义相近的记忆在混合搜索中排名很高,但实际上与任务无关,仅仅因为评分高而被选中。

这些问题属于管理和搜索算法调优的范畴。数据泄露是指奇怪、意外的数据进入记忆系统,这是“中毒记忆”较轻版本的表现。正确地对右侧的记忆记录进行丰富和提炼是解决泄露的方法。随着时间的推移,我们还会遇到静默漂移现象。记忆系统逐渐增长,可能在几千条记录时运行得非常好,但当达到五万、一百万或更多时,就会出现奇怪的结果,系统实际上无法正常工作。因此,应用适当的对策至关重要:写入前的缩减、范围检查审查、生命周期管理,以及最重要的反馈。

反馈是形成记忆闭环的关键。记忆质量需要可衡量,我们需要正确的检索能力,必须考虑到陈旧或有害的记忆,以及系统的下游有用性。这些信息需要反馈到排名和生命周期决策中。例如,如果智能体检索到一个候选记忆并使用了它却导致混乱崩溃,这种反馈必须传回。如果该记忆有害,其评分应降低;如果有用,则可能提升其优先级。因此,这不仅仅是一个存储库,记忆层需要记录哪些记忆是有帮助的、陈旧的、不相关的或有害的。

我们真正希望设计的是基于多模态存储平台的可衡量召回率和受控记忆形成。没有记忆,智能体更有可能重复相同的任务:一遍又一遍地重新创建、阅读同样的文件、运行同样的查询,浪费大量时间和令牌,速度更慢且更容易出错。它们会重复相同的错误。如果智能体不了解先前的技术,它就会重蹈覆辙;如果之前的做法是错误的,它将继续犯错。而在受控记忆的支持下,智能体可以从中断处继续工作,重用之前的成果,最终减少重复性失败。

这才是记录、检索、治理和演进的真正目标:我们希望提高成功率,做得更快、更便宜、更好。如果你倾向于动手实践,我推荐查看我们的 Python SDK for Agent Memory。该代码将引导你访问 GitHub 链接中的 Python Notebook,通过我们的 SDK 演示如何实现这一过程。该 SDK 基于数据库原语构建,我们在此讨论的所有内容都存在于数据库中。

此外,我们还拥有开发者中心。如果你是 AI 工程师、构建者或好奇现代多模态数据库如何融入 AI 开发,这里是查看示例、了解可能性并可能激发你用非常棒的数据库构建酷炫项目的地方。再次自我介绍,我是 Anders Swanson。如果你想聊天或与我联系,我会在 Oracle 展位等你。非常感谢大家,希望这对你们有帮助,祝大家在构建出色产品时一切顺利。谢谢。