Memory System
System HardeningKeep Only What Survives Sessions|414 LOC|5 tools
Memory gives direction; current observation gives truth.
s00 > s01 > s02 > s03 > s04 > s05 > s06 > s07 > s08 > [ s09 ] > s10 > s11 > s12 > s13 > s14 > s15 > s16 > s17 > s18 > s19
不是所有資訊都該進入 memory;只有跨會話仍然有價值的資訊,才值得留下。
這一章在解決什麼問題
如果一個 agent 每次新會話都完全從零開始,它就會不斷重複忘記這些事情:
- 使用者長期偏好
- 使用者多次糾正過的錯誤
- 某些不容易從程式碼直接看出來的專案約定
- 某些外部資源在哪裡找
這會讓系統顯得“每次都像第一次合作”。
所以需要 memory。
但先立一個邊界:memory 不是什麼都存
這是這一章最容易講歪的地方。
memory 不是“把一切有用資訊都記下來”。
如果你這樣做,很快就會出現兩個問題:
- memory 變成垃圾堆,越存越亂
- agent 開始依賴過時記憶,而不是讀取當前真實狀態
所以這章必須先立一個原則:
只有那些跨會話仍然有價值,而且不能輕易從當前倉庫狀態直接推出來的資訊,才適合進入 memory。
建議聯讀
- 如果你還把 memory 想成“更長一點的上下文視窗”,先回
s06-context-compact.md,重新確認 compact 和長期記憶是兩套機制。 - 如果你在
messages[]、摘要塊、memory store 這三層之間開始讀混,建議邊看邊對照data-structures.md。 - 如果你準備繼續讀
s10,最好把s10a-message-prompt-pipeline.md放在旁邊,因為 memory 真正重要的是它怎樣重新進入下一輪輸入。
先解釋幾個名詞
什麼是“跨會話”
意思是:
- 當前對話結束了
- 下次重新開始一個新對話
- 這條資訊仍然可能有用
什麼是“不可輕易重新推導”
例如:
- 使用者明確說“我討厭這種寫法”
- 某個架構決定背後的真實原因是合規要求
- 某個團隊總在某個外部看板裡跟蹤問題
這些東西,往往不是你重新掃一遍程式碼就能立刻知道的。
最適合先教的 4 類 memory
1. user
使用者偏好。
例如:
- 喜歡什麼程式碼風格
- 回答希望簡潔還是詳細
- 更偏好什麼工具鏈
2. feedback
使用者明確糾正過你的地方。
例如:
- “不要這樣改”
- “這個判斷方式之前錯過”
- “以後遇到這種情況要先做 X”
3. project
這裡只儲存不容易從程式碼直接重新看出來的專案約定或背景。
例如:
- 某個設計決定是因為合規而不是技術偏好
- 某個目錄雖然看起來舊,但短期內不能動
- 某條規則是團隊故意定下來的,不是歷史殘留
4. reference
外部資源指標。
例如:
- 某個問題單在哪個看板裡
- 某個監控面板在哪裡
- 某個資料庫在哪個 URL
哪些東西不要存進 memory
這是比“該存什麼”更重要的一張表:
| 不要存的東西 | 為什麼 |
|---|---|
| 檔案結構、函式簽名、目錄佈局 | 這些可以重新讀程式碼得到 |
| 當前任務進度 | 這屬於 task / plan,不屬於 memory |
| 臨時分支名、當前 PR 號 | 很快會過時 |
| 修 bug 的具體程式碼細節 | 程式碼和提交記錄才是準確資訊 |
| 金鑰、密碼、憑證 | 安全風險 |
這條邊界一定要穩。
否則 memory 會從“幫助系統長期變聰明”變成“幫助系統長期產生幻覺”。
最小心智模型
conversation
|
| 使用者提到一個長期重要資訊
v
save_memory
|
v
.memory/
├── MEMORY.md # 索引
├── prefer_tabs.md
├── feedback_tests.md
└── incident_board.md
|
v
下次新會話開始時重新載入
這一章最關鍵的資料結構
1. 單條 memory 檔案
最簡單也最清晰的做法,是每條 memory 一個檔案。
---
name: prefer_tabs
description: User prefers tabs for indentation
type: user
---
The user explicitly prefers tabs over spaces when editing source files.
這裡的 frontmatter 可以理解成:
放在正文前面的結構化後設資料。
它讓系統先知道:
- 這條 memory 叫什麼
- 大致是什麼
- 屬於哪一類
2. 索引檔案 MEMORY.md
最小實現裡,再加一個索引檔案就夠了:
# Memory Index
- prefer_tabs: User prefers tabs for indentation [user]
- avoid_mock_heavy_tests: User dislikes mock-heavy tests [feedback]
索引的作用不是重複儲存全部內容。
它只是幫系統快速知道“有哪些 memory 可用”。
最小實現步驟
第一步:定義 memory 型別
MEMORY_TYPES = ("user", "feedback", "project", "reference")
第二步:寫一個 save_memory 工具
最小引數就四個:
namedescriptiontypecontent
第三步:每條 memory 獨立落盤
def save_memory(name, description, mem_type, content):
path = memory_dir / f"{safe_name}.md"
path.write_text(frontmatter + content)
rebuild_index()
第四步:會話開始時重新載入
把 memory 檔案重新讀出來,拼成一段 memory section。
第五步:把 memory section 接進系統輸入
這一步會在 s10 的 prompt 組裝裡系統化。
memory、task、plan、CLAUDE.md 的邊界
這是最值得初學者反覆區分的一組概念。
memory
儲存跨會話仍有價值的資訊。
task
儲存當前工作要做什麼、依賴關係如何、進度如何。
plan
儲存“這一輪我要怎麼做”的過程性安排。
CLAUDE.md
儲存更穩定、更像長期規則的說明文字。
一個簡單判斷法:
- 只對這次任務有用:
task / plan - 以後很多會話可能都還會有用:
memory - 屬於長期系統級或專案級固定說明:
CLAUDE.md
初學者最容易犯的錯
錯誤 1:把程式碼結構也存進 memory
例如:
- “這個專案有
src/和tests/” - “這個函式在
app.py”
這些都不該存。
因為系統完全可以重新去讀。
錯誤 2:把當前任務狀態存進 memory
例如:
- “我現在正在改認證模組”
- “這個 PR 還有兩項沒做”
這些是 task / plan,不是 memory。
錯誤 3:把 memory 當成絕對真相
memory 可能過時。
所以更穩妥的規則是:
memory 用來提供方向,不用來替代當前觀察。
如果 memory 和當前程式碼狀態衝突,優先相信你現在看到的真實狀態。
從教學版到高完成度版:記憶系統還要補的 6 條邊界
最小教學版只要先把“該存什麼 / 不該存什麼”講清楚。
但如果你要把系統做到更穩、更像真實工作平臺,下面這 6 條邊界也必須講清。
1. 不是所有 memory 都該放在同一個作用域
更完整系統裡,至少要分清:
private:只屬於當前使用者或當前 agent 的記憶team:整個專案團隊都該共享的記憶
一個很穩的教學判斷法是:
user型別,幾乎總是privatefeedback型別,預設private;只有它明確是團隊規則時才升到teamproject和reference,通常更偏向team
這樣做的價值是:
- 不把個人偏好誤寫成團隊規範
- 不把團隊規範只鎖在某一個人的私有記憶裡
2. 不只儲存“你做錯了”,也要儲存“這樣做是對的”
很多人講 memory 時,只會想到糾錯。
這不夠。
因為真正能長期使用的系統,還需要記住:
- 哪種不明顯的做法,使用者已經明確認可
- 哪個判斷方式,專案裡已經被驗證有效
也就是說,feedback 不只來自負反饋,也來自被驗證的正反饋。
如果只存糾錯,不存被確認有效的做法,系統會越來越保守,卻不一定越來越聰明。
3. 有些東西即使使用者要求你存,也不該直接存
這條邊界一定要說死。
就算使用者說“幫我記住”,下面這些東西也不應該直接寫進 memory:
- 本週 PR 列表
- 當前分支名
- 今天改了哪些檔案
- 某個函式現在在什麼路徑
- 當前正在做哪兩個子任務
這些內容的問題不是“沒有價值”,而是:
- 太容易過時
- 更適合存在程式碼、任務板、git 記錄裡
- 會把 memory 變成活動日誌
更好的做法是追問一句:
這裡面真正值得長期留下的、非顯然的資訊到底是什麼?
4. memory 會漂移,所以回答前要先核對當前狀態
memory 記錄的是“曾經成立過的事實”,不是永久真理。
所以更穩的工作方式是:
- 先把 memory 當作方向提示
- 再去讀當前檔案、當前資源、當前配置
- 如果衝突,優先相信你剛觀察到的真實狀態
這點對初學者尤其重要。
因為他們最容易把 memory 當成“已經查證過的答案”。
5. 使用者說“忽略 memory”時,就當它是空的
這是一個很容易漏講的行為邊界。
如果使用者明確說:
- “這次不要參考 memory”
- “忽略之前的記憶”
那系統更合理的處理不是:
- 一邊繼續用 memory
- 一邊嘴上說“我知道但先忽略”
而是:
在這一輪裡,按 memory 為空來工作。
6. 推薦具體路徑、函式、外部資源前,要再驗證一次
memory 很適合儲存:
- 哪個看板通常有上下文
- 哪個目錄以前是關鍵入口
- 某種專案約定為什麼存在
但在你真的要對使用者說:
- “去改
src/auth.py” - “呼叫
AuthManager” - “看這個 URL 就對了”
之前,最好再核對一次。
因為命名、路徑、系統入口、外部連結,都是會變的。
所以更穩妥的做法不是:
memory 裡寫過,就直接複述。
而是:
memory 先告訴我去哪裡驗證;驗證完,再給使用者結論。
教學邊界
這章最重要的,不是 memory 以後還能多自動、多複雜,而是先把儲存邊界講清楚:
- 什麼值得跨會話留下
- 什麼只是當前任務狀態,不該進 memory
- memory 和 task / plan / CLAUDE.md 各自負責什麼
只要這幾層邊界清楚,教學目標就已經達成了。
更復雜的自動整合、作用域分層、自動抽取,都應該放在這個最小邊界之後。
學完這章後,你應該能回答
- 為什麼 memory 不是“什麼都記”?
- 什麼樣的資訊適合跨會話儲存?
- 為什麼程式碼結構和當前任務狀態不應該進 memory?
- memory 和 task / plan / CLAUDE.md 的邊界是什麼?
一句話記住:memory 儲存的是“以後還可能有價值、但當前程式碼裡不容易直接重新看出來”的資訊。