給 agent 的記憶瘦身:常駐和按需分層
給 agent 加記憶,前幾周是純收益:它記得你的偏好,記得上次踩的坑,不用每次重新解釋。
幾個月之後,問題來了。記憶文件越來越多,每次啓動要讀的東西越來越長。agent 什麼都「記得」,但真正相關的那幾條被淹在一大堆舊任務、舊狀態、過期結論裏。更糟的是,舊結論會被當成現在的事實。
我之前寫過怎麼用一個 git 倉庫在多台機器、多個 agent 之間同步記憶。這篇講另一件事:記憶多了以後,怎麼瘦身。
一、兩層:常駐和按需
規則很簡單,只有兩層:
| 層 | 內容 | 什麼時候讀 |
|---|---|---|
| 常駐 | 規則、共享摘要、本機本 agent 的摘要、自動生成的近期動態 | 每次啓動讀一次 |
| 按需 | 方向與策略、歷史記憶、項目文件、工作流、交接、收件箱 | 當前任務需要時才讀 |
項目上下文屬於按需層,不是第三層。一個文件放在哪一層,和它重不重要無關,只和它是不是每次都要用有關。
二、常駐層只回答三個問題
常駐層在任何檢索之前,先回答三個問題:
- 我在為誰工作:用户是誰、主要做什麼。
- 現在的目標是什麼:當前的優先級和非目標,附複核日期。
- 最近動了什麼:過去幾天改過哪些記憶和項目。
第三個問題變化太快,手寫一定會過期,所以它是自動生成的:每次會話啓動時,一個腳本從 git 歷史裏算出最近 7 天改過的記憶文件、最近 30 天動過的項目,各自帶一行描述,寫進一個本地文件。它不提交——每次啓動都重新生成,提交的話會每個會話產生一個提交,還會在多台機器之間衝突。
除此之外,常駐層只放穩定偏好、必要邊界和幾個檢索入口。
三、哪些東西不該進常駐
這一條比「該放什麼」更重要。不進常駐的:
- 項目待辦和進度。 它們幾天就變,放進常駐就是在製造過期事實。
- 事故經過。 事故的教訓可以壓成一句規則放常駐,經過本身放按需。
- 舊狀態。 「某個分支還沒推」「某個 PR 等合併」——這種句子一週後幾乎一定是錯的。
- 宿主已經提供的通用指令。 工具自己會告訴 agent 怎麼用工具,不需要在記憶裏再抄一遍。
還有一條容易漏的:鏈接是路由,不是加載命令。 常駐文件裏可以放指向主題文件的鏈接,但 agent 不應該把鏈接全部點開讀一遍,更不能遞歸加載。
四、給常駐層定預算
不定預算,常駐層一定會慢慢長胖。我的默認預算按字節算:規則 4 KB,共享摘要 4 KB,每個 agent 的摘要 2 KB,自動生成的近期動態 2 KB,一次啓動最多 12 KB。
有一個檢查腳本在提交前跑,檢查每個常駐文件有沒有超預算。它從不截斷內容——超了就報出來,由人決定是壓縮、移走還是拆分。預算是維護時的檢查,不是運行時隨手丟規則的許可。
效果是可以測的。在我自己的庫上(約 180 個記憶文件,總共三十多萬 token):老辦法全量啓動約 7 萬 token;分層之後常駐啓動約 640 token;帶一個主題文件處理具體任務約 3600 token。
五、按需層:靠路由,不靠少讀
按需層的擴展方式,不是「把一個大文件讀少一點」,而是路由:
常駐摘要 → 記憶索引 → 一兩個描述匹配的主題文件。
為此,大的記憶文件按原有標題拆成主題文件,每個文件寫一行觸發式描述——不是「關於 git」,而是「做 git 操作或並行協作前讀:管道吞退出碼、切分支搬走在飛改動、禁裸 stash……」。索引由腳本從這些描述自動生成。agent 讀索引,按描述挑一兩個文件打開,其餘不碰。
拆分時有一條紀律:原文逐字搬,不在拆分時改內容。 內容的改動留給後面的蒸餾,並且要驗證每個原始標題恰好落在一個主題文件裏。
六、糾正多了,才升級到常駐
一條規則從按需升級到常駐,我的判據是:重複糾正。
比如「全程用中文回覆,長任務中途也不許切英文」。它最開始只是普通記憶,同一個會話裏被我糾正了三次之後,升級成常駐規則,並且在後台任務的進度播報裏也適用。
反過來,常駐裏的東西過期了要刪,錯了要改,而且要留下修訂理由。我的一條身份記錄曾經寫錯過,後來更正時保留了原文作對照,寫明哪一句作廢、為什麼——這樣下一個讀到它的 agent 不會照舊口徑講。
七、舊結論不等於現在的事實
最後一條,也是最難做到的:權威不會讓一條舊的事實陳述變成當前事實。
每條記憶帶來源日期和適用範圍。讀到一條三週前的「某某已完成」,agent 應該去核實當前狀態,而不是直接引用。歷史任務和舊交接也不構成當前授權——上週讓它做的事,不等於這周還要它做。
收束
記憶系統的難點不在於記住,在於忘掉什麼、什麼時候想起來。
我的答案是兩層:常駐層只回答「為誰、為什麼、最近動了什麼」,並且有預算;其餘全部按需檢索,靠描述路由。 重複糾正的才升級,過期的要刪,舊的要核實。
agent 啓動時讀得越少,讀到的就越可能是對的。