LangGraph 把記憶拆成兩個彼此獨立的機制,這個拆法本身就是它最有價值的貢獻:checkpointer 負責「同一個對話續得上」,Store 負責「跨對話記得住」。前者是 runtime 的持久化責任,後者是產品的記憶設計。多數團隊把這兩件事混在一起討論,因此永遠說不清楚「我們的 agent 有沒有記憶」。
LangMem 是架在 Store 之上的 SDK,提供分型記憶(semantic/episodic/procedural)的抽取與管理 API。
兩層機制
Checkpointer(檢查點)——以 thread_id 為範圍,持久化圖的執行狀態。它讓一個中斷的對話可以續接、讓 human-in-the-loop 的暫停與恢復成為可能、讓執行可以回放到某個檢查點。它是 in-thread 的,不跨 thread。
Store(儲存)——以 namespace + key 定址的跨 session 儲存。典型的 namespace 設計是以 user_id 開頭,因此天然做到主體隔離。生產環境常用 PostgresStore 之類的後端。
這個二分是本篇最重要的可抽取模式。 它把一個常見的混淆解開了:「agent 記不記得剛才說的話」是 checkpointer 的職責(技術上是 state 持久化,跟記憶設計無關);「agent 記不記得上週說的偏好」才是記憶問題。任何新專案都應該先確認這兩件事分別由誰負責——很多團隊以為自己需要記憶框架,實際上只需要一個 checkpointer。
LangMem 的三型記憶
LangMem 直接把 分類學 的內容型態維度做成 API 概念:
Semantic(語意)——關於使用者與世界的事實。可以是條目式(一堆獨立事實)或畫像式(一份持續更新的結構化 profile)。兩種形態的取捨值得注意:條目式好增刪、好溯源;畫像式召回時 token 效率高、不需要選 top-k。多數產品最終需要兩者並存——條目作為真源,畫像作為召回時的快取視圖。
Episodic(情節)——過去互動的紀錄。LangMem 的文件明確把它與語意記憶區分為「聚焦於過去發生的事件而非一般知識」。它在 few-shot 上的用途最實際:把過去成功處理過的類似請求當成範例注入,比抽象規則有效得多。
Procedural(程序)——LangMem 把它定義為 agent 自己的系統指令。也就是說 prompt 本身是一種可以被記憶系統更新的資料。這個觀點比它聽起來激進:它意味著 agent 可以透過經驗改寫自己的行為規則,而這需要非常小心的護欄——見 記憶污染。
Hot path vs background:明確的兩個選項
LangMem 把記憶寫入的時機做成兩種明確的機制,這是它在工程上做得最清楚的一件事:
Hot path(熱路徑)——在 agent 執行的當下寫入記憶。優點是立即生效(同一輪學到的東西下一輪就能用),缺點是增加使用者感受到的延遲,而且記憶維護的推理會與任務推理競爭 context 與注意力。
Background(背景)——非同步處理,agent 回應後才整理記憶。優點是不影響延遲、可以看到更完整的對話再做判斷,缺點是有一段時間窗記憶還沒生效,而且需要額外的排程與失敗處理。
這個取捨與 Letta 的 sleep-time compute 以及 Hermes 的 periodic nudge 是同一件事的三種實作。三個路線不同的框架各自收斂到「記憶整理應該可以脫離主推理路徑」這個結論,這個共識的強度足以當成新專案的預設設計。
實務上的建議是混用:極少量的高價值記憶(使用者剛剛明確說出的偏好、剛剛糾正的錯誤)走 hot path 立即寫入;其餘走背景批次處理。判準是「這條記憶如果晚十分鐘生效,會不會造成可見的體驗問題」。
儲存後端與定位
Store 支援多種後端(記憶體、Postgres、以及各家向量/文件資料庫的整合)。LangMem 是 SDK 而非 runtime——但它預設你已經在用 LangGraph,因此實質上帶有框架綁定。
這使它的選型判準很簡單:如果你的 orchestration 已經是 LangGraph,LangMem 是最低摩擦的選項;如果不是,它的抽象不值得為此引入整個框架,直接抄它的概念設計會更好。
寫入與召回策略
寫入時機:hot path(工具呼叫)或 background(非同步管線),由開發者選擇。
召回方式:namespace + key 的精確取回,或在 namespace 內做語意搜尋。namespace 的階層設計實質上是一套範圍系統((user_id, "preferences") 這類),與 Mem0 的 scope keys 解決同一個問題。
遺忘:沒有內建機制,由開發者在寫入邏輯裡處理。
優缺點
優點:checkpointer 與 Store 的二分是最清楚的概念切割;三型記憶直接對應學術分類,詞彙統一;hot path/background 的取捨被明確做成選項;namespace 定址簡單可靠,不依賴向量相似度就能精確取回。
缺點:與 LangGraph 綁定;相較 Mem0 與 Letta,記憶治理(去重、衝突解決、失效)留給開發者自己實作的比例高很多——它提供的是機制與分類,不是完整的記憶管線;沒有時間模型;沒有內建的遺忘或容量控制。
適合場景:已經在用 LangGraph 的專案、需要自己完全掌控記憶治理邏輯的團隊、需要 human-in-the-loop 與執行回放的工作流。不適合:想要開箱即用的記憶治理、非 LangChain 生態的專案。
可抽取的模式
Separate thread state from cross-session memory(把 thread 狀態與跨 session 記憶分開)——這是本篇最重要的產出。兩者用不同的儲存、不同的生命週期、不同的 API。混在一起會導致「清除記憶」意外清掉對話續接能力,或者相反。
Namespaced key-value addressing(帶命名空間的鍵值定址)——記憶的第一存取路徑應該是精確定址((user_id, category, key)),語意搜尋是補充而非主要手段。這一條被大量團隊做反了:把所有記憶塞進向量庫,然後困惑於「使用者的名字為什麼沒被召回」。確定要用的東西不該經過相似度篩選。
Explicit write-timing choice(寫入時機的顯式選擇)——把「立即寫」與「背景寫」做成兩條明確的路徑,並為每一類記憶指定它走哪一條。
Prompt as memory(把 prompt 當成記憶)——系統指令可以是被記憶系統管理與更新的資料。使用時必須配上唯讀的護欄層(見 Letta 的唯讀 block),否則這就是一個記憶投毒直達行為規則的通道。