为什么不用 RAG 做記憶系統 ——壓縮上下文與 memory.md 的架構選擇

對話記憶 ≠ 知識檢索。把對話歷史存到向量資料庫,就像用 Google 搜尋來記住你昨天吃了什麼。

先說結論

在把 AI 應用落地時,有些團隊把 RAG(檢索增強生成,Retrieval-Augmented Generation)當成萬能解藥——知識庫用 RAG、對話歷史也用 RAG、使用者偏好還用 RAG。但實際上會發現 AI 總是失憶,使用體驗很糟。

根本原因在於:RAG 是為查找外部知識而設計的,不是為記住對話上下文設計的。

這兩件事雖然都需要「儲存 + 檢索」,但底層需求完全不同。

RAG 是什麼,它本來解決什麼問題

RAG(Retrieval-Augmented Generation)的工作流程:

這個場景是 RAG 的主戰場:大規模、相對靜態、面向事實查詢的知識庫

✅ RAG 真正擅長的問題:

  • 「我們公司的退款政策是什麼?」
  • 「合約第 7 條款說了什麼?」
  • 「Python asyncio 的最佳實務是什麼?」

這些都是主動查詢外部事實的場景,RAG 完全勝任。

當 RAG 遇到對話記憶

很多團隊會把使用者的對話歷史也存入向量資料庫,邏輯看似合理:「我把每次對話都存下來,下次使用者問相關問題時,檢索出來給 AI 看,AI 就有記憶了。」

實際上呢?

讓我們看一個真實的失敗場景。

案例:某 AI 私人助理,對話歷史存入向量資料庫

第一天的對話:

👤 我最近在學 Rust,幫我規劃一下學習路徑

🤖 好的!建議你從所有權系統開始……(詳細規劃)

👤 順便說一下,我的技術背景是 Python,做了 5 年後端

三天後,新的對話:

👤 幫我寫一個 Rust 的 HTTP 客戶端範例

🤖 ❌ 好的,這是一個基礎的 HTTP 客戶端範例。首先你需要了解什麼是 HTTP 協議……(從零開始解釋基礎概念)

為什麼失敗?

使用者的查詢是寫 HTTP 客戶端,而歷史中那句「我有 5 年 Python 後端經驗」和這個查詢的語義相似度極低,向量檢索根本不會召回它。

RAG 用於記憶系統的四大結構性缺陷

缺陷 1:相關性 ≠ 重要性

向量檢索召回的是語義上最相似的內容,不是最重要的內容。

使用者說「我不喜歡廢話連篇的回答」——這是極其重要的偏好,但它和絕大多數技術問題的語義距離都很遠,幾乎永遠不會被檢索到。

缺陷 2:上下文是整體,不是碎片

對話中「我、我老婆、我們的專案」是一個整體敘事。但是被切片存儲後,人稱關係斷裂,AI 拿到孤立片段,很容易產生理解錯誤。

比如「她不喜歡這個方案」存入向量庫後,下次檢索出來時,AI 已經不知道「她」是誰了。

缺陷 3:增加了不確定性

RAG 召回的 top-k 策略是具概率性的。同一個問題,在不同时機、不同嵌入(embedding)模型版本下,可能召回完全不同的歷史片段,導致 AI 行為難以預測與除錯。

缺陷 4:維護成本高

這會帶來很多運維負擔:維護向量資料庫(Pinecone / Weaviate…)增加基礎設施複雜度;嵌入模型版本更新後需要對歷史資料重新向量化;使用者資訊發生變動但舊向量還在資料庫中持續干擾——既然有這麼多缺陷,我們實際落地時要怎麼辦呢?

方案一:壓縮上下文(Context Compression)

壓縮上下文的核心思路:不要讓 AI 去檢索記憶,而是直接把精煉過的記憶放進上下文(context)裡。

效果對比

同樣的問題,換了方案之後。

注入系統提示的摘要:

## 使用者背景
- 5 年 Python 後端經驗,熟悉 FastAPI 和 async 編程
- 目前正在學習 Rust,已完成所有權章節
- 偏好:程式碼範例簡潔,不需要解釋基礎概念

## 上次對話摘要(2025-03-18)
- 使用者詢問了 Rust 學習路徑,決定下一步學習 async/await。
- 使用者明確表示不喜歡理論解釋,更喜歡直接看程式碼。

對話效果:

👤 幫我寫一個 Rust 的 HTTP 客戶端範例

🤖 ✅ 直接上程式碼,用 reqwest 套件。考慮到你熟悉 Python async,這裡的 .await 語法應該很眼熟:

use reqwest;

async fn fetch(url: &str) -> Result<String, reqwest::Error> {
    reqwest::get(url).await?.text().await
}

AI 知道使用者是有經驗的工程師,直接給程式碼;知道使用者學過 Python 的 async,做了類比——所有關鍵上下文都完整保留了。

方案二:memory.md(結構化記憶檔案)

壓縮上下文解決了會話歷史的問題,但還有另一類記憶:關於使用者本身的長期事實性記憶。比如職業背景、溝通偏好、正在進行的專案……

這些不應該每次都從對話歷史中重新推斷,而應該有一個固定的使用者檔案——這就是 memory.md。

示例檔案:

## 基本資訊
- 職業:後端工程師,5 年經驗,主力語言 Python
- 時區:Asia/Taipei,上班時間 10:00-19:00
- 溝通偏好:簡潔直接,程式碼優先,不需要廢話

## 正在進行的專案
- **Rust 學習**:進度到第 8 章(錯誤處理),目標是重寫內部資料管線
- **工作專案**:某 SaaS 產品 API 效能優化,技術棧 FastAPI + PostgreSQL

## 重要偏好
- 不喜歡過度解釋顯而易見的概念
- 喜歡以 Python 類比來理解新語言特性
- 程式碼範例:可執行的真實範例 > 極度簡化的示例

## 最近的關鍵決策
- 2025-03-15:決定使用 tokio 作為 Rust 非同步執行時
- 2025-03-10:選擇了 reqwest 作為 HTTP 客戶端庫

## 待跟進
- 等使用者確認是否需要協助設計資料庫 schema

memory.md 的關鍵特性:

  • 人類可讀、可編輯
  • 使用者可直接打開查看、修改,完全透明
  • 確定性地讀取全文並注入系統提示,不存在召回率問題
  • 輕量易維護,普通文字檔,不依賴任何外部向量服務
  • 資訊密度高:1000 token 可覆蓋幾個月的關鍵記憶
  • AI 自動維護:發現新重要資訊時,自動更新對應欄位

兩個方案如何配合

兩層架構,解決不同時間尺度的記憶問題:

關鍵點:兩層記憶都不需要向量檢索,都是確定性地注入系統提示。

這避免了所有的召回率問題,讓 AI 的行為變得可預測、可調試。

那 RAG 什麼時候用?

判斷標準只有一個:

這條資訊,是使用者主動問出來的(查詢外部知識),還是在對話中被動透露的(累積的上下文)?

  • 前者 → 用 RAG
  • 後者 → 用 memory.md + 壓縮上下文

場景推薦方案

  • 使用者對話歷史:壓縮上下文摘要
  • 使用者偏好 / 背景:memory.md
  • 公司內部文件 / FAQ:RAG(向量檢索)
  • 正在進行的任務狀態:memory.md(待跟進欄位)
  • 大規模技術文件語義搜尋:RAG(向量檢索)

業界是怎麼做的

這套思路並不是憑空而來,看看幾個真實的工業級產品會發現殊途同歸。

  • OpenAI Codex / Claude Code:這類工具在啟動時會掃描專案目錄,把 README.md、目錄結構、關鍵設定檔直接讀入上下文,同時在對話中自動維護一份「當前任務狀態」的結構化摘要。它們幾乎不用向量檢索來回憶之前的操作——而是靠不斷壓縮與更新的 working memory 來維持任務連貫性。
  • OpenClaw / Cursor 等:Cursor 的 .cursorrules 檔案本質上就是 memory.md 的工程化實作——由開發者手寫(或 AI 輔助維護)的專案級偏好檔案,每次對話都全量注入。使用者發現告訴 AI 一次就會永遠記住的最可靠方式,不是讓 AI 檢索歷史對話,而是直接寫進這個檔案。
  • Anthropic Claude 與 ChatGPT 的記憶功能:官方的記憶功能正是生成結構化的使用者檔案 Markdown 片段,在每次對話開始時注入系統提示。

落地時的注意事項

1. 壓縮摘要的觸發時機

不要等到 context 真正滿了再壓縮,那時已經來不及了。推薦策略:

  • 固定輪數觸發:每 15–20 輪對話壓縮一次,簡單可靠
  • token 閾值觸發:當 context 使用量超過模型上限的 60%–70% 時觸發,留出壓縮本身需要的空間
  • 話題切換觸發:偵測到使用者開始討論新話題時,把舊話題先壓縮歸檔

2. 壓縮摘要的 Prompt 設計

壓縮品質直接決定記憶品質,這步不能偷懶。一個有效的壓縮 prompt 應該明確告訴 AI 要保留什麼:

請將以下對話壓縮為結構化摘要,必須保留:
1. 使用者透露的個人背景和偏好
2. 已經做出的決定和選擇(不要省略)
3. 未完成的任務和待跟進事項
4. 重要的上下文約束(如技術棧、團隊規範)

不需要保留:
- 具體的程式碼細節(除非是核心架構決策)
- 過程中的錯誤嘗試
- 禮貌性寒暄

輸出格式為 Markdown,使用 ## 分節。

3. memory.md 的更新策略

不要讓 AI 在每輪對話後都判斷要不要更新 memory.md,這會引入大量無意義的寫入,也會讓 AI 分心。更好的做法:

  • 非同步更新:在每次對話結束後(使用者關閉會話),單獨跑一次提煉新資訊的任務
  • 增量 diff:讓 AI 只輸出新增/修改/刪除的欄位,不要每次重寫整個檔案
  • 版本控制:memory.md 最好用 git 管理,方便回滾和稽核

4. memory.md 的大小控制

肯定不是越大越好。

注入 prompt 是有 token 成本的,而且太長的 memory.md 反而會稀釋重要資訊的權重。

我的粗淺經驗值:500–1500 token 是可靠區間,超過 2000 token 就要考慮歸檔舊內容。可以把 memory.md 分層:

  • memory.md:當前活躍的核心資訊(≤1000 token,每次注入)
  • memory_archive.md:歷史歸檔(不注入,只在使用者主動詢問時檢索)

5. 警惕污染

AI 自動維護 memory.md 時,偶爾會寫入錯誤資訊——例如誤解了使用者的意思,或把暫時性的表述當成長期偏好。

應對方法:

  • 在 UI 上給使用者提供查看或編輯記憶的入口,讓使用者能隨時校正
  • 對 memory.md 的寫入操作做人工確認(至少在產品早期),累積足夠樣本後再改成全自動

寫在最後

我之前一直寫 Java 相關的技術文章,框架、效能優化、微服務架構……寫了很多年,也算累積了一些東西。

但最近開始轉向 AI 應用落地,剛開始有點迷惘。這個領域變化太快、概念滿天飛,每隔幾天就有新的模型、新的框架、新的最佳實務冒出來,感覺自己永遠在追趕。

於是我就乾脆停下來,不追熱點了,老老實實地去做專案、踩坑、復盤。這篇文章裡關於 RAG 作為記憶系統的問題,就是我們團隊實際踩過的坑。在我看來,這些東西才是應該認真沉澱和分享的,而且這些經驗,只有真正做過落地才知道。

以後我會慢慢把這些心得整理出來分享,關於 AI 應用架構、prompt 工程、agent 設計……都是從實際專案裡提煉的精華。

最後,想跟大家說:不要怕被 AI 淘汰。

我在實際做 AI 應用的過程中,越來越清楚地感受到一件事——AI 現在有多強大,就有多需要人來掌舵。 至少在目前這個階段仍然如此。

模型不知道你的業務邊界在哪裡,不知道你的使用者真正關心什麼,不知道一個決策背後的組織博弈,不知道什麼時候該停下來讓人工介入。這些判斷,現階段全都需要人來做。

所以現在這個階段,真正的競爭不是「你 vs AI」,而是 「會用 AI 的你 vs 不會用 AI 的你」

掌握足夠的 AI 使用與應用技能,不只是避免被淘汰,更有可能借著這波浪潮,做出以前根本沒有條件做的事情。

共勉。


原文出處:https://juejin.cn/post/7620027489954004992


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝14   💬10   ❤️2
417
🥈
我愛JS
📝2   💬9   ❤️2
93
🥉
💬1  
4
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登