iT邦幫忙

2026 iThome 鐵人賽

DAY 12
0
AI Engineering

AI Agent 上線要想清楚的事:30 天拆解 Harness 的設計取捨系列 第 12 篇

Day 12|Memory 記住的事,過期了怎麼辦?

  • 分享至 

  • xImage
  •  

🧠 Agent 記下的 memory 會過期。寫進去時連當時的條件一起存,讀回來先看它多舊、條件還在不在;有了新說法,舊的標成已取代,別直接蓋掉。

昨天在 Day 11,我們讓摘要查得回原始證據,那些都發生在同一個任務裡。今天把時間拉長,看上次交代過的事,到了下一個 session 還該不該照做。

快速回顧一下:Day 4 說過 Session 之間預設互相看不到,要跨對話記住東西,得另外定寫入規則和有效期,今天就來補這一塊;Day 4 用來擋掉過期更新的 version 欄位,今天也會用到。Day 10 看過 Claude Code 在 session 開始時,把 CLAUDE.md 和 auto memory 一起放進模型輸入,今天打開 auto memory 看裡面存了什麼。

假設你用 Claude Code 維護一個電商 repo。三個月前 staging 很不穩,e2e 測試(開瀏覽器把結帳流程從頭點到尾)常常莫名失敗,你跟 Claude 說:「這陣子 staging 很不穩,e2e 先別跑,跑 unit test 就好。」畫面跳出一行提示,說存了一筆 memory。這是 Claude Code 的 auto memory:Claude 自己寫筆記,存在你電腦上的一個目錄,下次開 session 會讀回來。目錄裡多了兩樣東西:

~/.claude/projects/<專案>/memory/
├── MEMORY.md             ← 索引,每個 session 開始時放進模型輸入
└── feedback_testing.md   ← 這筆 memory 本身

MEMORY.md 多的那一行是:

- [測試只跑 unit test](feedback_testing.md) — 改完不跑 e2e

兩週後 staging 修好了,沒人想到要改這筆 memory。三個月後,你開了一個新的 session:「修一下 checkout 的折扣計算,改完跑測試。」Claude 改完、跑了 npm test,回報測試全過。PR 開出去,CI 上的 e2e 掛了。你問它怎麼沒跑 e2e,它說你之前交代過先別跑。這句話你早就忘了,當時那段對話的紀錄檔,Claude Code 預設 30 天後就刪掉了。

三個月前的 memory,今天照樣被拿來用

圖:三個月前 staging 不穩,交代 e2e 先別跑 → Claude 存成一筆 auto memory → staging 修好了,沒人去改 memory → 今天請它修 checkout 折扣、改完跑測試 → 索引照常載入,Agent 只跑 unit test → 回報測試全過,CI 的 e2e 掛了。這是示意,實作要照自己的工具和環境調整。

你當時說的沒錯,Claude 也照著做了,只是那句話帶著「這陣子 staging 很不穩」這個條件,今天已經不成立。這筆 memory 當初存成什麼樣子、Agent 讀到時看不看得到它多舊、有沒有機會先問一句,都可能影響這次跑了哪些測試。

下面先把記憶分類,講清楚今天談哪一塊,再看 Claude Code 的 auto memory 怎麼存、怎麼讀,接著沿著這筆 memory 走三段:寫進去時少了什麼、三個月後讀回來看不看得出過期、你給了新說法之後舊的怎麼處理,最後看自己刻 Harness 至少要存什麼。

記憶有哪幾種?今天講哪一種?

Letta(一個主打持久記憶的 Agent 框架)有篇文章主張 memory 沒辦法當成外掛裝上去:CLAUDE.md 怎麼載入、skill 的說明放在哪、compaction 之後留下什麼、互動紀錄查不查得到,都是 Harness 在決定,對過去的對話做搜尋只是其中一小塊。這些前幾天碰過一部分,先把記憶分個類,比較好說今天講哪一塊。

常見的分法來自 CoALA 論文,它把語言 Agent 的記憶分成四種。對到 Claude Code 上:

種類 存什麼 Claude Code 裡的例子 哪一天講
working memory 手上這件事正在用的資料 這個 session 的對話和工具結果 Day 4 的任務狀態、Day 8 的目前工作摘要
episodic(經歷) 以前發生過的事 session 紀錄檔,三個月前那段對話的原文 Day 11 的原始歷史
semantic(知識) 關於外界和使用者的事實 auto memory 裡的「e2e 先別跑」 今天
procedural(做法) 怎麼做事:模型本身,和程式、prompt、skill CLAUDE.md、skill Day 10 看怎麼載入,Day 30 看怎麼改

四種可以放在同一個地方,差別在誰能寫、多久有效、怎麼更新。CoALA 也提醒,讓 Agent 自己改 procedural 這一類,風險比寫 episodic 或 semantic 高很多,容易寫出 bug,也可能讓 Agent 繞過設計者的意圖。Claude Code 的兩種檔案剛好分在這條線兩邊:CLAUDE.md 是你寫的規則;Claude 自己記的放在 auto memory,你叫它「記住」什麼也是存到那裡,要寫進 CLAUDE.md 得明講「加到 CLAUDE.md」,或自己改。

今天只講 semantic 這一塊,也就是 Claude 自己寫的 auto memory,看一筆 memory 從被記下、被讀回來用,到被新說法取代。沿著開頭的情境,會碰到三個問題,發生的時間點不一樣:

問題 什麼時候發生 e2e 的例子
過期了沒(新鮮度) 拿出來用之前 staging 早就修好了,沒人告訴 Agent,「先別跑 e2e」還留在 memory 裡
這次要求和記憶,聽誰的 你這次講的跟 memory 不一樣 你這次明講「連 e2e 一起跑」,memory 寫先別跑
新說法怎麼取代舊的 你給了新說法 你說「staging 修好了,以後都跑 e2e」,舊的那筆要改掉,還是留著標成已取代?

第二個問題的規則最單純:這次講清楚了,就照這次的做,後面用一段帶過。重點在第一和第三個,一個是還沒有新說法,舊的卻可能已經不成立;一個是新說法來了,舊的要怎麼處理。Day 4 說要另外定的「有效期」和「寫入規則」,對到的就是這兩個;寫入規則還包括一開始要記什麼,三段裡先講這個。

跟 memory 有關、但今天不展開的,交給其他幾天:memory 什麼時候載入模型輸入是 Day 10;多個 Agent 分工、成果怎麼合併是 Day 13;查詢時用誰的身分、能看哪些人的資料是 Day 22;外部內容怎麼把模型帶偏是 Day 24;skill 和團隊規則怎麼改是 Day 30。

Claude Code 的 auto memory 怎麼運作?

Claude Code 的文件把跨 session 帶東西的機制分成兩種,並排比過:

CLAUDE.md auto memory
誰寫 你 Claude
寫什麼 指示和規則 從你的糾正和偏好學到的東西
範圍 專案、使用者或整個組織 一個 git repo 一份,所有 worktree 共用
什麼時候載入 每個 session 每個 session,只放索引的前 200 行或 25KB

Day 10 講的是左邊那欄怎麼進到模型輸入,今天看右邊。

auto memory 的目錄就是開頭那個 ~/.claude/projects/<專案>/memory/,<專案> 照 git repo 算,同一個 repo 底下的子目錄和 worktree 共用一份。Claude 每寫一筆,會在檔案開頭標一個 type,文件列了四種:

type 記什麼 放到電商 repo 會是
user 你的角色、專長和工作偏好 「後端工程師,前端比較不熟」
feedback 你給的糾正,和你確認過的做法 「e2e 先別跑,跑 unit test 就好」
project 進行中的工作、期限和決定,程式碼和 git 歷史看不出來的 「月底前 checkout 只修 bug,不加功能」
reference 專案外的資訊去哪裡找 「e2e 的結果看 CI 的哪個 dashboard」

程式碼看得出來的東西,像架構、檔案路徑、修過的 bug,還有 CLAUDE.md 已經寫了的,Claude 不會存。也不是每個 session 都會存,要看它判斷下次用不用得到。

讀的時候分兩層。MEMORY.md 在每個 session 開始時放進輸入,只放前 200 行或前 25KB,所以一筆一行、細節放在各自的檔案;feedback_testing.md 這種單筆的檔案,Claude 覺得需要時才用一般的讀檔工具去讀。畫面上看到 Saved 2 memories、Recalled 2 memories 這種提示,就是它在寫、在讀這個目錄。檔案都是一般的 markdown,打 /memory 可以開資料夾瀏覽、直接改或刪。

索引寫滿了也有處理。Claude 寫完 MEMORY.md,Claude Code 會量它的大小,接近上限就提醒 Claude 縮短:一筆一行、細節搬進各自的檔案、合併或刪掉過時的;超過上限,寫入照樣成功,但會回一個錯誤要它重寫,因為超過的部分下次不會載入。這個清理是看索引多長才觸發,跟每一筆寫了多久無關。

還有幾種情況,後面會用到:

情況 會怎樣
換一台電腦、在雲端跑 讀不到,auto memory 只存在這台機器上;同事的 Claude Code 也看不到你的
同一個 repo 開另一個 worktree 共用同一個目錄,兩邊都會讀、也都會寫
交給 subagent 做 文件說主對話的 auto memory 不會帶過去;我用 v2.1.280 實測,一般的 subagent 收得到 MEMORY.md 索引,內建的 Explore 收不到
session 紀錄檔放了 30 天 預設會被自動刪掉;memory 目錄不在清理範圍,會留到有人改或刪

最後,這兩種檔案對模型來說都只是 context,不是強制設定。不管 Claude 怎麼判斷都要擋下的動作,文件建議用 Day 10 提過的 PreToolUse hook。

寫進去的時候,少了什麼?

開頭那句話,存成 memory 可以長成兩種樣子。上面是情境裡 Claude 存下來的(照我用 v2.1.280 存出來的格式,省略兩個欄位),下面把條件和原話也寫進去:

只存結論
  ---
  name: feedback-testing
  description: 改完程式只跑 unit test,不跑 e2e
  metadata:
    type: feedback
    modified: 2026-06-22T03:10:00.000Z
  ---
  改完程式只跑 npm test,不要跑 npm run test:e2e。

連條件和原話一起存
  (開頭那幾欄同上)
  改完程式只跑 npm test,不要跑 npm run test:e2e。
  條件:staging 修好之前。
  原話(6/22):「這陣子 staging 很不穩,e2e 先別跑,跑 unit test 就好。」

只存結論,三個月後就沒有任何東西提醒它可能過期。

Claude Code 的 memory 檔最上面那幾欄,記的是名稱、描述、type 和寫入時間,沒有放條件的欄位,條件有沒有存,要看 Claude 寫內文時有沒有寫進去。我手上的版本還會多記一欄是哪個 session 寫的(文件沒寫這欄),可是那個 session 的紀錄檔 30 天後就刪了。三個月後,這份檔案寫了什麼,就是 Agent 和你手上全部的線索。

用 Claude Code 的話,我會在講的時候就把結束條件講出來:「staging 修好之前,e2e 先別跑。」看到存了 memory 的提示,打 /memory 打開那份檔案看一眼,條件沒寫進去就自己補。

誰說的也要記。這筆是你明講的;Claude Code 的 feedback 還包括你確認過的做法,也就是 Claude 提出、你點頭的那種。自己刻 Harness 可以分得更細:使用者明說的可以直接記;模型從幾次操作猜出來的,只能當候選,標成推測,不能寫成使用者說過;網頁、文件或工具結果裡的文字,不能自己變成 memory。我會讓寫入的工具收一段使用者原話,Harness 在這個 Session 的使用者訊息裡找得到這段話,才記成使用者明說。

範圍也是存的時候要記的。如果你當時說的是「checkout 的 e2e 先別跑」,存成「不跑 e2e」,其他模組的 e2e 也會一起跳過。Claude Code 的 memory 本來就一個 repo 一份,不會跑到別的 repo,但 repo 裡面的範圍,還是要寫進內文。一份 2026 年的研究 BenchPreS 量過這類情況:模型常把記住的偏好當成到處都適用的規則,越會照偏好做事的模型,套錯的比例越高。

三個月後讀回來,看得出它過期了嗎?

Agent 自己不會知道 staging 修好了沒。

Claude Code 在這裡做了兩件事。一件寫在文件裡:Claude 每次寫 memory 檔,Claude Code 會在檔案開頭記一個 modified,也就是寫入時間(v2.1.214 起),讓你和 Claude 讀回來時都看得出這件事有多新。另一件文件沒寫,是我實測看到的:Claude 用讀檔工具讀一份 memory 檔,工具結果前面會多一段提醒。我讀的那份是 7 天前寫的:

This memory is 7 days old. Memories are point-in-time observations, not live state — claims about code behavior or file:line citations may be outdated. Verify against current code before asserting as fact.

意思是:這份 memory 已經 7 天了,memory 記的是當時觀察到的,不是現在的狀態,講到程式行為或行號的地方可能過時,當成事實講出來之前,先對照目前的程式碼。寫完不到兩天的讀回來沒有這段。打開那個 session 的紀錄檔(~/.claude/projects/<專案>/<session>.jsonl)搜 days old 就看得到。

拿開頭的情境對一下,這兩件事幫得上忙,但不一定夠。session 開始時放進去的是 MEMORY.md 那一行索引,只有檔名和一句描述,沒有日期;Agent 看索引就照做的話,不會看到三個月這個數字。就算讀了那份檔案,提醒要它對照的是程式碼,staging 修好了沒,程式碼裡查不到,檔案裡也沒寫條件,它不知道該問什麼。

STALE 這份研究專門量這種情況:使用者之前說每天騎車上班,Agent 記了下來;幾個月後使用者說打球摔斷了腿,沒提到騎車,再請 Agent 排通勤。測過的模型裡最好的(Gemini-3.1-pro),整體也只答對 55.2%。認得出狀況變了,也不一定會照新的做:Qwen3.5-27B 被直接問「還騎車上班嗎」能答對 76%,實際排通勤時只有 39% 用上新的狀況。

Harness 能做的,是讓帶條件的舊 memory 看起來就像需要確認的東西。Claude Code 是照天數,讀單筆檔案時附上它多舊;自己刻 Harness 可以再往前一步:寫入時存了條件,組輸入時把有條件、又超過確認期限的標成「待確認」,連原話和日期一起放進去。情境裡那筆,模型讀到的差別是這樣:

session 開始時放進去的索引(Claude Code)
  - [測試只跑 unit test](feedback_testing.md) — 改完不跑 e2e

讀那份檔案時看到的(Claude Code)
  This memory is 94 days old. Memories are point-in-time observations...
  改完程式只跑 npm test,不要跑 npm run test:e2e。

組輸入時標過的(自己刻的 Harness)
  [待確認] #3 改完只跑 unit test,不跑 e2e|條件:staging 修好之前|原話:「這陣子 staging 很不穩,e2e 先別跑」|使用者明說,6/22

模型看到「待確認」、條件和三個月前的日期,比較有機會先問一句「之前說 staging 不穩先別跑 e2e,現在修好了嗎?」。有沒有真的問,要拿同一題對跑才知道。

確認期限看種類定。project 那類記的本來就常是期限和進行中的工作,我會讓它早一點問;你的角色和專長變得慢,可以久一點。「這陣子」也不要讓模型自己換算成到期日,它沒有根據可以算。

自己刻 Harness 的話,Anthropic API 有一個 memory tool:模型發出「看這個目錄」「改這個檔的哪一段」這類請求,實際存在哪、怎麼存,由你的程式決定。它的文件建議定期刪掉很久沒被讀過的 memory 檔。這條清不掉開頭那筆,它每次跑測試都會被讀一次。

如果你這次直接講了,例如「這次連 e2e 一起跑」,就照這次的做,memory 不用拿出來比。memory 也不必跟著改,這次可能只是例外,等你說「以後都…」再改。

你說「staging 修好了」,舊的那筆怎麼辦?

CI 掛了之後,你跟它說:「staging 早就修好了,以後改完都跑 e2e。」

在 Claude Code 裡,Claude 會直接改 feedback_testing.md 的內文,modified 換成今天,原本那句就不在了。文件沒提到 memory 檔會留舊版,這個目錄預設也不在任何 git repo 裡。

一個人用 Claude Code,這樣通常就夠了。做給很多使用者用的 Agent,舊的那筆有兩種處理方式。Mem0(一套給 Agent 用的記憶服務)的論文裡,新事實跟舊記憶衝突時,一般版本直接刪掉舊的;圖的版本改成把舊的關係標成失效,不實際刪除。Zep 開源的 Graphiti 也是標記:舊的那筆設上 expired_at,文章的例子是 Maria 升職,原本的「Maria 是 junior manager」被改寫成「Maria 以前是 junior manager,直到升上 senior manager」。

我會選標記。舊的那筆標成已取代、指向新的那筆,組輸入時就不會再放進去;它還留著,之後有人問「以前為什麼都不跑 e2e」答得出來,模型誤會了使用者的意思也改得回去。只有使用者明說的新說法才取代舊的,模型從「這次跑了 e2e」推測使用者改了習慣,只能存成候選。Letta 的 Context Repositories 走的是另一條路:memory 存成 git 版本,每一版都留著,多個 subagent(分出去做子任務的 Agent)各自在 worktree 裡整理,再用 git 合併。

還有一種覆蓋要擋:別人剛改過,又被拿舊的內容寫回去。auto memory 是同一個 repo 的所有 worktree 共用,你在兩個 worktree 各開一個 session,兩邊都可能去改 feedback_testing.md。Claude Code 的編輯工具有擋這件事,工具文件寫到:檔案在 Claude 讀過之後被改過,要換掉的那段文字還跟檔案現在的內容一字不差,才准改;對不上就要重讀。

我也試了整份覆寫:讓 Claude 讀完一個檔,我從外面改一行,再叫它整份寫回去,它直接收到錯誤,要它先重讀。這跟 Day 4 的 version 是同一件事,寫入時比對當初讀到的東西,變了就寫不進去。資料存在一般資料庫裡,就要自己加這個欄位。

你如果說「不要再記這個」,是另一種更新:memory 檔刪掉,之後不會再讀進來。這跟把資料刪乾淨是兩件事,那段對話的紀錄檔在被清掉之前都還在;memory 如果放進 git,GitHub 的敏感資料清理文件提醒,改寫歷史之後,clone 和 fork 裡還可能留著舊內容。「以後不會再用」和「資料已經刪掉」,產品上要分開講。

最後一件:「改完一定要跑 e2e」如果是團隊的規則,不要只放在 memory。auto memory 只在你這台機器上,同事的 Claude Code 看不到;它對模型也只是 context,照不照做沒有保證。這種規則寫進 CLAUDE.md 跟著 repo 走,再讓 e2e 沒過的 PR 合不進去。prompt 擋不住的事交給誰,Day 20 會細講。

自己的 Harness 最少要存什麼?

用 Claude Code 的話,上面講的大多靠習慣:講的時候帶條件、存完看一眼、隔一陣子開 /memory 清。自己刻 Harness,或用 memory tool 自己接儲存,就要落在資料上。沿用 e2e 這筆,至少要有下面這幾欄,少了哪一欄,前面某一段就判斷不了;第三欄對照 Claude Code 有沒有。資料放在既有的資料庫就好,不用為 memory 另外搭一套。

欄位 這個情境的值 Claude Code 裡 誰讀寫
content 改完只跑 unit test,不跑 e2e 檔案內文 寫入工具存;組輸入時放進去
type feedback 有,四種 決定多久要重新確認
quote/source 「這陣子 staging 很不穩,e2e 先別跑」/使用者明說 沒有;原本那段對話 30 天後刪掉 寫入工具照原話找不找得到來判斷;推測的另存候選
scope 這個 repo 的所有 e2e 一個 repo 一份;repo 裡的範圍要寫在內文 寫入時記;模型判斷適不適用
condition staging 修好之前 沒有,要寫在內文 寫入時記;有條件的才會被標待確認
confirmed_at 6/22 modified,但任何一次寫入都會更新它 使用者每確認一次就更新
status/superseded_by active 變成 superseded,指到新的那筆 沒有,直接改檔 更新時寫;組輸入時只放 active
version 1 變成 2 編輯工具比對檔案目前的內容 更新時比對,擋掉拿舊版本寫回來的

組輸入和更新各一個函式。memory_lines() 在每個 session 開始時跑,決定哪幾筆放進去、要不要標待確認;supersede() 處理新說法,找不到使用者原話就只存候選,舊的標成已取代和新的寫入放在同一個 transaction。

RECONFIRM_AFTER = {"feedback": timedelta(days=30),      # 每種 memory 各自定
                   "project": timedelta(days=14)}       # 沒列的種類不標

def memory_lines(memories, now):
    lines = []
    for m in memories:
        if m.status != "active":                         # 已取代、撤回的不放
            continue
        limit = RECONFIRM_AFTER.get(m.type)
        stale = m.condition and limit and now - m.confirmed_at > limit
        tag = "待確認" if stale else "有效"
        lines.append(f"[{tag}] #{m.id} {m.content}|條件:{m.condition or '無'}"
                     f"|原話:{m.quote}|{m.source},{m.confirmed_at:%m/%d}")
    return lines

def supersede(old_id, read_version, new_content, quote, user_messages, now):
    if not any(quote in msg for msg in user_messages):   # 找不到使用者原話
        return save_candidate(old_id, new_content)       # 推測的只當候選
    with transaction():
        old = load(old_id)
        if old.version != read_version:                  # 讀了之後有人改過
            return {"status": "conflict"}                # 重讀再決定
        new = insert(type=old.type, scope=old.scope, content=new_content,
                     quote=quote, source="使用者明說", confirmed_at=now)
        update(old_id, status="superseded", superseded_by=new.id,
               version=old.version + 1)
    return {"status": "ok", "id": new.id}
誰呼叫 什麼時候 結果
Harness 組輸入的地方呼叫 memory_lines() 新 session 開始,組第一輪輸入時 已取代、撤回的不放;#3 有條件又超過 30 天沒確認,標成待確認放進去
模型透過 memory 工具呼叫 supersede() 你說「staging 早就修好了,以後改完都跑 e2e」 原話找得到:#3 標成已取代、新的寫入,版本從 1 變 2;找不到就存成候選
另一個 worktree 的 session 呼叫 supersede() 同一段時間也想改這筆 帶著它讀到的版本 1 來寫,這時已經是 2,寫入被擋下,要重讀

模型不用自己帶版本號:Harness 在組輸入時記下這個 session 讀到的是第幾版,memory 工具被呼叫時由它填進 read_version。

記下條件、用前確認、舊的標成已取代

圖:寫入時連原話、誰說的、條件一起存 → 找不到使用者原話的只當候選 → 組輸入時跳過已取代和撤回的 → 有條件又太久沒確認的標成待確認 → 使用者給了新說法,舊的標成已取代 → 寫回時比對版本,擋掉拿舊版本寫的。這是示意,實作要照自己的工具和環境調整。

可以先從哪裡做起?

假設你已經做到 Day 11:同一個任務裡,摘要查得回原文。現在要讓 Agent 跨 session 記住事情,我會照這個順序加:

第一步,看得到 Agent 記了什麼、什麼時候記的。 用 Claude Code 的話這一步已經有了:看到存了 memory 的提示就打 /memory 點開看,隔一陣子把整個資料夾翻一次。自己的 Harness 就讓每筆 memory 存成看得懂的文字、帶寫入時間,使用者查得到、改得掉。

第二步,帶條件的,連條件和原話一起存,讀的時候標出來。 用 Claude Code,講的時候就把結束條件講出來,存完確認內文有寫。自己的 Harness 照上面的欄位存 condition 和 confirmed_at,組輸入時標待確認,再拿「修個 bug、沒說要跑哪些測試」這類題目,對跑有標和沒標兩個版本,看 Agent 會不會先問。標了不保證它一定會問,要量過才知道。

第三步,更新走自己的工具,比對版本。 舊的標成已取代、新的寫入,放在同一個 transaction,再比對版本。Claude Code 的編輯工具已經會比對檔案目前的內容,只是舊的不會留下來。

一定要照做的規則,不管做到哪一步,都寫進 CLAUDE.md,再用 CI 或 hook 擋,不要只放在 memory。

一個人用 Claude Code、memory 只有十幾筆的話,做到第一步、講話時記得帶條件就夠了,內建的已經記了寫入時間,讀回來也會提醒多舊。Agent 要給很多使用者用,或有好幾個 session、背景工作同時在寫,才需要第三步的版本比對和留下舊版。

多個 Agent 分工時,subagent 看不到主對話講過的話,要交代的東西怎麼帶過去,Day 13 接著看;查詢時用誰的身分、能看哪些人的資料是 Day 22 的題目;外部內容怎麼把模型帶偏是 Day 24;skill 和團隊規則怎麼經過驗證再更新,Day 30 再談。

你可以怎麼確認自己讀懂了?

回到 e2e 的例子,可以試著問自己:Claude Code 讀那份 memory 時,已經附上「這份 memory 94 天了」,為什麼 Agent 還是可能只跑 unit test?你說「staging 早就修好了,以後都跑 e2e」,Claude 直接把檔案改掉、舊的就沒了,這樣有問題嗎?

第一題,那段提醒要它對照的是程式碼,staging 修好了沒,程式碼裡看不到;檔案裡也沒寫「staging 修好之前」這個條件,它不知道該問什麼。session 開始時放進去的索引那一行,更是連日期都沒有。第二題看是誰在用。一個人用 Claude Code,舊的沒了通常無所謂;做給很多使用者用的 Agent,改寫之後就查不到「以前為什麼不跑、哪天改的」,模型誤會了也救不回來,標成已取代留著,兩件事都做得到。

memory 要連當時的條件一起記,用之前先看它多舊、條件還在不在,換新的時候別直接蓋掉。

明天換一個分工問題:資料和狀態都有了,多找幾個 subagent 一起做,真的會比較快嗎?我們會把派工、等待、合併和驗證的成本一起看。

參考資料

查核日期:2026-09-26。Claude Code 的行為照官方文件;讀回 memory 時附上的天數提醒、整份覆寫被擋、memory 檔的欄位格式、subagent 收不收得到 MEMORY.md 索引,是我用 v2.1.280 實測的。Letta 的 Context Repositories 是 2026-02-12 介紹 Letta Code 的文章,Why Memory Isn't a Plugin 是 2026-04-03 的文章。STALE 和 BenchPreS 的數字是論文裡那批題目和模型量出來的,換成自己的任務要重新量。電商 repo、e2e 那句話和日期是情境裡編的。

  1. Letta|Why Memory Isn't a Plugin:說明檔怎麼載入、skill 說明放在哪、compaction 之後留下什麼、互動紀錄查不查得到,都由 Harness 決定;對過去的對話做搜尋只是 memory 的一小塊。
  2. Sumers et al.|Cognitive Architectures for Language Agents (CoALA):working、episodic、semantic、procedural 四種記憶的定義,和「寫入 procedural 比寫入 episodic、semantic 風險高很多」的說法。
  3. Claude Code|How Claude remembers your project:CLAUDE.md 由人寫、auto memory 由 Claude 寫,兩者對模型都只是 context;叫 Claude 記住的存進 auto memory;目錄一個 git repo 一份、worktree 共用、只在這台機器;四種 type 和不存的東西;MEMORY.md 載入前 200 行或 25KB,接近上限時提醒合併或刪掉過時的,單筆檔案需要時才讀;modified 寫入時間(v2.1.214 起);文件寫不帶給 subagent;紀錄檔清理不含 memory 目錄。
  4. Claude Code|Explore the .claude directory:session 紀錄檔等檔案超過 cleanupPeriodDays 自動刪除,預設 30 天。
  5. BenchPreS|A Benchmark for Context-Aware Personalized Preference Selectivity of Persistent-Memory LLMs:模型常把記住的偏好當成到處適用的規則,偏好遵守得越強的模型套錯越多;測的是對第三方溝通的情境。
  6. STALE|Can LLM Agents Know When Their Memories Are No Longer Valid?:騎車通勤和摔斷腿的例子、最佳模型整體 55.2%、Qwen3.5-27B 認得出變化 76.0% 但照新狀況做只有 39.0%。
  7. Anthropic|Memory tool:memory tool 在應用程式端執行,模型發出 view、create、str_replace 等指令,存在哪由應用程式決定;安全建議包括定期刪掉很久沒被讀過的 memory 檔。
  8. Mem0|Building Production-Ready AI Agents with Scalable Long-Term Memory:更新階段的 ADD、UPDATE、DELETE、NOOP,衝突時一般版刪掉舊記憶,圖的版本改成標記失效。
  9. Zep|Beyond Static Graphs: Engineering Evolving Relationships:Graphiti 碰到矛盾的新事實時,舊的那筆設上 expired_at,不刪除;Maria 升職的例子。
  10. Letta|Introducing Context Repositories:memory 存成 git 版本,多個 subagent 在各自的 worktree 整理,再用 git 合併、處理衝突。
  11. Claude Code|Tools reference:Edit 在檔案讀過之後被改過時,要換掉的文字還跟目前內容一字不差才會套用,否則要重讀。整份覆寫被擋是我實測的,文件沒寫。
  12. GitHub|Removing sensitive data from a repository:改寫 git 歷史之後,clone、fork 和其他副本裡還可能留著舊內容。

上一篇
Day 11|Compaction 壓完,原文去哪了?
下一篇
Day 13|多開幾個 Subagent,會比較快嗎?
系列文
AI Agent 上線要想清楚的事:30 天拆解 Harness 的設計取捨 共 13 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言