我使用多台機器工作,並根據任務切換不同的程式碼代理人。然而,每個代理人面對我的專案時都像個陌生人,上次會話的推理在結束後就消失了。每個新的代理人,在每個新的主機上,都必須從頭開始。
今年稍早發表的論文《Software Forgets: Agent Traces Are the Memory》指出,程式碼代理人實際上已經產生了我們不斷丟失的紀錄。當它們搜尋程式碼庫、嘗試各種方法、遇到錯誤、閱讀文件並改變方向時,它們留下了詳細的記錄,不僅說明了哪些地方發生了變化,還解釋了原因。
儘管診斷正確,但這些追蹤紀錄(traces)僅是潛在的記憶。代理人的會話日誌仍然只是一個檔案庫。你無法透過 grep 在上萬次的互動中找到「我們為什麼放棄串流解析器?」的答案。要讓代理人在工作時使用這些追蹤紀錄,它們需要索引、檢索、排名和精確的來源證明。
這正是 funes 所提供的功能。它為你的代理人(Claude Code、Codex、pi 和 Hermes)提供了一個持久的記憶層。funes 是根據你機器上已有的會話紀錄建立的,它在本地運行,只需一個指令就能成為你代理人正常工作流程的一部分。如果你願意,它也可以傳輸到你擁有的 Hugging Face 資料集,預設為私有。
funes 是一個單一的二進位檔案。它的預設推論後端沒有機器學習執行時依賴,嵌入和重新排名都在你的機器上進行。安裝方式如下:
curl -fsSL https://huggingface.co/buckets/huggingface/funes/resolve/install.sh | sh
然後將它添加到代理人:
funes add claude # 或:codex, pi, hermes
這個 add 指令會建立第一個索引,賦予代理人 recall 和 get 工具,並安裝自動化功能來索引每個完成的互動。索引是增量的,新的運行只會添加新的互動,而不是重新嵌入整個歷史紀錄。較舊和較深的內容可以分階段回填。
從那時起,你只需正常工作。當一個任務涉及到過去的決策、理由或發現時,代理人可以自行調用 recall。你不需要記住舊的會話,也不需要將其上下文貼到新的會話中。
添加 funes 後,recall 會在對話內部發生。代理人會自行調用其記憶,並指出其答案背後的會話來源。
recall 返回的是原始文本,而非摘要,並精確顯示其來源(代理人、時間戳、會話和互動)。每個結果都包含一個 get 指令,可以打開完整的互動及其周圍的上下文。
在底層,一個確定性的管道將每個支援的追蹤紀錄解析成相同的「互動與區塊」形狀,然後進行分塊、使用固定的本地模型進行嵌入,並寫入本地的 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 "我們對串流解析器做了什麼決定"
或者將它指向共享記憶。我們發布了一個 funes 開發的記憶,所以你可以直接詢問 funes 為什麼這樣設計,而無需自己建立記憶:
funes ask claude "為什麼 funes 只能追加" --memory huggingface/funes-memory
funes ask 是 funes add 的唯讀、單一問題版本。它會回溯相關段落,將它們交給程式碼代理人,並返回一個有根據的答案,同時標明其來源。它不會安裝整合或改變代理人的持久設定。
檢索失敗不會被掩蓋。如果段落無法支持答案,代理人會直接說明。你可以重新措辭問題,或將 funes 添加到代理人,以便它在正常工作期間迭代地搜尋記憶。
切換代理人而不失連
共享記憶不與創建它的代理人或模型綁定。你可以在 Claude Code 中開始一項任務,下週在 Codex 中繼續,第二個代理人仍然可以回溯第一個代理人的推理。你可以使用 pi 搭配本地模型或透過 Hugging Face 路由器提供的模型,然後再返回 Claude。
Claude 做出一個決定;一個鉤子(hook)將其索引;Codex 在另一個會話中回溯它。演示中較舊的命中結果是相同實驗的早期記錄:一個只能追加的記憶也記住了排練過程。
這在幾個不同的範圍內都很重要:
跨你的機器:將每個代理人綁定到一個記憶,並從你正在使用的任何主機回溯歷史紀錄。
跨團隊:新隊友的代理人可以在第一天就檢索數月的決策,包括死胡同和從未進入拉取請求的理由。
與開源專案並行:維護者可以發布版本背後的會話紀錄,並在推送時命名它們。將其視為一個可搜尋的 CLAUDE.md,它包含了專案為何如此的歷史紀錄,而不是一個需要不斷重寫的頁面。任何人都可以使用 --memory 讀取公共記憶。
已發布的記憶帶有資料集卡片和 funes 標籤,使其在 Hub 上易於識別和發現。Hub 已經託管了開源權重和資料集。funes 增加了開源的工作記憶。它包含了專案背後的決策、失敗的方法和理由,可供其他代理人查詢,並可追溯到產生它們的會話。
擺脫冗長會話最便宜的方式
冗長的調查會使會話膨脹,直到每次互動攜帶上下文的成本高於實際工作的成本。通常的解決方案是讓代理人壓縮並繼續,或者寫一份交接文件並重新開始。recall 是第三種選擇,我們在「交接與回溯」基準測試中對它們進行了比較:這兩項任務的答案無法在沒有會話先驗知識的情況下重建。
壓縮是大多數代理人預設的做法,它是三種方法中唯一結果分歧的:它在一個任務上成功了,但在另一個任務上從未成功。在失敗的情況下,其摘要扁平化了重要的發現。recall 返回的是原始段落本身,因此發現不必在摘要過程中倖存下來。
recall 在兩項任務中都是最便宜的,比書面交接在一個任務上便宜 8 倍,在另一個任務上便宜 4 倍。
每個條形圖中較淺的部分是準備通道(交接或壓縮)的一次性費用,在提出第一個問題之前支付並計算一次。叉號表示從未成功的通道,因此沒有成功成本。
停止從零開始
「思考就是忘記差異,概括,抽象化。」,豪爾赫·路易斯·波赫士,《記憶的富內斯》
你的代理人已經寫下了紀錄。funes 位於 github.com/huggingface/funes,只需一個指令,就能將這些紀錄轉化為下一個代理人可以讀取的記憶,無論你身在哪台機器上。
基於開源建構
funes 在這方面幾乎沒有發明什麼。它依賴於足以在本地運行的開源嵌入模型、Lance 具有廉價增量寫入功能的只能追加資料集,以及 Hub 的資料集快取和內容去重功能。其工作在於將它們整合到一個代理人實際可以使用的記憶中。
funes 也是開源的。無論是安裝問題、recall 遺漏,還是你希望支援的代理人,都歡迎提出問題。



