我把 repo 做成 OKF bundle,讓 AI agent 不再失憶——然後它差點害我漏掉一個 bug
這個網站是我用 Claude Code 跟 Codex 一塊一塊疊出來的。想到什麼就請它們加什麼,很快。但有一天我意識到一件事:它們每次來,都不知道前面做過什麼。
不是它們笨,是它們沒有記憶。每開一個新 session 就是冷啟動——不可能每寫一篇文章就回頭重讀整個 repo、爬一遍 git。久了,它們會重猜架構,甚至跟前一版的自己打架。
剛好我最近在研究 Google 的 OKF(Open Knowledge Format)——一種給 AI agent 用的、結構化的 markdown 知識格式。我心想:那我乾脆把這個 repo 的腦,做成一個 OKF bundle。做完我沒有直接相信它有用,我做了個實驗。結果它救了我一次,也差點害我一次。
我的網站沒有人在管記憶
問題不是「文件不夠」,而是「知識沒有被放在 agent 會讀、也會維護的地方」。架構為什麼這樣設計、有哪些踩過的雷、哪些是刻意的決策——這些散落在 commit 訊息、我的腦袋、還有我們過去某次對話裡。下一個 session 一律看不到。
結果就是:agent 每次都要重新爬 code 重建心智模型,慢又貴;碰到 code 裡看不出來的決策(例如某個坑當初是用平台設定解的,不是改 code),它根本無從得知,很可能往錯的方向修。
我給 repo 一個腦:一個 OKF bundle
OKF 的核心很簡單:一個目錄的 markdown 檔,每個檔是一個概念,開頭用 YAML frontmatter 標 type(concept/howto/reference/decision),概念之間用普通 markdown link 連成一張知識圖。agent 從 index 出發、沿著連結走訪,而不是亂搜。
我在 repo 開了一個 /knowledge 目錄,把這幾週真的做過的東西各寫成一個節點:SSR 雙渲染器、文章資料模型、系列文章系統、i18n、資料快照管線、部署方式,還有踩過的雷。內容都是真的,不是憑空生成的。
但這裡有個關鍵,也是我最想強調的:bundle 不是魔法。光有它,agent 不會自己去讀、去更新。我把「動工前先讀相關節點、改完後更新它」的紀律,寫進 agent 預設就會載入的入口檔(AGENTS.md 給 Codex、CLAUDE.md 給 Claude Code)。有人讀、有人更新,這份記憶才活得下去。
我沒有直接相信它,我做了 A/B
我不想憑感覺說「有用」。所以我開了兩個冷啟動 agent,丟同一個刁鑽、只有這個 repo 才答得出的問題:一組被要求「先讀 /knowledge」,另一組被禁止讀知識庫、只能爬 code。然後比兩件事:答對沒、花多少功夫。
第一題:兩個都對,但記憶快一倍
第一題我問:「如果我在文章頁加一個 React 元件,Google 爬蟲看得到它嗎?要改哪個檔?」正解不直覺——文章頁的爬蟲 HTML 是另一支腳本手寫產生的,client 端又用 createRoot 清空重繪,所以只加到 React 元件是不夠的。
兩組都答對了。老實說這題對知識庫「不公平地簡單」,因為那支腳本剛好有一段很好心的註解,純爬 code 也查得到。但讀知識庫的那組,用了一半的時間、三分之一的 token 就到位。這題比的是效率。
第二題:記憶答出了 code 裡根本查不到的東西
第二題我給的是真實症狀,不給答案:「線上網站 console 一直噴 React #418(hydration mismatch),手機 LCP 慢到 8 秒,該怎麼修?是改 code 還是別的?」
讀知識庫的那組幾秒就答對真因:是 Cloudflare 的 Email Obfuscation 在邊緣把頁面上的 email 改寫掉,讓伺服器 HTML 跟 React 對不上。而且它給了正確的決策——去 Cloudflare 後台關掉那個開關,不要寫 code 繞。
這一條,純爬 code 的 agent 永遠不可能知道,因為它根本不在程式碼裡。這就是 OKF 記憶最不可取代的價值:它記得「為什麼」和「當初的決策」,而這些是 code 本身表達不出來的。
但記憶也差點害我
轉折在這裡。只能爬 code 的那組,反而挖出一個知識庫裡沒有的、真的 bug:首頁有段程式在畫面渲染當下呼叫 new Date() 算「今天是第幾天」,build 當天的數字會被烤進預渲染的 HTML,隔天訪客算出不同數字——一樣會觸發 #418。
而讀知識庫的那組呢?它對到知識庫裡記錄的那個原因(Cloudflare)就停手了,完全沒往下查,漏掉了這個 bug。記憶讓它不再懷疑、不再往下找。這就是錨定偏誤。
| 只爬 code | 讀知識庫 | |
|---|---|---|
| 成本 | 約 6.7 分、23 次工具呼叫 | 約 49 秒、4 次 |
| 答出「code 裡沒有的決策」 | 不可能 | 是(關 dashboard、別改 code) |
| 找到另一個真 bug | 找到 | 沒有(錨定在已記錄的原因) |
真正的教訓:記憶是召回,不是真相
兩邊其實都對——只是對的是不同的 #418。這站真的有兩個 hydration 地雷:一個是邊緣層改寫 HTML(code 裡看不到,靠記憶才知道當初怎麼解),一個是 render 期的日期值(記憶裡沒有,靠當下分析才挖到)。
所以我的結論不是「有了記憶就不用查」。而是:用記憶來召回——它又快、又能給你 code 裡沒有的決策;但仍然要驗證當下的現實,別讓記憶變成「不用再查」的藉口。而且每次驗證撈到的新東西,要回寫進記憶。
這次我就做了:把那個雷區節點從「只講 Cloudflare」改成「#418 的兩類成因」,還加了一條明確的規則「別對到第一類就停手」,順手把那個真 bug 修掉。實驗本身讓這份記憶變得更好——這大概才是這套做法真正該有的樣子。
我不確定這是不是管理 agent 記憶最好的方法。但至少現在,Claude 跟 Codex 來這個 repo 不再是完全的冷啟動,我也學會了別把記憶當成不用再查的藉口。這份 knowledge bundle 就在 repo 裡,是公開的,你可以直接看。
延伸閱讀:Google OKF 會取代 RAG 與向量資料庫嗎?