寫入和檢索都講完了,還剩一個常被跳過的維度:時間。一個 agent 跑了三個月,記憶庫裡同時躺著三個月前的「使用者偏好 Python」和昨天的「幫我查一下天氣」。下次檢索時,誰該浮上來?記憶該不該過期?這些問題每個系統都得回答,而且答案的分歧比寫入和檢索更大。
第一個問題:偏「新的」還是偏「重要的」? 最新的往往最不重要(昨天查天氣),重要的往往很舊(三個月前定下的專案慣例)。但系統沒辦法直接知道哪條重要,只能找代理指標:時間、被使用的頻率、或者讓 LLM 打分。
第二個問題:這個偏向發生在寫入時,還是搜尋時? 寫入時決定(存的當下就分層或淘汰),之後的每次搜尋都很輕;搜尋時決定(全部存著,查詢當下才計算衰減),彈性大但每次查詢都要多算一筆。
拿這兩個問題當座標,五個系統的設計就攤開了。
OpenViking:熱度衰減,搜尋時計算。 昨天介紹過的這個階層式記憶系統,給每條記憶算一個熱度:被取用的次數乘上時間衰減(半衰期七天),搜尋時把熱度混進語意分數(三成熱度、七成語意)。邏輯是「你最近一直在查的東西,現在對你重要」。冷掉的記憶不會被刪,只是在排名裡沉下去。
agentmemory:知識類型決定壽命,寫入時分層。 前天介紹過的全量捕捉派,借了心理學的遺忘曲線概念,把記憶分四層、各有衰退速率:程序性知識(「這個專案用 pytest,fixture 放 conftest.py」)幾乎不過期;今天的臨時觀察一個 session 後就消散。不用人工排優先序,記憶的「種類」本身決定它活多久。這對 coding agent 特別合理,因為最值得複用的正是程序性知識。
DeerFlow:沒有時間,只有排擠。 昨天那個全量注入的極簡派,記憶上限 100 條,每條帶著寫入時 LLM 給的信心分數,空間滿了就淘汰分數最低的。記憶永遠不會因為「太舊」而死,只會被更有信心的新記憶擠出去。這個設計有一個隱患:LLM 的信心分數會隨模型版本漂移,三個月前的 0.8 和今天的 0.8 未必是同一種確定程度,比較基準悄悄歪掉。
engram:最新的直接蓋掉舊的。 Day 10 講過它的 topic key upsert,從生命週期的角度看,這等於百分之百偏向最新:同主題只留最後一筆。對技術決策這是對的(認證方案改成 JWT,舊方案留著只會誤導);對「使用者偏好的演變」這類需要歷史脈絡的場景,直接覆蓋就會丟資訊。同一個機制,換個場景就從優點變成缺點。
HermesAgent:刻意不偏向任何時間。 Day 4 講過它的 frozen snapshot:session 開始時凍結記憶,整個 session 不變。從生命週期的角度重看,這是五個系統裡唯一主動避免「新資訊優先」的,而動機竟然是省錢:記憶不動,system prompt 前綴就穩定,prompt cache 才吃得到。一條成本約束,意外造出一個「session 內所有記憶平等」的哲學。
| 系統 | 偏向什麼 | 發生在何時 |
|---|---|---|
| OpenViking | 頻率 × 時間(熱度) | 搜尋時混分 |
| agentmemory | 知識類型決定衰退速率 | 寫入時分層 |
| DeerFlow | LLM 信心分數 | 寫入時驅逐 |
| engram | 永遠最新(覆蓋) | 寫入時 upsert |
| HermesAgent | 不偏向(凍結) | session 開始 |
看完五種答案,判斷的問題可以收斂成一個:你的場景裡,「舊」代表什麼?
舊代表過時(叢集狀態、進行中的任務),要嘛用覆蓋要嘛用快速衰退;舊代表沉澱(專案慣例、使用者長期偏好),就需要分層或者乾脆不衰減;舊新混雜(多數真實場景),熱度這種用「近期有沒有被用到」代理重要性的設計最保險,因為它不刪東西,判斷錯了還有救。
順帶標一個適用邊界:這些機制全部建立在「記憶量大到需要取捨」的前提上。你的 agent 記憶只有幾十條的話,DeerFlow 那種全量注入加上限的做法就夠了,別急著搬一套衰減公式進來。
到今天,Context Engineering(這系列的 L2)的記憶三部曲完成:寫入、檢索、生命週期。剩最後一塊拼圖:對話歷史本身。記憶處理的是萃取後的知識,但窗口裡那一大坨原始對話和工具輸出,隨著輪數膨脹、每輪重複計費(Day 3 講成本物理學時的伏筆),它們怎麼辦?明天講 compaction:把歷史變小的工程,以及為什麼你的 agent 越跑越貴。