← 文章 / AI技术
HuggingFace博客 7小时前 · 2026-09-04 02:15:22 · 1 阅读

给你的编程代理一个你自己拥有的记忆

我在多台机器上工作,会根据任务切换不同的编码代理。而每个代理都像陌生人一样面对我的项目——上次会话中产生的推理,在会话结束时就消失了,每个新代理在每个新环境里都从零开始。 今年早些时候,Software Forgets: Agent Traces Are the Memory 一文指出,编码代理实际上已经产生了我们不断丢失的记录。当它们搜索代码库、尝试方案、遭遇错误、查阅文档、调整方向时,它们留下的是一篇详尽的记录,不仅记录了什么发生了变化,还记录了为什么。 不过诊断虽对,追踪记录只是潜在的记忆。代理的会话日志本质上仍是一份档案。你无法靠 grep 在万次操作里找到"我们为什么放弃了流式解析器?"的答案。要让代理在工作时真正利用这些追踪记录,还需要索引、检索、排序和精确的溯源能力。 这正是 funes 所提供的。它为代理(Claude Code、Codex、pi 和 Hermes)提供了一个持久的记忆层,从你机器上已有的会话构建,本地运行,一条命令即可融入代理的日常工作流。当需要时,它还可以同步到你私有默认的 Hugging Face 数据集。

为你已有的代理添加记忆

funes 是一个独立二进制文件,默认推理后端无需 ML 运行时依赖,嵌入和重排序都发生在你的机器上。安装方式如下:

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

然后将其关联到代理:

funes add claude    # 或:codex, pi, hermes

这条 add 命令会构建首次索引,赋予代理 recallget 两个工具,并安装自动化索引逻辑——每次操作完成后自动建立索引。索引是增量进行的:新轮次只需处理新增部分,而非重新嵌入整个历史。更久远的深度内容可以在有限的步骤内回填。

此后你只管正常工作。当任务触碰到过去的某项决策、某个理由或某个发现时,代理可以主动调用 recall。你无需记住旧会话的内容,也不用把上下文粘贴到新会话里。

# 让你的编程代理拥有属于自己的记忆

编程代理主动调用 funes 进行回忆,定位到之前的决策,并基于检索到的会话内容回答问题

加入 funes 后,回忆发生在对话内部。代理主动调用自己的记忆,并在回答时指明来源会话。

recall 返回原始文本而非摘要,并精确标注来源位置(代理、时间戳、会话、轮次)。每个结果都附带一条 get 命令,可打开完整轮次及其上下文。

底层通过一个确定性管道将各类支持的 trace 统一解析为「轮次+块」结构,然后分块、用本地固定模型进行嵌入,写入本地 Lance 数据集。查询时融合向量搜索与 BM25 的结果,再用交叉编码器对候选项重排序,按时效性重新加权,并附加相邻的块内容。

这一设计赋予 funes 三个关键特性:

  • 跨代理共享一份记忆:Claude Code、Codex、pi 和 Hermes 统一写入相同结构。一条 recall 结果可以跨越多个代理的历史,并标明出处是哪个代理生成的。
  • 原始证据保持完整:写入时不做提炼或事实蒸馏。任何结果都能回溯到生成它的原始轮次。
  • recall 默认本地运行:无需账户或 Hub 仓库。托管模型不会处理你的会话数据用于索引——嵌入和重排序都在本机完成,推理由你的编程代理自行完成。

「代理如同陌生人」的问题在一台机器上已得到解决。但当下一个代理运行在其他设备上时,记忆的价值会更大。

记忆是一个数据集,而非一项服务

要让记忆跟随你的工作流,只需在绑定 funes 到代理时指定一个记忆:

funes add codex acme/funes-memory

该命令会将你当前的记忆发布到目标位置。此后 funes 会持续保持同步,在本地对每一轮对话进行索引,并在会话边界处发布。整个过程中代理都可以从中召回。在另一台机器上运行相同的命令,记忆便会随之迁移。

底层而言,本地记忆是一个 Lance 数据集,共享记忆则是一个 Hugging Face 数据集(默认私有),由你完全拥有。 在数据到达 Hub 之前,凭据已在索引阶段被清除。发布时还会再次扫描每个分块,把任何仍像秘密的内容扣留下来。背后的扫描器在 SECURITY.md 中有文档记录,包括它能做什么、不能做什么。 当代理读取远程记忆时,funes 会将数据集文件缓存在本地,因此热点查询能达到本地速度。Hub 提供所有其他数据集都已具备的归属、访问控制、版本管理和分发能力。你的记忆不会变成某个独立记忆服务的账号,你也无需通过 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 记忆为何是追加只写模式;funes 检索相关会话并让编码代理据此作答

funes askfunes add 的只读单问版本。它召回相关片段,交给编码代理处理,返回一个标注来源的依据性答案。它不会安装任何集成或修改代理的持久化配置。

检索失败不会被掩盖。如果片段无法支撑某个答案,代理会明确告诉你。你可以换一种问法,或者在代理正常运行时将 funes 接入其中,让它能够迭代搜索记忆。

切换代理,不失主线

共享记忆不绑定于创建它的智能体或模型。在 Claude Code 中启动任务,下周用 Codex 接续,第二个智能体仍能调取第一个智能体的推理过程。用本地模型或经 Hugging Face 路由加载 pi,再回到 Claude 也一样。 Claude Code chooses an embedding model, then Codex recalls that decision in a separate session 这在多个场景下都很有价值: - **跨设备**:将智能体绑定到同一份记忆,从任意主机都能回顾完整历史。 - **跨团队**:新同事的智能体第一天就能检索数月来的决策记录,包括从未进入 PR 的死胡同和推理依据。 - **与开源项目并存**:维护者可以在 push 时命名并发布版本背后的会话记录。这相当于一个可搜索的 `CLAUDE.md`,保存着项目为何如此的历史,而非一篇需要人不断重写的文档。任何人都能用 `--memory` 读取公开记忆。 已发布的记忆带有数据集卡和 funes 标签,在 [Hugging Face Hub 上](https://huggingface.co/datasets?other=funes)既易识别又可发现。Hub 已有开放的模型权重和数据集,funes 则补全了开放的工作记忆——它保存项目的决策、失败方案和推理过程,可供其他智能体查询,并能追溯到产生它们的原始会话。

走出长会话成本最低的方式

漫长的对话会让会话越来越臃肿,直到每一轮承载上下文的开销远超执行任务本身。通常的做法是:让 agent 自行压缩后继续推进,或者写一份交接文档然后从头开始。Recall 是第三种选项,于是我们在 handoff-vs-recall benchmark 上对三者做了对比:这两项任务的解答,脱离了会话的先验知识就无法被还原。 Compaction 是大多数 agent 的默认行为,也是三案中唯一结果出现分歧的那一个:它在其中一项任务上完成了,另一项却始终失败。失败之处,摘要将关键发现一并抹平了。Recall 直接返回原文段落,因此关键发现不必经过摘要也能原样留存。 Recall 在两项任务上都是成本最低的方案,比手写交接文档便宜 8 倍和 4 倍。 Weighted tokens per successful task for five channels across two tasks, with recall the shortest bar on both

每根柱子较浅的部分是一次性的通道准备开销——无论是撰写交接文档还是做压缩,都在第一次提问前支付,只算一次。叉号代表某通道从未成功过,因此没有单位成功率成本。

别再从零开始了

“思考就是忽略差异、概括、进行抽象。” — 豪尔赫·路易斯·博尔赫斯,《博尔赫斯全集:回忆博尔赫斯》

你的 agent 早已留下了记录。funes 位于 github.com/huggingface/funes,一条命令就能将这些记录转化为下一条 agent 可读的记忆,无论你当前在哪台机器上操作。

建立在开源之上

funes 本身并无太多发明。它依赖的开源嵌入模型已经足够好,可以直接在本地运行;依托 Lance 的追加写入数据集实现低成本增量写入;再借助 Hub 的缓存和内容去重能力处理数据集。真正的工作在于把这些组件串联成一个 agent 真正能用得上的记忆系统。

`funes` 同样开源。无论是安装遇到阻碍、记忆召回不够精准,还是希望支持其他智能体,都欢迎在 GitHub 提交 issue。
原始来源: HuggingFace博客

评论 (0)