智能体记忆:一种文件格式
Memoryfields —— 一种简单得多的智能体记忆方案
许多模型基准测试 都从空白的上下文窗口开始,也就是 AI 的“白板”状态。从某种程度上说,这样做有道理,能保证基准测试的公平性。
但真实的智能体绝不应该从空白上下文窗口起步。它们应该在启动时就获得尽可能多的相关信息。换句话说,你的 AI 智能体应该带着记忆开始工作。
为什么现有的智能体记忆系统都不太奏效
问题是,很多智能体记忆系统其实相当糟糕。当下流行的记忆系统大致可以分为三类,每一类都有各自失效的方式。
第一类是有意把你绑定在某个特定的“马具”(harness)上,通常这套马具由向你出租它的实验室自己打造。该实验室迫切希望从(竞争激烈的)"API 业务"转型到(利润高得多的)"平台业务"。这类系统一般通过从你的对话历史中挖掘信息来运作,结果就是它们记住的内容大多都是关于你的,而关于世界的信息其实往往更有用。
另一类则荒谬地复杂。我听说过一个知名的系统,光是为了判断哪些内容值得记住,就需要 pgvector、一个 Neo4j 图数据库,再加上一个独立的 LLM。这种复杂性不仅难以运维,还会让模型本身也被搞糊涂,具体原因我后面会解释。而且这些"大型系统"也无法随着模型前沿的演进而扩展。
最后一类属于"高度现代主义"风格,它们构想出一种理想化、理性化的记忆形态。这类系统几乎必然会用到图结构,有时还会用到逻辑命题。它们系统性地把信息从其语境中剥离出来,使其变得孤立、对智能体(以及你而言)毫无意义。想想看,一份简单的"提炼后的事实清单"究竟能有多大用处?
它们的共同之处在于:都把记忆当成一个流程来处理。但对模型而言,记忆更适合被当作数据来表达。
记忆应该是一种数据格式,而非多阶段流水线
Brooks 说过:
给我看你的流程图,藏起你的表格,我就还是一头雾水。给我看你的表格,那我通常就不需要你的流程图了——一切不言自明。
那么,下面就是"记忆域"(memoryfield)这种可移植的内存文件格式:
my-memories.memoryfield.zip
├── carbon-fibre-woks.md
├── finnish-bureaucracy-tips.md
├── [... many more md files...]
├── wec-2026-season-notes.md
└── nomic-embed-text-v1.5.sqlite3
一个记忆域包含:
- Markdown "页面"
- (可选的)YAML 前言(frontmatter)
- (可选的)用于语义检索的 SQLite 向量索引
智能体最适合用文件来工作,且听我道来。
设计决策一:采用散文,而非分块或"事实"
RAG 流水线之所以可能非常复杂,根本原因在于它们试图让大量已有的人类文档变得对 AI 智能体可读。这些文档往往很难被智能体直接读取,比如因为它们是体积庞大的 PDF。
但智能体的记忆并非复杂的遗留文档。记忆在形成的那一刻,是直接发生在完全能写散文的 AI 智能体身上的。这段散文无需分块、也无需人工补充、双重摘要或任何其他机械化的处理——只要让智能体直接用它最擅长的格式(也就是 Markdown)把记忆写下来就行。
一个记忆域页面看起来是这样:
---
title: Carbon Fibre Woks
created: '2026-03-01T09:00:00Z'
updated: '2026-08-22T14:30:00Z'
uuid: 6aa615f0-486f-48a7-a210-ba4f5ff18c8b
summary: Thermal properties of carbon fibre cookware
---
Carbon fibre woks conduct heat evenly, but...
诚然,有一个限制条件:页面必须足够短,才能放进向量嵌入里——也就是说,有一个大约 8KB(约 2000 个 token)的软上限。
不过这在实际中反倒是个很有益的限制:8000 个字符大约相当于 1300 个英文单词,也就是一篇中等长度杂志文章的篇幅。说实话,这本来就是一个值得施加的限制。想要补充更多细节,就多加几页——这对智能体来说不在话下。
设计决策二:语义跳转,而非图遍历
一个重要的先例是 Karpathy wikis。它以超链接的 Markdown 文件为核心,模仿 Roam 或 Obsidian 的设计。思路是让智能体在"知识图谱"中游走,找到相关页面。
但实践中,让 AI 智能体遍历知识图谱既慢又不可靠,对智能体本身也很容易造成混乱。
之所以慢,是因为模型必须频繁停下来,串行地调用工具去一页一页地读。
智能体遍历知识图谱的大致流程是:
- 读 wiki 首页 [工具调用]
- 找出相关链接
- 读取链接到的页面 [工具调用]
- 找出相关链接
- 判断信息是否已经足够
- 若不够,回到第 2 步
如果相关信息藏在知识图谱的 N 层深处,就需要 N+1 次工具调用才能拿到。这非常慢——你那价值十亿(百亿?)美刀的 LLM 得为每次调用暂停,而每次调用又要花上 2 到 3 秒。同时,这种方式对深嵌套的知识图谱极不友好,而这恰恰违背了用知识图谱的初衷。
知识图谱也不可靠。AI 只能通过链接文字,或者(假设被外部化的)页面标题来判断内容是否相关。这迫使智能体不得不搞 90 年代 SEO 式的元数据优化,让每个页面的链接文字、标题、说明都变得又醒目又精准。这种要求会惩罚一切"跑题"——随手记下的边角细节、隐含的背景设定——而这些东西在大型文本语料中既常见又极有价值。
实践中,Karpathy wikis 经常漏掉真正相关的信息,只因为它们的标题或说明对正在搜索的智能体来说不够"诱人"。
知识图谱对智能体来说也很令人困扰,因为它们在图谱中穿梭时,往往得翻阅大量无关信息。无意中读到这些无关内容(首页通常是主要「罪魁祸首」)会把一堆噪音塞进模型的上下文窗口,从而降低输出质量,还会让模型看起来执着于一些奇怪的东西。
用语义搜索就能彻底解决这些问题——直接定位到所有相关的页面(依据实际内容而非页面元数据),然后让智能体一次性、并行地读完这些页面(现在绝大多数智能体都能这么做)。所以在 memoryfield 中,最多只需要两次工具调用(第 1 次搜索,第 2 次并行读取)。相关内容真正能被找到,无关的输入 token 也被压到最少。
设计决策三:少做机制,多交给模型
「高机制」的内存系统(那种带一大堆专门定制的 API 或数据库的系统)有个问题:要用它们,智能体得穿过一个接口迷宫才能达成目标。如果接口很大,就得把大量 openapi.json 塞进上下文;如果接口很小,又会处处受限。就算接口大小刚好合适,API 设计也常常不对劲——回想一下你不得不使用别人写的、根本没考虑过你需求的 API 时的经历。那体验愉快吗?
memoryfield 作为一种「低机制」系统(仅仅是一个文件格式),给了智能体更大的自由度去发明自己的访问方式。虽然提供了一些(希望是)有用的辅助工具,但智能体完全可以自由选择任意访问方式。比如用 perl 对整个语料库做查找替换,或者把内联的 CSV 文件嵌进记忆里,再用 SQLite 查询(这两个都是我亲眼见过的真实例子)。
"低机制"也意味着 memoryfield 能随着模型前沿能力的提升而扩展。模型越强,智能体能想到要做的事就越多。最近的一个突破是,模型在 bash 上意外地非常拿手。Markdown 也难不倒它们,SQLite 同样不在话下。我认为 memoryfield 之所以能在真实智能体中良好运作,其中一个原因是:智能体从根本上就能从训练数据中"领会"发生了什么(在你能够读取自己的记忆之前,训练数据是你唯一的依凭),而这一点,作为"记忆管线"中一次孤立的 LLM 调用,是做不到的。
随着模型变强,它们自然而然地开始把记忆写得更加巧妙。而那些"外挂式"的记忆系统很少能做到这一点。对一组固定的 API 端点,再怎么花样翻新也就那么几种玩法。memoryfield 会跟着模型前沿一起进化。
设计决策 4:开放格式、可互换、传输方式无关
随着记忆越积越多,它们会变得弥足珍贵。那是你一路积累下来的经验教训和来之不易的既定事实。你不会愿意被某个特定的框架、模型或智能体绑死。
我已经写了一份 RFC 风格的文件格式规范,主要目的是消除歧义,并避免把它绑定到某个特定的嵌入函数上。
如果你愿意,单凭这份规范当然可以 vibe code 出你需要的任何工具。不过我也配套提供了一个技能模块和一个面向智能体优化的命令行工具。
memoryfield 的标准"归档"格式是一个 zip 压缩包,目的是让数据交换尽可能简单。但我在规范中刻意留出了余地,允许从本地文件、Amazon S3、GitHub 或 HTTP 等任意方式加载——只要能存放文件就行。我个人就混合使用了这几种传输方式:个人用的 memoryfield 用 Syncthing 同步,需要和别人共享的则放在 S3 上。
入门
你完全可以让智能体把SPEC.md拉下来,然后 vibe 出一个实现。但最简单的入门方式大概还是直接用我提供的工具:
# 需要:ollama、uv 和 npx(npm 自带)
#
# 1. 拉取嵌入模型:
ollama pull nomic-embed-text
# 2. 安装 CLI 工具:
uv tool install git+https://github.com/calpaterson/memoryfield-tool
# 3. 安装 skill:
npx skills add calpaterson/memoryfield-skill -g -y
从这里开始,你的 agent 应该会帮你跑起来。
如果你想要一个能直接试用的 memoryfield,可以试试
soapstones.memoryfield.zip。
Soapstones 是我之前做的一个 agent 记忆项目,这份精心整理的导出文件里包含了很多高价值、低"体积"的记忆,比如:agent 怎么搜索 Reddit、怎么用 Jina Reader、怎么用 MediaWiki API 高效地读 wiki。
「这不就是个 RAG 吗」——以及其他常见质疑
这不就是个 RAG 吗?
「RAG」这个词现在的含义已经宽泛得离谱了——只要 agent 取了点数据,就有人说「这就是 RAG」。从这个角度说:没错,这就是一种 RAG。
但问题是:几乎所有 agent 都会取数据,比如搜个网页。而那些通常被认为属于「RAG 系统」的技术,这里一个都没用。没有切片,没有重排,也没有混合检索。
另一方面,关键在于记忆是由 agent 自己写入的。RAG 系统通常只关心读,而 memoryfield 同时也服务于写。
nomic-embed-text-v1.5不是已经发布两年多了吗?没有更新更强的模型吗?
嵌入模型既没有前沿模型那么大,也没有它们迭代得那么快。
nomic-embed-text-v1.5 在体积和效果之间仍然是个不错的平衡。它足够小(270MB),也足够快,能在非 GPU 的机器上跑,而且是被广泛推荐、很多人都在用的默认嵌入模型。
不过规范本身是允许换成其他嵌入模型的。
我怎么判断什么记忆值得存?怎么避免往记忆里塞一堆垃圾?
在记忆系统中,这算是一种常见担忧,但放在 memoryfield 上其实并不成立。无关的内容根本不会被语义搜索检索到。它们确实会占空间——你可能也希望定期清理一下——但不会妨碍 agent 的运行。
想取得最佳效果:往 memoryfield 里多写就对了。有一条建议是:记忆最好附带引用,理想情况下是 URL 形式。这样后续重新审视这些记忆时可以强化它们,也能帮助 agent 核对那些已过时或存疑的内容。
安全性怎么办?遇到"忽略前面的指令!"这种提示怎么办?
不要把你的上下文窗口(包括以记忆形式存在的部分)分享给任何你不信任的对象。
规范中采用静态 zipfile 格式的原因之一,就是让你能手动审查并通过 sha256sum 锁定(pin)从他人那里获取的 memoryfield。
到目前为止,仍然没有办法让 agent 区分"善意提示"和"恶意提示"。
数据优先
既然流程已经很清楚了,干脆直接说清楚:
- 把记忆写成 Markdown
- 做 embedding 并把向量存入 SQLite
- 通过语义搜索重新找回这些记忆
Memoryfield 在记忆系统中很特别:它定义的是数据结构,而不是处理流程。没有抽取流水线,没有后台处理服务,也没有什么可插拔的——什么都好。倒是有一个向量索引,但它只是一个可以删掉的缓存,而不是系统的核心。
记忆就是数据!agent 和数据之间的固定机制越少,agent 的表现就越好。
联系方式等
备注
如果你有空,欢迎看看这份规范。任何(人工的)审阅都非常有价值。
我的安装流程里数下来一共涉及四种包管理器(Ollama、uv、NPM、Vercel Skills)。感觉应该还有更好的办法。有答案的朋友,欢迎来鸿雁传书。