面向Google编程CHARLES ZHANG

AI DAILY / 2026-09-07

给编程 Agent 一份你拥有的记忆

Give Your Coding Agents a Memory You Own

Agent 开发Hugging Face · 2026-09-03

全文中文翻译 · AI 生成,仅供学习交流

Give Your Coding Agents a Memory You Own

2026年9月3日

David Corvoysier

dacorvo

我在多台机器之间工作,也会根据任务换不同的编码智能体(coding agents)。

它们面对我的项目时,都像个陌生人。「上周二」的那次推理,会话一结束就消失了。新主机上的每个新智能体,都从零起步。

今年早些时候,我写过一篇《Software Forgets: Agent Traces Are the Memory》,里面提出,编码智能体其实已经在生产我们一直在丢失的那份记录。它们在搜索代码库(codebase)、尝试方案、碰到错误、翻阅文档、调整方向的过程中,留下的不只是「发生了什么变化」,还有一份关于「为什么会这样」的密集记录。

诊断是对的,但 trace(追踪记录)只是潜在的「记忆」。一份智能体的会话日志,终究只是份归档。你没法在动辄上万轮的记录里靠 grep 找到「我们当初为什么放弃流式解析器(streaming parser)?」这句话。要让智能体在工作中真的用上这些 trace,就得给它们做索引、做检索、做排序,还要保证精确的可溯源性(provenance)。

这正是 funes 提供的。它是你智能体(Claude Code、Codex、pi 和 Hermes)的一个持久化记忆层(memory layer)。它由你机器上已有的会话构建。本地运行,一条命令就接入你智能体的日常工作流。需要的时候,它也能同步到你拥有的一个 Hugging Face 数据集,默认私密。

为你已经在用的智能体加上记忆

funes 是一个单一的可执行文件。它默认的推理后端不依赖任何机器学习运行时(ML runtime),嵌入(embedding)和重排序(reranking)都在本机完成。安装方式,

curl -fsSL https://huggingface.co/buckets/huggingface/funes/resolve/install.sh | sh

然后接入一个智能体,

funes add claude

# or: codex, pi, hermes

这一条 add 命令会建好第一份索引,给智能体配齐 recallget 工具,并装上每轮会话结束后的自动索引流程。索引是增量式的(incremental),新跑的内容只会追加新轮次,而不是把整段历史重新嵌入一次。更早、更深的内容会按有界步长回填(backfill)。

之后你照常工作就行。只要任务碰到过去的某条决策、某条理由、某个发现,智能体就能自己去调 recall。你不用记着那个旧会话,也不用把它的上下文粘到新会话里。

funes 接好之后,召回就发生在对话内部。智能体自己伸手去翻记忆,并且把答案背后的那个会话点名出来。recall 返回的是原始文本,不是摘要,并清楚标出来源,包括智能体、时间戳、会话、轮次。每条结果都附带一个 get 命令,能展开完整的轮次和它周围的上下文。

在底层,一条确定性的流水线(pipeline)把每种支持的 trace 解析成统一的「轮次-块」(turn-and-block)结构,做切分(chunking),用一个固定的本地模型做嵌入,再写入一份本地的 Lance 数据集。一次查询会同时跑向量搜索和 BM25 搜索,融合两边的排序,再用交叉编码器(cross-encoder)做一轮重排序,按时间新鲜度重新加权,最后把相邻的块挂上来。

这套设计让 funes 拿到了三个重要特性。

跨智能体的统一记忆。Claude Code、Codex、pi 和 Hermes 写入的都是同一种结构。recall 跨过它们的历史,每条命中都标明是哪个智能体产出的。

原始证据保持完整。写入时不会被提炼成「事实」。每条结果随时能回溯到产出它的那个轮次。

recall 默认本地运行。不要求任何账号,不要求任何 Hub 仓库。索引过程不依赖托管模型去处理你的会话,嵌入和重排序都在本机完成,推理由你自己的编码智能体来做。

「智能体如陌生人」的问题,在同一台机器上已经解决了。但当下一次智能体跑在另一台机器上,记忆的价值才真正显现出来。

记忆是数据集,不是服务

想让一份记忆跟着你的工作走,在给智能体装 funes 的时候绑定(bind)一份就行,

funes add codex acme/funes-memory

绑定时,会把当前记忆发布到那里。之后 funes 会持续保持更新,本机索引每一条轮次,在会话边界把更新发到云端。智能体在工作中随时从这份记忆里召回。在另一台机器上跑同一条命令,记忆就跟着你过去。

在底层,本地记忆是一份 Lance 数据集,共享记忆则是一份属于你的 Hugging Face 数据集(默认私密)。

在内容抵达 Hub 之前,索引阶段就已经把凭据脱敏了。发布时还会再扫一遍每一块,凡看起来还像密钥(secret)的内容一律扣下。这层扫描器的覆盖范围和未覆盖的部分都写在 SECURITY.md 里。

智能体读取一份远程记忆时,funes 会把数据集文件缓存到本地,热查询(warm queries)也能回到本地速度。Hub 提供的是它原本就给其他数据集的那套能力,包括所有权(ownership)、访问控制(access control)、版本管理(versioning)、分发(distribution)。你的记忆不会变成另一家「记忆服务」里的一个账号,也不会通过 API 再租回来。

先问,再接入

recall 是为智能体设计的。你自己想向一份记忆提个问题,就用 ask。它默认读你的本地记忆,

funes ask claude "what did we decide about the streaming parser"

也可以指向一份共享记忆。我们发布了一份关于 funes 开发过程的记忆,这样你不用自己建一份,也能问出 funes 为什么会是现在这个样子,

funes ask claude "why is funes append-only" --memory huggingface/funes-memory

funes askfunes add 的只读、单问版本。它召回相关段落,交给一个编码智能体,返回一个有据可查的、注明来源的答案。它不装任何集成,也不改智能体的持久化配置。

召回没命中也不会被糊弄过去。如果相关段落撑不起一个答案,智能体会直说。你可以换个问法,或者把 funes 装到智能体里,让它在日常工作中迭代地搜记忆。

切换智能体时不丢线索

一份共享记忆不绑定产它的那个智能体或模型。在 Claude Code 里开个任务,下周切到 Codex 接着干,第二个智能体能召回第一个智能体的推理过程。本地模型上跑 pi,或者通过 Hugging Face 路由器(router)用托管模型,完事再切回 Claude,都可以。

Claude 做了一个决定,钩子(hook)把它索引进去,Codex 在另一场会话里召回它。演示里更早的那些命中,是同一实验的更早版本,一份只可追加(append-only)的记忆同样记住了那些排练过程。

这件事在几个不同的尺度上都有意义。

跨你的多台机器。把每个智能体绑到同一份记忆上,不管你人在哪台主机,都能召回完整历史。

跨团队。新同事的智能体入职第一天就能召回几个月来的决策,包括那些没进过拉取请求(pull request)的死胡同和背后的理由。

伴随一个开源项目。维护者可以把一次发布背后的会话发布出来,推送(push)时给它们命名。可以把它理解成一份可搜索的 CLAUDE.md,承载着项目之所以成为现在这个样子背后的历史,而不是一份需要有人反复重写的页面。任何人都可以用 --memory 读取一份公开记忆,并且这份记忆在 Hub 上也能被发现。

Hub 上原本就托管着开放权重(open weights)和数据集。funes 在此之上又加上了开放的工作记忆(open working memory)。它装着项目背后的决策、失败的尝试和理由,既可以被另一个智能体查询,也能追溯到产出它们的那些会话。

走出长会话的最便宜路径

一项漫长的调查会把会话撑得臃肿不堪,等到每轮要扛的上下文比要干的活还贵,会话就拖不动了。常见的应对是让智能体压缩(compact)一下继续,或者写一份交接(handoff)然后重新开始。召回是第三种出路,所以我们把它们放在 handoff-vs-recall 基准上