AI Workflow · part 11
[Dev Workflow] 退役 AI agent 的記憶系統:doctrine 跟 runtime 漂開時的三個暗坑
❯ cat --toc
TL;DR
退役一個看起來沒用的舊記憶資料夾,估半小時。它沒死——我第一個看的鏡像 mtime 是凌晨 2:30,幾小時前才被寫過。連踩三坑,同源:白紙 doctrine 早跟實際在跑的 runtime 漂開。① 那 352 檔不是過時前身,是 407 檔 canonical memory 的現役鏡像(知識庫再蒸餾成 59),箭頭我讀反了。② doctrine 說『有 git 備份』是假的——hook commit 的是別的資料夾,最該保的行為準則筆記零雲端副本。③ 從我筆電看只有兩個 peer,從 hub 看是四端星型;刪掉看得到的兩端,hub 半夜會從你看不到的兩端 re-sync 回來。⚠️ 治理招:產出者不能自己放行,終閘一定是另一方拿真實狀態重驗。
白話版:清一個看起來沒用的舊倉庫
你要清掉一個看起來沒用的舊倉庫。規劃上這是半小時的雜活:確認它真的被新系統取代了,關燈、上鎖、走人。
結果我一走進去,燈還亮著,裡面的帳本凌晨兩點半還有人在寫字。
三件事讓我差點闖禍。第一,我以為這是一疊舊帳,其實它是總帳本的即時副本——每寫一筆總帳,這裡就同步抄一份。我把因果讀反了:不是它要被淘汰,是它一直在忠實抄寫。第二,規章白紙黑字寫著「這批帳另有備份」,我信了;真的去翻才發現,備份的是隔壁那疊,而且偏偏漏掉最重要、最難重寫的那幾張。第三,我站在自己這間分店,櫃檯只顯示兩條對外連線,看起來關掉這兩條就沒事了;但總倉其實連著四間分店,每間只跟總倉通、彼此不通。我只關掉看得到的兩間,總倉會在半夜把倉庫原封不動補回來——像那扇門從來沒被拆過。
串起這三件事的是同一句話:一個「系統」對自己的描述,會慢慢跟現實脫節。說明書上寫「已淘汰」「有備份」「只有兩條線」,每一句當年都對,後來悄悄變成不對,卻沒有人回頭改。它不是故意騙你,是它自己跟自己對不上了——所以你要繞到中央總倉,親眼核對它真實的樣子,而不是照單全收任何一台機器對自己的描述。
還有一條規矩貫穿全場:沒有人可以自己簽字說「我這邊沒問題」。要另一個人拿著真帳去對,才算數。那天下午,兩次是機器自己喊停、不肯硬幹,才擋下我差點犯的錯——比任何一句「搞定了」都值錢。
前言
退役一個系統,聽起來像關掉一台舊伺服器:拔電、確認沒人在用、收工。真正動手才知道,難的不是拔電,是搞清楚到底誰還在用它。
這是 AI Workflow 系列 的 Part 11。Part 9 講怎麼把 AI agent 的 live state 外化到系統外面,Part 10 講怎麼外化任務;這篇往下挖一層,挖到記憶本身。
沒人事先警告你的是:一旦你把記憶做成一個「系統」,它對自己的描述就會開始跟實際在跑的東西脫節——舊說法留在那裡沒人改,新狀態又跟舊筆記不同步。它會告訴你它退役了、它有備份、它只連兩台機器——那天,這三句話全是錯的。
退役的資料夾其實還活著:凌晨 2:30 還在被寫
任務單看起來很無害:「那個舊的 shared-memory 資料夾,應該被知識庫取代了吧?是的話就讓它退場。」一行字,估半小時。
我第一個動作是看它還有沒有在呼吸。挑了我 running log 的那份鏡像,看 mtime——當天凌晨 2:30。有東西幾小時前才寫過這個「叫我埋掉」的資料夾。(那杯咖啡我還沒喝完。)半小時的清理,當場變成一場拓撲調查。
腦裡的直覺讀法是這樣:資料夾 352 檔,精選知識庫只有 59 檔,所以是知識庫取代了它、還有 293 檔沒遷完。這讀法把整個層級搞反了。那 352 檔不是過時的前身,是我 canonical memory(407 檔)的現役單向鏡像——一個 hook 每次寫檔就 re-sync 一次,再經 sync daemon 擴散到別台機器。知識庫不是來取代它的,是把它當上游「吃」進去、蒸餾成那 59 檔。
所以 352 對 59 不是什麼遷移欠帳,是「全量鏡像」對「精選蒸餾」,箭頭我一開始就讀反了。指紋就是 mtime:真的死掉的資料夾,時戳會很舊;這個幾小時前才被寫過,它明明還在幹活。拿 comm 去跟 canonical 一比,鏡像零獨有內容——唯一 6 個獨有檔是 handoffs 的二次副本。結論很乾脆:退它不會丟知識,但退錯,可能弄垮還在讀它的東西。
大家都以為有的那份備份根本不存在:hook commit 的是別的資料夾
這坑最會痛。
我自己白紙寫的 doctrine 明明白白寫著:memory 目錄「已經有 git hook 自動 commit」。我信了自己寫的字。規劃退役時順手去查——hook 確實在,但它 commit 的是「另一個」資料夾:那份鏡像,不是 canonical memory 本體。
更慘的是,那份鏡像剛好設定排除一整類檔案——就是定義我要 agent 怎麼工作的那些行為準則筆記,整個系統裡最難重現的東西。真實狀態是:canonical memory 自己沒有 git、沒有 Time Machine、沒有任何備份 job。我最不想丟的那一類,完全沒有雲端副本,只靠一條每天 rsync 到另一台機器的本地備份撐著——離「全沒了」只差一個節點掛掉。
doctrine 的宣稱曾經是真的,後來悄悄不再是真的,而沒有人真的從備份還原過一次、去發現這條路早就斷了。這就是任何備份系統最慘的失效模式:不是「沒備份」,是「大家都以為有備份」。一條描述你系統的規則有它的時效;你不去驗它,你就不是有備份——你只是有「一句講備份的話」。
從我筆電只看得到半張拓撲:兩個 peer,hub 上卻是四端星型
要不是一個 agent 停了下來,我會直接踩進去。
我把 transport 拆除派成一張工單。跑到一半,executor 撞上紅線、停住沒硬做——它看到的拓撲跟工單對不上。
從我筆電看,sync daemon 回報兩個 peer:一台 NAS,加一台 lastSeen 是 Unix epoch 的機器(從沒連上的鬼)。兩個 peer、一個鬼,拆掉這兩端就完事——spoke 視角是這樣告訴我的。hub 講的是另一個故事:讀 NAS 自己的 config,這資料夾分享在四台活機器組成的星型上——我筆電、一台 Mac mini、當 hub 的 NAS 本身、還有我那台 always-on 的 agent 機——每台只連 hub、彼此不連。站在任何一個 spoke 上,你看不到其他 spoke;daemon 只給你看你自己那一條邊。
而且 sync 的 ignore 檔(.stignore)是 per-device、不會傳播——我在一台上設的排除,在別台等於沒設。

你刪掉看得到的兩端,hub 半夜從你看不到的兩端補回來
具體會發生什麼:你把看得到的兩端刪掉,hub 很開心地從你看不到的兩端 re-sync 回來。
我手上有證據——agent 機自己的 sync log 裡,一個檔在 03:15:14 被刪、03:15:42 又回來。這種星狀的連法會自己把你戳的洞癒合。唯一安全的拆法,是先從 hub 把每一條 spoke 測繪出來,再一起移除。
這招通用到任何 hub-and-spoke 架構:message queue、replica、load balancer 後面一整排機器,都一樣。你機器上的 daemon 不是整個系統的地圖,它只是「你這一條邊」的地圖。
產出者不能驗自己的工:我採信 AI 稽核的診斷、丟掉它一半的處方
回頭看第三坑真正救我的是什麼——executor「停了下來」,不信自己那張計畫。這不是走運,是串起整篇的那條規則。
其實幾小時前,我才從另一個方向學過同一課。我讓一個 AI CLI 對我整套 agent setup 做唯讀稽核。它回了一份很有份量的報告:critical findings、提議蓋一個叫 agentctl 的控制面、再分幾步把它補起來。我第一反應是把報告當藍圖、直接開蓋。
我沒有。大半處方撞上一個稽核者看不到的 constraint:我自己筆記裡有明確的 operator 規則——這系統要保持輕量、容忍小落差、別去蓋一座 ship 不出東西的工廠。稽核者從沒讀過那些筆記,所以它開的藥系統性地偏重。我採信它的診斷、丟掉一半的處方——reuse 我已經有的那幾個東西(ticket、handoff、evaluator、review queue、知識庫),不另立一個平行的 task database。
兩個 AI 各對一半:那個我自認「已修」的矛盾,其實活了九天
同一回合,它回頭抓出我推理裡四個事實錯誤——包括我上一輪一個自我認證的宣稱(「canonical 的矛盾已經修好了」)其實是假的。那矛盾活了九天,因為推翻它的那個決策只改了頂層文件,從沒回頭在那張舊筆記上貼個 banner。我們各對一半、兩半剛好互補。
治理規則講白就是:產出者不能驗自己的高風險工。一份稽核報告可能很有自信地說某個修復完成了,其實根本沒發生;一份 doctrine 會告訴你有備份;一個 agent 會回你「done」。這些全都不是證據,只是自述——終閘一定得是另一方,拿真實狀態重驗。
診斷和處方可以拆開:你可以採信別人觀察到的事實,同時打回他想蓋的東西。而當「補一個治理缺口」的提案變成「蓋一整個新系統」,通常該聽 operator 那條規則的——reuse 勝過 build,因為每多加一層,就多一個會跟自己 doctrine 漂開的東西。
現在架構長這樣:一個源頭、一層蒸餾、一份真的異地副本
終態不複雜,這正是重點。
canonical memory 在一個地方,現在有了自己的版控,加一份私有的異地副本——包含那些以前完全沒備份的行為準則筆記。知識庫坐在它上面,當精選蒸餾層;檢索跑在這兩者之上,靠搜尋加一個小 graph。
舊的四端鏡像是封存、不是刪除,放在觀察期裡晾著,萬一還有我沒測繪到的東西靠它。退役流程我拆成幾個可回頭的步驟:先拉掉檢索源、再加異地備份、再一台一台拆 transport,最後觀察幾週,才真的刪。整條路沒有一步是回不去的。

收穫
最花時間的地方:不是拆除,是測繪
時間全花在發現這系統對自己的每一句自述都是錯的:資料夾沒死、備份不在、peer list 只有一半真相。真實拓撲一上紙,實際退役就純機械了。
可搬走的診斷
叫任何東西「死了」之前,先看 mtime。信任一份備份之前,先把 restore 從頭到尾跑一遍——一份你從沒 restore 過的備份,是傳言。hub-and-spoke 的系統要從 hub 測繪;spoke 視角是你那條邊,不是整張圖。把每一個「done、fixed、backed up」當成待驗的宣稱,不是待歸檔的事實。
通用原則
記憶一旦變成系統,它對自己的描述就會漂移、過時——治理就是不把系統的自述當事實,每次都回頭核對真實狀態。從 hub 驗、留一份真的異地副本、永遠別讓產出者自己放行。那天下午兩次 agent 急停(一次踩到 secret-scanner 的引線、一次拓撲對不上)比任何一句「done」都值錢。
收尾:碰它之前,先問這五個問題
- 它真的死了嗎?——碰之前先看 mtime、跟 canonical 對一次 diff。
- 備份是真的嗎?——把 restore 從頭到尾跑一遍;一行 doctrine 不是備份。
- 拓撲長怎樣?——從 hub 測繪,不是你面前這台機器。
- 可逆分階段退——檢索源 → 異地副本 → transport 一台一台拆。
- 留觀察期再刪——封存、別刪,直到沒有東西在哀嚎。
還有一條蓋在全部上面:產出者不能自己放行。 換另一方拿證據重驗,不是拿報告。
常見問題
- 怎麼安全退役、刪掉 AI agent 記憶系統的一部分?
- 先確認它是不是真的退役了:看 mtime、跟你的 canonical 來源對一次 diff,確定沒有東西還在寫它、也沒有獨有內容。然後分階段、可逆地退——先拉掉檢索源、加一份異地備份、再一台一台拆掉同步、最後留幾週觀察期才真的刪。每一步都要能回頭。
- 為什麼在一台機器上刪掉同步資料夾,它沒有真的消失?
- 因為它多半是 hub-and-spoke 拓撲裡的一個 spoke。你在自己那台機器上刪掉檔案,但中央的 hub 還連著其他你看不到的 spoke,下一輪同步就把檔案原封補回來。要真的移除,得先從 hub 把每一條 spoke 測繪出來、一起拆,而不是只刪你面前這台。
- 什麼是 doctrine 跟 runtime 的漂移?
- doctrine 是你白紙寫下、描述系統該怎麼運作的規則;runtime 是它實際在跑的樣子。漂移就是兩者不知不覺分了岔——例如 doctrine 說『memory 有 git 備份』,但實際上 hook 備份的是另一個資料夾。每一句 doctrine 都有它的時效;你不回頭驗,它就會悄悄過期。
- 兩個 AI agent 互審時,誰有終審權?
- 另一方,不是產出者自己。產出者——不管是一份 AI 稽核報告、一份 doctrine、還是回報 done 的 agent——都可能很有自信地回報一個根本沒發生的結果。終審權要交給另一個角色,拿真實狀態去重驗。你可以採信對方的診斷,同時打回他想蓋的東西。
接著讀
- 2026-07-12[Dev Workflow] 交辦 AI 工程任務:交出去的單位是一張工單檔,不是一段對話
交辦 AI 工程任務,交出去的不是一段對話,是一張工單檔。這篇講我怎麼把任務寫成自足工單(目標/步驟/機器可驗收/紅線)、detached 背景派工給 Codex、用三個 flag 和一個看門狗擋掉永久卡死,以及為什麼收到完工報告不等於做完——報告是 claim,驗收重跑才是 evidence。
- 2026-07-11[Dev Workflow] 額度斷在半路:讓 Claude Code 跟 Codex 交接任務的 handoff 協議
額度斷在任務半路,蒸發的不是知識庫,是這個任務的 live state:做到哪、排除了哪些死路、下一步跑哪個命令。這篇講我怎麼把 state 外部化成一個 handoff 檔,讓 Claude Code 跟 Codex 經 symlink 讀寫同一份、互相接手彼此做一半的活——以及用 hook 上鎖時踩到、又修掉的一個 false-takeover bug。
- 2026-05-19[Claude Code] 規則我會跳過,hook 我跳不過 — 我替自己裝了一個發文閘
我有一條「發文前要查證」的規則,還是寫了三次說錯。問題不在規則,在它放在哪一層。這篇講我怎麼把它從 skill 升級成 hook — 一段守在「按下送出」那一刻的小程式,沒查證連嘗試都不准。
- 2026-05-05[Skill] 我的繁中不夠台 — zhtw-mcp 掃 72 篇文章修了 128 處陸用詞
sysprog21/zhtw-mcp 把繁中規則編譯成執行檔。掃 ai-muninn 全部 72 篇繁中文章三輪修了 128 處陸用詞,但真正的收穫不是修了多少 — 是發現我的盲點不是「不知道台灣怎麼說」,是「碰到陸用詞時預設不會主動懷疑」。
不想錯過新文章?
訂閱我確保不漏接!
隨時一鍵退訂。