跳转到内容

记忆库(Memory Store)

每个 Agent 的 session 默认是相互独立的——上一次对话学到的东西,下一次不会自动记得。Neutree Agent Platform(NAP)用记忆库(Memory Store) 解决这个问题:你或 Agent 写进去的内容,会随后续每一次 session 进入 Agent 的工作上下文。

记忆库是新版本(替代了早期”每个 Workspace 一份单一 Markdown”的简单 Memory),它带来了几个能力:

  • 一个 Workspace 可以挂多个记忆库;一个记忆库也可以挂给多个 Workspace
  • 库里是多条记录,每条带版本,可追溯可回滚
  • 每条记录有类型(user / feedback / project / reference)
  • 对 Agent 暴露为普通文件,能用 grep、bash pipe、按需读取

旧版的痛点很具体:

  • 读不动——Agent 每次要读记忆都得全量读出来,长 session 跑久了内容很长,但跟当前对话相关的可能就一小段
  • 写不准——只有”全量替换 / 追加”两个语义。想改其中一小段,要么重写全文(耗 token、易丢失),要么追加(越来越乱)
  • 没结构——所有内容混在一份文档里。Agent 想给不同类型的任务记不同的事,最后都汇到一处,难维护

新版的设计目标就是把这三件事解开。

在「全局管理」里有 记忆库 入口。左边侧栏是当前账号下的所有记忆库。

  • 新建 Workspace 时,系统会自动创建一个同名记忆库并挂给它——所以默认情况下你看到的就是”一一对应”
  • 关系是解耦的:你可以新建一个库,手动挂给一个或多个 Workspace;也可以把同一个库挂给多个 Workspace 共享

这次新版上线时做了一次迁移——旧版每个 Workspace 的单条 Memory 内容会迁到对应的同名记忆库里。

这带来两个实用的分层模式:

  • 用户级共享记忆库——记”我”的偏好(用什么语言对话、偏好的风格),挂给自己所有 Workspace
  • Workspace 专属记忆库——记当前 Agent 的项目知识,只挂给一个 Workspace
  • 跨 Workspace 临时共享——两个 Workspace 协同做一件事时,临时挂同一份记忆

打开任意一个库,看到的是一个列表——每条记忆是一条独立的记录。

每次写入记忆,平台都会保留版本快照。你可以查看历史版本、回滚到任意一版——和 Git 的语义类似,让记忆从”一团黑盒文档”变成看得见、回得去的东西。

新建一条记忆时,必须从这四个类型里选一个,不能自定义

类型倾向例子
user整个用户全局的个性 / 偏好 / 倾向”我倾向用葡萄牙语对话”、“代码风格偏 PEP 8”
feedback当前对话里的即时反馈”回复时简洁一点”、“不要中英混杂”
project围绕任务的项目级知识”这个项目用 PostgreSQL,主表在 app_user 库下”、“上次直接 DROP TABLE 翻车过”
reference外部引用”回答这类问题之前先读 https://internal-wiki/foo

这套分类参考了 Claude 的官方记忆系统(Claude Code 和它的托管 Agent 都用同一组类型)。我们目前没有足够的量化数据来证明这是最优分类,但选择跟随一个已经被大规模验证的方案,比自己拍脑袋设计更稳。后续会根据使用数据扩展。

这是新版最关键的设计决定:记忆库在 Agent 容器里以文件形式暴露,挂载在 /mnt/memory/<store-name>/ 下。

也就是说——Agent 读写记忆,用的不是某个特殊 API,就是普通的文件操作

Terminal window
# Agent 视角
ls /mnt/memory/
cat /mnt/memory/user-prefs/language.md
grep -r "DROP TABLE" /mnt/memory/
echo "新的偏好" >> /mnt/memory/user-prefs/notes.md

为什么这么做?因为 LLM 对文件读写有非常深的原生 affordance:它会用 catgrepheadtailsed、bash pipe 这一整套工具按需高效读写。任何自定义的 API 都得另写一段 prompt 教 Agent 怎么用,效率不如直接复用它已经会的文件语义。

特别是写入——通过 pipe 直接合并多个文件到记忆,Agent 一次 bash 调用就能完成,不需要把内容作为 token 输出再粘贴。这是 MCP 工具至今难以匹配的效率。

每个库的根目录下,MEMORY.md(大写)是一个特殊的索引文件

  • 由 Agent 自主维护——每次新增/修改/删除记忆条目时,Agent 会同步更新这份索引
  • 它会被平台直接内联进 Agent 的系统 prompt

因此 Agent 一启动就能从系统 prompt 里看到:当前挂了哪些库、每个库的大纲是什么。具体某一条记忆的完整内容仍在子文件里,Agent 看到大纲后按需读取——这是新版高效读取的核心。

打个比方:MEMORY.md 是图书馆门口的索引牌,子文件是书架上的书。Agent 进门就知道有哪些书、各自讲什么,要看哪本再走过去翻。

为了让记忆库这种机制生效,NAP 在你写的 system prompt 之外还会注入一层「平台 prompt」。这层 prompt 是平台自动维护的,会动态拼接:

  • Agent 类型、注册的内置 skills(比如 platform skill)的引用说明
  • 当前挂载的所有记忆库的名字 + 每个库的 MEMORY.md 索引内容
  • 一些常驻的工具使用建议

所以 Agent 启动时就能”看见”它有哪些记忆可用、各自的大纲、要深入读时去哪里——不需要用户在自己的 prompt 里手写引导。

你自己写的 system prompt 仍然完全有效,平台 prompt 只是叠加在上面的一层公共上下文。

这一节是给好奇底层的同学准备的,不影响使用。

记忆库的真源是数据库——库、记录、版本、(workspace, store) 挂载关系都是 control plane 数据库里的表。这样后台才能做批量整理、跨 Workspace 的索引、未来的”持续记忆整理”功能。

但 Agent 看到的是文件。这中间的桥是给每个 Agent pod 注入的一个 sidecar 容器——memory-fuse

┌─────────────────────────┐ ┌──────────────────────┐
│ Agent 容器 │ │ memory-fuse sidecar │
│ 读写 │ │ │
│ /mnt/memory/<store>/ │◄──►│ FUSE 挂载点 │
│ │ │ ↕ │
└─────────────────────────┘ │ 本地缓存(文件副本) │
│ ↕ │
│ control plane API │
└────────────┬──────────┘
DB(库/记录/版本)
  • 挂载时——sidecar 启动或收到 mount/umount 信号时,从 control plane 拉这个 Workspace 挂了哪些库、库里有哪些记忆,把内容写到本地缓存目录
  • Agent 读——FUSE 劫持读请求,命中本地缓存就直接返回;不会每次都打 DB(grep 一类操作可能同时命中很多文件,每次回源 DB 性能会很差)
  • Agent 写——FUSE 劫持写请求,翻译成对应的 control plane API 调用(create / update / delete),最终落 DB;同时刷新本地缓存让后续读看到一致状态

为什么不用 MCP 工具暴露记忆?两个原因:

  1. 读的灵活性——LLM 已经会用 grepheadtail、按行读、按片段读这些文件操作。一套自定义 MCP 读接口要重复实现这些语义,还要花 prompt 教 Agent 用
  2. 写的 pipe 能力——文件系统支持 cat a.md b.md | tee /mnt/memory/x.md 这种连贯操作,Agent 不需要把内容回流到 token 里再输出。MCP 目前还没有等价的 pipe 语义

这套机制也跟 Claude 的托管 Agent 高度一致——根据外部分析和实测来看,他们也是用类似的 sidecar + FUSE 方案让记忆”看起来像文件”。

让 Agent 自己整理记忆——尤其是从旧版迁移上来的库,第一条记录通常是一整段陈年笔记。直接对 Agent 说”按最佳实践重新整理一下这个记忆库”,它会自己拆分、归类、维护索引。

写好 MEMORY.md——索引越清晰,Agent 按需读取的命中率越高。每条记忆在索引里有一两句话的简介足够,正文留给子文件。

分层挂载——账号级偏好(语言、风格)放一个独立的”用户记忆库”,挂给所有 Workspace;项目知识放 Workspace 专属库。别把所有东西塞一个库里。

敏感信息不要进记忆库——API key、密码请用 凭证。记忆库本质是 Agent 上下文,会进对话,不适合放秘密。