如何构建智能体记忆:知识存储在哪里?
智能体记忆的核心不是存储位置,而是区分产物(历史记录)与知识(当前真相),将知识视为基于产物的物化视图,并按缓存逻辑决定物化哪些知识——记住比重新发现更便宜的内

在本系列的第一篇文章中,我们将智能体的记忆拆解为四个部分:表示与存储、提取、检索和维护。如果你熟悉数据库,可以大致将它们类比为CRUD操作。知识是如何存储的?如何写入?如何再次找到?又如何保持最新?
这篇文章讨论的是第一个问题:智能体的知识实际上存放在哪里?
显而易见的答案是在数据库中。但这有点操之过急了。在决定把知识放在哪里之前,我们首先需要确定这些知识实际上是什么样子的。
记忆是什么样子的?
在存储这个说法背后,其实藏着两个独立的决策。第一个是表示:知识本身的形态。第二个是物理存储:承载知识的系统。
一段记忆可以是一段Markdown文本、一组事实、一个主题层级结构,或者一张连接实体与关系的图。其中任何一种都可以存放在文件、Postgres、向量数据库或更专门的系统中。这种区分很重要,因为存储相对容易替换,而你选择的表示方式决定了智能体如何理解并交互这些知识。
在光谱的最简单一端,记忆就是纯文本。比如AGENTS.md、CLAUDE.md、之前会话的转录,或提取出的事实列表。在此基础上,你可以开始添加关系:产品有功能,GitHub issue由拉取请求关闭,事实属于某个主题。这些关系可以形成简单的树状结构,或更丰富的图结构。
在实践中,大多数记忆系统最终会结合使用这些方法。没有一种表示方式能在所有场景下都胜出。
文件能带来的惊喜远超想象
存放代理记忆的方式多种多样。你可以将少量信息直接注入上下文窗口,将数据嵌入向量数据库并通过语义搜索检索,在图形数据库中建立关系,或者赋予代理SQLite或Postgres权限,让它用SQL查询自己的记忆。
或者,你也可以把知识放在一个目录里。
最后这个选项听起来简单得几乎不可信,但它已成为代理系统中最实用的模式之一。第一代LLM应用将检索等同于RAG:嵌入一切,存入向量数据库,按语义相似度搜索。
随后,编码代理在bash操作上变得异常娴熟。
它们能浏览目录、运行grep和rg、跟随链接、检查文件名,并并行读取多个文件。文件系统不仅是存储信息的便捷之所,更是当今编码代理已极为熟悉的接口。
因此,如果你从零开始构建代理记忆,文件往往是一个很好的起点。但更棘手的问题不在于文件存放何处,而在于你往里面放什么内容。
区分事实与真相
在Dosu,我们发现将记忆划分为两大类别颇为有用:产物与知识。
产物是所发生事件的记录。一条Slack线程即是一个产物。拉取请求、Linear工单、会议记录、设计文档或代理会话追踪同样如此。它们之所以有价值,在于其高保真度并保留了原始背景,但未必代表真相。
一份设计文档可能描绘了从未实现的架构。一段Slack对话可能解释了一年前某事物的运作方式。一张工单能告诉你功能为何创建,却未必说明该功能如今如何运作。
产物是证据。知识则是你的代理当前应视为真实的内容。
这一区分至关重要,因为有用的记忆几乎总涉及抽象化。我们不希望代理每次理解系统运作原理时,都要重读六个月的Slack记录。我们期望将全部历史转化为简洁且有用的信息。
借用数据库的类比,你可以将知识视为基于产物的物化视图。产物保留了发生之事;知识捕捉了当前重要之事。
关键在于保持两者间的联系。每当你要求LLM总结对话、提取事实或整合多个来源时,你都在进行有损转换。部分信息会消失,这无妨。丢失信息往往正是抽象化之所以有用的原因。
问题在于当你丢弃了源头。相反,知识应指向生成它的产物。多数情况下,代理可采取快捷路径:这是我们当前所相信的。但当具体细节至关重要时,它能深入探究并回答诸如此类的问题:我们为何相信这一点?这一变化何时发生?最初的讨论是什么?
这让你在享受抽象带来的效率的同时,又不失对底层历史的忠实还原。
而一旦知识被规范化,另一个问题便立刻浮现:它可能会过时。
知识需要版本控制
工件是历史性的。一旦某事发生,便已成定局。知识则不同。它代表世界的当前状态,而世界在不断变化。
如果今天你的记忆说认证使用API密钥,而明天团队迁移到OAuth,那么旧记忆就不仅仅是没那么有用了,而是错误的。
这也是Git为何成为知识管理的理想心智模型的原因之一。Git不仅告诉你文件现在长什么样,还告诉你它是如何变化的。你可以查看历史、查看差异,并重建过去某个时间点的真实状态。
但Git中还有一个概念,对智能体记忆而言可能更为重要:分支。
想象一个智能体在功能分支上实现OAuth。组织的当前知识说认证使用API密钥,但任务进行到一半时,智能体已经改变了系统,在其工作分支内,OAuth现已得到支持。这两种说法都是正确的,取决于你观察的是哪个版本的世界。
第二个事实不应成为组织知识,直到功能真正合并。智能体真正需要的是共享的组织知识,加上一个临时的、特定于任务的覆盖层,代表它当前正在操作的世界。
然后,当代码合并时,知识也可以随之合并。
随着智能体承担更长期、更自主的工作,我认为这将成为越来越重要的需求。我们不仅需要更新记忆,还需要分支、合并和调和知识。
当然,这听起来意味着需要维护更多的知识,这引出了下一个问题:我们究竟应该存储多少?
知识即缓存
人们很容易想象理想的智能体记忆系统是那种能记住一切的系统。我认为这是错误的目标。
人工制品相对容易保存。一条Slack消息发生了,就存储它。一次智能体会话发生了,就存储它。无需不断更新历史记录。
知识有维护成本。一旦你创建了关于认证系统如何工作的权威解释,你就创造了一个需要与认证系统保持同步的东西。将这个逻辑乘以大型组织中的每个功能、服务、客户工作流、决策、惯例和内部流程,你就构建了一个非常昂贵的维护问题。
思考智能体知识的更好方式,是将其视为缓存。缓存存在是因为某些信息重新计算代价高昂,而智能体知识与此类似。
想象一个智能体花费二十分钟追踪十二个服务之间的调用,以理解你的计费架构如何运作。这是获取成本高昂的上下文。如果接下来的二十个智能体都要重复同样的调查,那就保存结果。
现在想象智能体需要知道某个服务运行在哪个端口上,而答案就在一个显而易见的配置文件中。直接读取文件即可。创建并维护该事实的第二个表示,可能比重新计算它更昂贵。
这为我们提供了一个有用的框架,用于判断什么应放入记忆。有些知识是不可替代的:人类说,“我们不能移除这个行为,因为我们最大的客户依赖它。”这个事实可能在其他任何地方都不存在。如果你不捕捉它,它就消失了。
有些知识重新计算成本高昂:一个代理要搜索二十个文件、三个服务和六段历史讨论才能理解某件事。这正是值得固化的候选对象。而有些知识则频繁被使用。即便单次发现并不特别昂贵,反复重新发现也会造成不必要的成本。
其余一切都可以视为缓存未命中。
目标并非让代理记住所有东西,而是让它们记住那些“记住比重新发现更划算”的内容。
从简单开始
如今审视代理记忆领域,很容易得出结论:你需要图数据库、向量搜索、时间关系、本体论,以及一套新的基础设施,才能起步。
你可能并不需要。
如果今天从零构建一个内部记忆系统,我会从 Git 中的文件开始。代理已经知道如何使用它们,人类也知道如何检查它们。你免费获得历史和差异记录,而且不必在了解真正重要的事项之前预测所有未来需求。
然后观察它在何处失效。如果代理难以找到正确信息,改进检索;如果关系变得重要,增加更多结构;如果代理反复执行相同的昂贵研究,固化结果;如果规范知识变化太快难以手动维护,构建更好的维护系统。
如果你不想考虑这些,直接用 Dosu 就行。这正是我们投入时间解决的问题。
代理记忆行业在这里经历了一个有趣的循环。我们从日益复杂的检索和图架构起步,然后重新发现:把一堆组织良好的 Markdown 文件放进仓库,效果出奇地好。
我不认为这意味着 Markdown 是代理记忆的最终形态。它意味着复杂性应当被赢得,而非预设。
从最简单、能用的表示开始。保留底层产物。将值得维护的知识具体化。让系统中的失败告诉你下一步该增加何种复杂度。
当然,决定知识应该呈现为何种形态、存放在何处,只是问题的一半。无论如何,这些知识首先得被写入那里。
这就是我们接下来要深入探讨的:智能体如何捕获知识并将其写入记忆。
dosu.dev