MapleCheng

在浩瀚的網路世界中無限潛水欸少年郎!

0%

AI Agent 的記憶架構:向量資料庫 vs 檔案系統的取捨

我有一個用 OpenClaw 搭的 AI 助手,平常幫我做各種事——專案管理、code review、查資料、回訊息。用了幾個月之後,最大的痛點浮現了:它需要記住越來越多東西,但記憶方式很蠢。

怎麼蠢呢?每次對話開始,就把一堆 markdown 檔案整包塞進 context。專案慣例、技術規範、開發守則……二十幾個檔案全部載入。簡單暴力,確實有效,但 token 燒得我肉痛。

所以我花了一整天把知識庫遷移到向量資料庫。然後隔天又改回來了。

原本的做法:檔案就是記憶

一開始的設計很樸素:每個專案的知識寫成一份 markdown,像是 coding-conventions.mddb-naming-rules.mdapi-patterns.md 之類的。Agent 啟動時全部載入,塞進 system prompt。

好處顯而易見——精確、完整、可預測。你知道 Agent 看到了什麼,它知道的就是你寫下來的,不多不少。Debug 的時候也好追蹤,打開檔案就能看到 Agent 的「知識庫」是什麼。

壞處也很明顯:

  • 22 個知識檔,載入後吃掉大量 context window
  • 不是每次對話都需要所有知識,但你不知道這次會需要哪些
  • 隨著知識越加越多,token 用量線性成長
  • 超過 context window 上限就只能硬砍,砍了又怕漏

就像你出門把家裡所有工具書都塞進背包一樣。安心是安心,但背不動。

向量遷移:看起來很美好

某天看到 LanceDB 的介紹,覺得這根本就是為我的場景設計的——嵌入式向量資料庫,不用開額外服務,直接跑在本地。於是動手遷移。

把 22 份 markdown 檔案濃縮成大約 30 筆知識條目,每筆控制在 500 字以內,盡量原子化。用 Jina 的 embedding model 做向量化,加上 reranker 做二次排序。

檢索架構是 hybrid retrieval:

  • 向量相似度佔 70%
  • BM25 關鍵字匹配佔 30%
  • hardMinScore 設 0.35,低於這個分數的結果直接丟掉

聽起來很專業對吧?我自己設計完也覺得挺帥的。

測試的時候效果也不錯——問「Controller 的命名規則是什麼?」能正確召回相關條目;問「資料庫欄位怎麼命名?」也能找到 DDL 規範。token 用量從「每次塞滿」變成「只取需要的」,省了至少 60%。

好,完美。收工。

然後現實打臉了

遷移完的隔天,Agent 在做 code review 的時候漏掉了一條重要的 coding convention。

我追查原因:那條規則確實在向量資料庫裡,但 Agent 當時的 query 跟那條規則的語義距離不夠近,similarity score 低於 0.35 的門檻,被過濾掉了。

這讓我意識到一個根本性的問題:

向量查詢的結果是「可能相關」,檔案載入的結果是「確定完整」。

當你做開發規範這種需要精確執行的事情,你要的不是「大概率相關的前 5 筆」,你要的是「所有規則,一條都不能漏」。漏掉一條命名規則,可能就是一個 PR 要打回重做。

向量搜尋的本質是 approximate——它很擅長在大量資料中快速找到「可能有關」的東西,但它不保證完整性。你沒辦法對一個向量查詢說「給我這個主題的所有規則」,因為它不理解「所有」這個概念。它只理解「跟你的 query 最像的 top-K」。

折返:混合模式才是正解

糾結了一陣子之後,我決定不全用向量,也不全用檔案,而是走混合模式。

            
            flowchart TD
    A[Agent 遇到決策點] --> B{知識類型?}
    B -->|精確規範| C[檔案系統]
    B -->|模糊查詢| D[向量資料庫]
    
    C --> C1[載入完整規範檔]
    C1 --> E[執行決策]
    
    D --> D1[Hybrid Retrieval]
    D1 --> D2[Vector 70% + BM25 30%]
    D2 --> D3[Reranker 二次排序]
    D3 --> E
    
    E --> F{新知識產生?}
    F -->|是| G[判斷歸屬]
    G -->|開發規範| H[更新檔案]
    G -->|經驗教訓| I[存入向量 DB]
    F -->|否| J[完成]

    style C fill:#2ecc71,color:#fff
    style D fill:#4a9eff,color:#fff
          

分工邏輯是這樣的:

檔案系統負責「精確」的東西

  • 開發規範、命名慣例、code review checklist
  • 這些是「必須 100% 遵守」的規則
  • 寧可多塞幾個 token,也不能漏掉任何一條

向量資料庫負責「靈活」的東西

  • 過去踩過的坑、debug 經驗、設計決策的理由
  • 跨專案的知識關聯(某個客戶的坑可能跟另一個客戶相關)
  • 不需要每次都載入,用到的時候再查就好

用一個不太精確但還蠻傳神的類比:向量資料庫就像二進制,機器原生、高效、但人不好讀;檔案系統就像 JSON,人機皆讀、好維護、但體積大。你不會把所有東西都存二進制,也不會把所有東西都存 JSON。

Context-Driven Recall:不預載,按需查詢

混合模式裡有一個重要的設計決策:不再開場就載入所有知識

取而代之的是 context-driven recall——在每個決策點,根據當前的上下文去查詢可能相關的知識。

比如說 Agent 要幫我寫一個新的 API endpoint,它不需要在對話一開始就知道所有的 coding conventions。它需要的是:

  • 在設計 Controller 的時候,查一下 Controller 的命名規則
  • 在寫 DAL 的時候,查一下 DataModel 的慣例
  • 在寫 SQL 的時候,查一下 DDL 命名規範

每個步驟只載入那個步驟需要的知識。這樣 context window 的使用效率大幅提升,而且因為查詢的語境更精確,向量搜尋的準確率也更高。

當然,這對 Agent 的「自我意識」要求比較高——它要知道自己在做什麼、這個步驟需要什麼知識、去哪裡查。這部分要靠好的 system prompt 設計,告訴它「在每個決策點,先查相關慣例再行動」。

自動擷取的雜訊問題

還有一個踩到的坑值得一提。

向量資料庫有一個 autoCapture 功能——自動從對話中擷取重要資訊存入知識庫。聽起來很棒吧?Agent 自己會學習!

結果它學了一堆垃圾。

對話中的 metadata、操作步驟的記錄、甚至「Maple 說了 OK」這種東西都被當成「知識」存了進去。幾天之後向量資料庫裡面塞滿了這種無意義的條目,查詢結果的品質明顯下降——因為那些垃圾條目也在搶排名。

解法是定期清理,但更根本的解法是不要無條件信任自動擷取。有價值的知識應該是人(或 Agent 在明確指令下)主動存入的,不是從對話流裡隨便撈的。

這就像你不會把會議逐字稿直接當作知識庫——你會整理出會議結論和行動項目,然後只存那些。

向量記憶的衛生守則

折騰了這一輪之後,我整理出幾條向量記憶的衛生守則:

  • 每筆知識控制在 500 字以內——太長的條目 embedding 品質會下降,而且召回後佔 token
  • 原子化——一筆知識只講一件事。不要把「Controller 命名規則」和「DAL 命名規則」塞在同一筆
  • 不存重複內容——向量資料庫不會自動去重,你存了三筆差不多的東西,查詢結果前三名可能都是它們
  • 定期清理——autoCapture 產生的雜訊、過時的資訊、測試用的條目,每隔一段時間掃一次
  • 存完立刻驗證——存入後馬上用 recall 查一次,確認能查到、分數合理。查不到就改寫重存

沒有完美的記憶架構

折騰了一整天遷移到向量,隔天又花半天改回混合模式。看起來好像白做工了?

其實不是。這個過程讓我搞清楚了一件重要的事:記憶架構的選擇取決於你對「精確度」和「靈活度」的需求比例。

如果你的 Agent 主要做的是創意發想、資料蒐集、開放式問答——全向量可能就夠了,因為你要的是「聯想」和「靈活」。

如果你的 Agent 要執行嚴格的規範、遵循特定的流程——純檔案更安全,因為你要的是「確定」和「完整」。

大部分 Agent 的場景介於兩者之間,所以混合模式通常是比較務實的選擇。

重點不是技術多花俏,是它能不能可靠地在正確的時候給你正確的知識。這聽起來像廢話,但在被向量搜尋的 approximate 特性坑了一次之後,我對「可靠」這兩個字有了更深的體會。

如果你也在做 AI Agent 的知識管理,我的建議是:先從檔案開始,等你真的感受到「token 不夠用」的痛了,再考慮向量化——而且只向量化那些「不需要 100% 完整」的部分。精確的規範,就讓它安安靜靜躺在 markdown 裡吧。