LLM 沒有記憶。每次 API 呼叫獨立 —— 模型對你上次對話零回憶。Agent 產品裡的「記憶」是你透過決定每次呼叫帶哪些 context 蓋出來的。蓋錯,agent 感覺很笨(兩條訊息後就忘了使用者名字)或很貴(每次都送整段所有對話歷史)。
四層記憶基本涵蓋所有真實產品需求。大部分團隊過度工程化,在自己 50 行就夠的時候去抓記憶函式庫。
四層
- Working memory。 當前對話的 message 歷史。「我剛告訴你我叫 Alice」。對話內有效。
- Session memory。 當前 session 的壓縮摘要。「這個使用者在處理退費。」直到使用者關掉聊天有效。
- User memory。 跨 session 知道使用者的東西。「Alice 是 Pro 方案、住台北、偏好繁中。」永久。
- Episodic memory。 使用者之後可能引用的特定過去事件。「3 月 3 日 Alice 問了 API rate limit 我們用 X 解決。」可搜尋,不一定載入。
它們不是順序層 —— 是你平行維護的不同抽象。
第 1 層:working memory(簡單那個)
就是你每次 API 呼叫送的 message 陣列:
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "My name is Alice"},
{"role": "assistant", "content": "Nice to meet you, Alice"},
{"role": "user", "content": "What's my name?"},
]
模型輕鬆答「Alice」因為答案在 context 裡。
working memory 有一個真挑戰:context window 會塞滿。50 輪對話帶大工具輸出之後,你可能已經到 context 預算 80%。三個解法:
- 摘要舊輪次。 把前 30 輪換成 200 token 摘要,每 N 輪跑一次。
- 消費過的工具結果丟掉。 第 4 輪的檢索結果第 20 輪用不到。
- 用 prompt caching。 Claude 或 Gemini,system prompt + 對話前段可以 cache,重送便宜。(但還是吃 context。)
第 2 層:session memory(把簡單做好)
Session 結束時(使用者關聊天、你開新對話),別把整段歷史丟掉,壓縮它:
session_summary = llm.summarize(
"用 200 token 摘要這段對話。"
"重點:使用者要什麼、解決了什麼、還有什麼待處理。"
f"\n\n對話:\n{full_transcript}"
)
store_in_db(user_id, session_id, session_summary)
下次使用者出現:載入他最近 3 個 session 摘要,作為「最近脈絡」注入 system prompt。Agent 現在感覺有連續性,你卻沒送 5 萬 token。
這個單一功能 —— session 摘要注入下個 session 的 context —— 用 100 行程式碼給你 80% 的「感覺它記得我」效果。
第 3 層:user memory(團隊想太多的地方)
關於使用者該永久持續的東西:名字、方案 tier、語言偏好、工作脈絡、表述目標、學到的事實(「使用者是兒科醫生」「使用者對花生過敏」)。
兩種實作方法:
方法 A:結構化 profile
CREATE TABLE user_profile (
user_id UUID PRIMARY KEY,
display_name TEXT,
preferred_language TEXT,
occupation TEXT,
notes TEXT[] -- 使用者提過的自由格式事實
);
使用者提到事實時,agent 用 remember(category, fact) 之類的工具加進 profile。Session 開始時把 profile 載入 system prompt。
優點:結構化、可查詢、可預測。使用者可以看跟編輯他的 profile。
缺點:需要你預測哪些欄位重要,抓不到所有東西。
方法 B:自由格式記憶 + 檢索
把事實存成 vector store 裡的 embedding。每輪檢索 top-K 最相關記憶。
relevant_memories = vector_store.search(current_query, top_k=5)
system_prompt += f"\n相關記憶:\n{relevant_memories}"
優點:抓任意事實,規模到每使用者幾千條記憶。
缺點:檢索可能漏相關記憶或浮出無關的。比較難 debug。沒遺忘政策的話儲存無上限成長。
實務上有效的做法
混合:
- 重要事實用結構化 profile(方案 tier、語言、名字、3 個主要表述目標)。5-10 欄。
- 軼事事實用自由筆記表(「偏好簡潔答案」、「是兒科醫生」)。最多 50 筆最近的,更多就用 embedding 搜尋。
出貨這個之後撞到真實限制再去抓 Mem0 / Letta / Zep。
第 4 層:episodic memory
最深層。使用者可能想回頭參考的過去對話:「上個月關於 API rate limit 的問題我們決定怎麼處理?」
實作:
- 每段過去對話(完整或摘要)用 metadata(日期、user_id、主題)當文件 index。
- Agent 收到 query,對這個 index 跑檢索。
- 找到符合就當 context 浮出:「2026-03-03 你討論過... [摘要]」
- 可選:讓 agent 對特定過去 session 問追問。
大部分產品不需要第 4 層。客服 agent 跟個人助理受益。一般 chatbot 不需要 —— 成本(儲存、檢索延遲、評測複雜度)比偶爾「你記得那次嗎?」時刻多。
2026 框架版圖
值得認識的記憶框架:
- Mem0。 最熱門。自動記憶抽取 + 儲存 + 檢索。Python 跟 TS SDK,可以塞 LangChain 或獨立用。用 LLM 從對話抽事實存起來。
- Letta(原 MemGPT)。把記憶當階層作業系統 —— 「主記憶」對「歸檔記憶」。學術上有趣,設定多。
- Zep。 Production 導向,評測跟 dashboard 較強。認真的對外 agent 值得。
- LangChain Memory / LlamaIndex Memory。 那些框架的內建模組。
我的看法: 單產品獨立團隊,自己寫。5+ 人團隊出多個 agent 產品,用 Mem0 標準化。高風險(法律、醫療、金融建議 agent),跟 Zep 團隊評估。
常見錯誤
- 存太多。 每個路過評論都進長期記憶。半年後 agent 以為使用者真的很在乎貓,因為他提過一次。儲存時激進過濾。
- 忘了忘記。 使用者會變,舊事實變錯。加時戳跟衰減權重,讓使用者清記憶。
- 相信 agent 抽取的事實。 「使用者說他 30 歲」可能其實是「使用者說我覺得你30 歲」。LLM 抽取會錯。把存的記憶給使用者看,讓他改。
- 沒隱私控制。 2026 年使用者期待能看、改、刪除自己的記憶。「這個 app 記得我什麼?」必須能回答,理想上是 UI。
- 每輪載入太多。 每輪塞 5000 token 記憶,你每次 API 呼叫都付錢。要選擇性,只載相關記憶。
獨立開發者務實 stack
2026 年我自己個人專案在跑、推薦給獨立創辦人的:
Working memory:就 message 陣列,30 輪後摘要。
Session memory:每 session 200 token 摘要存 postgres。
User memory:5 欄結構化 profile + 50 筆最近自由筆記。
Episodic memory:除非使用者明確要,跳過。
大概 200 行程式碼,涵蓋大部分產品「記憶」該做的 90%。撞牆再評估框架。
什麼時候不要蓋記憶
- 單輪產品(搜尋、無來回的 tool use)。不需要記憶。
- 無狀態 API endpoint。 記憶讓輸入輸出依賴隱藏狀態,測試難。
- 高隱私領域。 使用者假設關頁面對話就忘了的話,蓋記憶創造期待跟風險。預設不記得,讓使用者 opt in。
下一步
- MemGPT: Towards LLMs as Operating Systems(Packer et al, 2023)—— 原始 Letta 論文。
- Mem0 文件 —— 實務抽取 pattern。
- Generative Agents: Interactive Simulacra of Human Behavior(Park et al, 2023)—— 推紅 agent 記憶的史丹佛論文。
- 查這些詞:episodic memory、retrieval-augmented memory、fact extraction、memory consolidation。