Mem0 Intro Part 5 — 生產部署 — OSS 與 Platform 的分界線在哪裡

大多數人評估「要用開源版還是託管版」的方式,是比較功能清單的長度,然後選比較便宜的那個。 真正的答案是:功能清單只告訴你今天缺什麼,不告訴你半年後你會自己寫出什麼。 Mem0 的 OSS 與 Platform 之間那條線,剛好切在「記憶治理」上——而 ADD-only 架構保證了你遲早要處理它。 你不是在選要不要付錢,是在選要不要自己寫。


前言

前四篇拆完了 OSS 的全貌:全景架構ADD-only 寫入三訊號檢索儲存層選型

一路上反覆出現同一句話:「這個在 Platform 有,OSS 沒有。」 圖記憶、時序推理、記憶衰減、背景整合、自訂分類、webhook。

這一篇把那條線畫清楚,並且回答一個更實際的問題:如果你選 OSS,你必須自己補哪些東西,以及那大概要花多少工。

本篇的目標:讀完之後,你能做出一個有依據的 OSS/Platform 決策,能完成 v2→v3 的遷移,能用官方開源的框架測自己的資料,並且有一份可以照抄的生產檢查清單。


一、核心問題:那條線切在哪裡

官方文件對這件事相當坦白,開宗明義寫著兩者「run the same core extraction and retrieval logic」,差別在三類東西:

        ┌────────────────────────────────────────────────────┐
        │  完全相同的部分                                     │
        │  · add / search / get / get_all / update /          │
        │    delete / delete_all / history 全套 API           │
        │  · user_id / agent_id / run_id 作用域                │
        │  · AND / OR / NOT 過濾組合、萬用字元                 │
        │  · 實體感知排序(兩邊都抽實體、都用共享實體加權)    │
        │  · 多模態輸入、記憶過期、reranking、程序記憶         │
        │  · custom_instructions                              │
        │  · Python / JS SDK + REST API                       │
        └────────────────────────────────────────────────────┘
                              │
        ┌─────────────────────┼─────────────────────┐
        ▼                     ▼                     ▼
┌───────────────┐  ┌──────────────────┐  ┌──────────────────┐
│ 差異一:託管   │  │ 差異二:搜尋排序  │  │ 差異三:管理面    │
│                │  │ (v3-only)      │  │                  │
│ · 誰跑向量庫   │  │ · Graph Memory   │  │ · 組織/專案      │
│ · 誰負責擴充   │  │ · Memory Decay   │  │ · app_id 租戶隔離 │
│ · 有沒有       │  │ · Temporal       │  │ · 專案級事件流    │
│   dashboard    │  │   Reasoning      │  │ · 自訂分類        │
│                │  │ · Dream          │  │ · Webhook         │
│ ← 這是錢的問題 │  │ ← 這是工程量問題 │  │ ← 這是產品面問題  │
└───────────────┘  └──────────────────┘  └──────────────────┘

差異一是最不重要的那個。 自架一套 pgvector 不難,Part 4 講過。

差異二才是關鍵,因為它們全都在解同一個問題:ADD-only 架構產生的記憶熵增。Part 2 的結論是「v3 刻意接受了記憶只增不減的代價,把治理責任外移」——Platform 就是那個「外面」


二、四個 Platform 專屬能力,以及 OSS 的補法

2.1 Graph Memory:從外接圖庫變成內建

變更歷史:v2 的 OSS 可以接 Neo4j / Memgraph / Kuzu / Apache AGE,用 enable_graph + graph_store 設定。v3 把這個整合從 OSS 移除,改成 Platform 內建、永遠開啟。

官方遷移文件的原話:

Graph memory: enable_graph + graph_store in config → Removed. Graph memory is removed from OSS. It’s a built-in, always-on Mem0 Platform feature.

以及平台對照表裡更精確的說明:

OSS still extracts entities and uses them to boost ranking, but there is no queryable graph and no relations field.

所以 OSS 失去了什麼、保留了什麼

保留:實體共現加權
  查詢「Alice」→ 實體庫查到 Alice → 拿到 linked_memory_ids → 加權那些記憶
  ← Part 3 第四節的那個公式,OSS 完整保有

失去:多跳遍歷與關係查詢
  「Alice 的同事的專案」——這需要沿著邊走兩跳
  「Alice 和 Bob 是什麼關係」——這需要邊有型別(COLLEAGUE / MANAGES / ...)
  OSS 的實體庫只有 entity → [memory_ids] 這種扁平的反向索引,
  沒有 entity → entity 的邊,也沒有邊的型別

OSS 的補法

需求補法工程量
只要實體加權不用補,OSS 已經有0
要「關於 X 的一切」get_all + metadata filter,寫入時把實體寫進 metadata
要多跳關係查詢自己在 Mem0 外面掛一個圖庫,寫入後把實體對寫進去中—大
要關係型別需要 LLM 抽關係三元組,成本會顯著上升

誠實的建議先確認你真的需要圖。 多數對話記憶場景,「關於 Alice 的一切」用實體加權就夠了,而多跳查詢(「Alice 的同事的專案」)在真實產品裡的出現頻率遠低於你的想像。如果你真的需要圖,那可能該考慮的是一個以時序知識圖為核心的系統,而不是在 Mem0 外面補一個。

2.2 Temporal Reasoning:時序訊號

Platform 做什麼:寫入時用一個獨立的推理階段,讀出每條記憶的時間中繼資料——事件何時發生、是進行中還是已完成、時間精度如何、以及記憶型別(事件/狀態/計畫/偏好/關係/缺席)。檢索時把查詢的時序意圖分類(不額外呼叫 LLM),再用這些中繼資料算一個加分項。

官方強調兩點:這個推理階段獨立於萃取、可非同步跑,所以寫入延遲不受影響;以及時序分數是加分而非過濾,「semantic relevance always dominates」——它只會把正確的那個日期版本往前推,不會把候選整個踢掉。

效果:LongMemEval 的 temporal_reasoning 分項達到 97.0,LoCoMo 的 temporal 是 92.0。

OSS 完全沒有。傳 timestampreference_date 會直接拋錯:「not supported by the OSS Memory SDK」。

OSS 的補法(Part 3 第八節講過,這裡按投入產出比排序):

補法一(最便宜,效果最好):把時間寫進記憶文字
  custom_instructions = "當事實涉及狀態變化(居住地、職稱、關係、目標),
                        務必在記憶文字中包含對話發生的日期。"

  「使用者自 2026 年 8 月起住在柏林」
  → 時間進了語意向量,查詢「他現在住哪」時帶年份的那條匹配更好
  工程量:一行設定

補法二:檢索後在應用層按 created_at 重排同主題記憶
  工程量:20 行程式碼 + 寫入時要標 topic

補法三:把新舊都給 LLM,附上日期,讓它自己判斷
  「已知關於使用者:
     - [2025-03-14] 使用者住在里斯本
     - [2026-08-02] 使用者住在柏林」
  工程量:改一下 prompt 模板
  ← 現代模型處理這種明確標註的矛盾相當可靠。這其實最符合 ADD-only
    的設計哲學:保留證據,讓最有能力判斷的那一層判斷。

補法四:expiration_date(OSS 支援!)
  對天生有時效的事實在寫入時就標好過期日
  工程量:加一個參數

四個補法加起來,能覆蓋 Platform 時序推理的大部分實用價值,而且工程量都很小。這是四個專屬能力裡最容易自己補的一個。

2.3 Memory Decay:用「最近有沒有被用到」重排

Platform 做什麼:每條記憶記錄「最後一次被取回是什麼時候、被取回過幾次」,把這個歷史換算成一個 0.3× 到 1.5× 的縮放因子,乘進檢索分數。

記憶狀態              縮放因子      排序效果
─────────────────────────────────────────────
剛剛被取回            ≈ 1.5×        強加分
今天被碰過            1.2 – 1.4×    輕度加分
閒置幾天              0.6 – 1.0×    輕度抑制
閒置數週              0.4 – 0.6×    較強抑制
閒置數月/數年        ≈ 0.3×        地板,不會再低

檢索流程也很有意思:先把候選池擴大到 top_k × 3(最低 50)給重排留空間,用未截斷的乘積排序(讓 0.3–1.5 的完整範圍能真的重排),但回傳的 score 會被 clamp 到 [0,1] 以維持 API 契約,最後對回傳的每條記憶做一次 fire-and-forget 的「強化」(存取歷史 +1,最多保留最近 20 次)。

設計上的克制值得注意:0.3 是地板不是零——衰減永遠不會讓一條記憶消失,只會降低它的排名。這符合 ADD-only 的一貫哲學。

OSS 沒有。傳 decay 會拋錯。

OSS 的補法

 1# 自己維護存取計數:在 search() 之後,對回傳的記憶更新 metadata
 2results = m.search(q, filters={"user_id": u}, top_k=60)["results"]
 3
 4# 應用層重排
 5import math, datetime
 6def decay_factor(meta):
 7    last = meta.get("last_accessed") or meta.get("created_at")
 8    days = (datetime.datetime.now(datetime.timezone.utc)
 9            - datetime.datetime.fromisoformat(last)).days
10    return max(0.3, min(1.5, 1.5 * math.exp(-days / 30)))
11
12reranked = sorted(results,
13                  key=lambda r: r["score"] * decay_factor(r.get("metadata") or {}),
14                  reverse=True)[:10]
15
16# fire-and-forget 更新存取時間(丟到背景 task)
17for r in reranked:
18    background_update(r["id"], {"last_accessed": now_iso()})

工程量:中等。 難的不是公式,是那個 fire-and-forget 的更新——m.update() 會重新嵌入記憶文字(浪費),而且高頻更新會對向量庫造成寫入壓力。務實的做法是把存取計數放在一個獨立的 Redis 或 SQL 表裡,不要塞進向量庫的 metadata。

2.4 Dream:背景整合

這是四個裡面最難自己補、也最有價值的一個。它有三個動作:

動作做什麼何時跑可用性
Supersede新事實與舊事實矛盾時,把舊的標記為已被取代並連結到新的加入記憶時所有方案,永遠開
Merge把重複的記憶折疊成單一正規版本加入記憶時所有方案,永遠開
Synthesis把多條記憶蒸餾成更高階的「模式記憶」排程、背景需開啟(Pro 以上)

Supersede 的關鍵設計:被取代的記憶不刪除、不隱藏。一般的 searchget 仍會回傳它們,只是帶上「已被取代」的標記。要只拿現況時,明確傳 latest_only=true

這正是 Part 2 那個問題的正解:不是在寫入時決定要不要覆蓋(v2 的錯誤),也不是完全不處理(v3 OSS 的現狀),而是保留兩者但標記關係,讓讀取端決定

Synthesis 的例子(官方文件的):四條分別講跑步、重訓、Garmin 手錶、馬拉松目標的記憶,被蒸餾成一條:

「使用者維持結構化的健身routine,包含每週長跑(約 40 公里)、規律的腿背重訓、用 Garmin 裝置追蹤訓練,並持續追求漸進的馬拉松時間目標。」

四條來源記憶原封不動留著,新的模式記憶連回它們作為證據。官方強調它是「additive and idempotent」——重跑不會產生重複的模式。

兩個限制值得記:Synthesis 只看純 user_id 作用域的記憶(同時帶 agent_id / run_id / app_id 的會被排除);而且只處理啟用之後建立的記憶,不會回頭批次處理歷史資料。

OSS 的補法

Merge  → Part 2 第七節的週期性合併作業
         每週撈 get_all(),相似度 > 0.92 的群組交給 LLM 合併
         工程量:中(一個排程作業 + LLM 呼叫 + 自己的稽核表)

Supersede → 這個最難。要判斷「矛盾」需要 LLM,而且要在
           正確的候選範圍內判斷(不能只看 top-10)
           務實的替代:用 metadata 的 topic 分群 + created_at 取最新
           工程量:中—大

Synthesis → 一個週期性的「為每個活躍使用者產生 profile 摘要」作業
           把摘要用 infer=False 寫回去(記得標 metadata 區分)
           工程量:中

三者加起來大概是一到兩週的工程量,加上持續的維護成本。 這是評估 OSS vs Platform 時該放進天平的那個數字——不是月費多少,是這些作業值不值得你的團隊寫和養


三、決策:OSS 還是 Platform

選擇              選 OSS 的理由                      選 Platform 的理由
──────────────────────────────────────────────────────────────────────────
資料主權          資料完全在自己的基礎設施           ← OSS 勝
成本              大量使用時單位成本低               小量使用時 Platform 更划算
                  (但要算進工程與維運人力)           (不用養任何東西)
後端自由度        25 種向量庫、18 種 LLM 任選        ← OSS 勝
                  可用本機模型完全離線
記憶治理          **要自己寫**(Merge/Supersede/     ← Platform 勝,而且差距最大
                  Decay/時序)
圖查詢            沒有(只有實體加權)               原生、永遠開
管理面            沒有 dashboard、沒有組織/專案      有
                  沒有 webhook、沒有事件流
上線速度          看你的向量庫與 LLM 設定            幾分鐘(只要 API key)
benchmark 分數    「directionally similar gains      官方公布的數字是這個
                  but not identical numbers」
──────────────────────────────────────────────────────────────────────────

三個判斷訊號(比功能表更實用):

訊號一:你開始寫「哪條記憶才是最新的」的邏輯了嗎?
  → 是:你正在重造 Supersede。評估一下這條路要走多遠。

訊號二:你的記憶庫在三個月後,單一活躍使用者累積了多少條?
  → 超過 200 條且你一眼看得出大量同義重複 → 你需要 Merge。

訊號三:合規要求資料不出境嗎?
  → 是:沒得選,只能 OSS。此時要把治理作業的工程量正式排進 roadmap,
       而不是等到出問題才處理。

一個折衷路線值得考慮:用 OSS 跑 search()(高頻、低成本、無 LLM),用自己的排程作業處理治理。這條路的關鍵是先把 Part 3 第五節的標註集建起來——沒有它,你無法判斷自己補的治理作業是讓系統變好還是變壞。


四、v2 → v3 遷移清單

如果你有既有的 Mem0 程式碼,這一節是你最需要的。官方遷移文件開頭就掛了一個警告:「Breaking changes ahead. This release includes renamed parameters, removed parameters, changed defaults, and a fundamentally different extraction model.」

4.1 Python OSS 的破壞性變更

變更怎麼改
search() / get_all() 的實體 ID頂層參數 user_id="..."放進 filtersm.search("q", filters={"user_id": "..."});用舊寫法會拋 ValueError
top_k 預設10020要舊行為就明確傳 top_k=100
threshold 預設None(不過濾)0.1要舊行為傳 threshold=0.0
threshold 驗證任意 float必須在 [0,1]超範圍會拋 ValueError
rerank 預設TrueFalse要舊行為傳 rerank=True
實體 ID 驗證接受任意字串trim 後拒絕空字串與含內部空白傳乾淨的識別碼
add()messages可以是 None必須是 str / dict / list[dict]其他型別拋 Mem0ValidationErrorVALIDATION_003
add() 回傳的事件ADD / UPDATE / DELETE只有 ADD移除期待 UPDATE/DELETE 的程式碼
自訂萃取提示詞custom_fact_extraction_promptcustom_instructions改名
自訂更新提示詞custom_update_memory_prompt廢棄改用 custom_instructions
圖記憶enable_graph + graph_store移除見 2.1
Qdrant client>=1.9.1>=1.12.0升相依
Upstash client>=0.1.0>=0.6.0升相依

4.2 TypeScript OSS 額外要注意的

除了對應的改動之外,有一個只有 TS 才有的坑

變更說明
limittopK參數改名
詞形還原欄位text_lemmatized(snake_case)→ textLemmatized(camelCase)

那個欄位改名的後果,官方文件講得很清楚:

If you share a vector store collection between Python and TS SDKs, lemma-based BM25 will not resolve across languages: keep collections language-scoped.

翻譯:Python 寫進去的記憶,TS 的 BM25 檢索不到;反之亦然。 如果你有混合技術棧,兩邊必須用不同的 collection,或者統一只用一種 SDK 寫入。這是一個很隱蔽、且只會表現為「檢索品質莫名變差」的問題。

4.3 建議的遷移順序

1. 先升版但不改程式碼,跑測試 → 收集所有 ValueError / 驗證錯誤
   ← 好消息:v3 把大部分不相容都改成「明確拋錯」而不是靜默行為改變

2. 修 filters 的位置問題(最常見)

3. 明確寫出三個預設值:top_k / threshold / rerank
   ← 就算你想用新預設,也明確寫出來,避免下次改版又被動

4. 移除任何依賴 UPDATE / DELETE 事件的邏輯

5. 如果用過 graph_store:評估 2.1 的四種補法

6. **重跑你的標註集**(Part 3 第五節)
   ← 這一步不能跳。extraction 模型換了、預設值換了、
     ADD-only 換了——召回行為一定變了,你需要知道變好還是變壞

7. 考慮跑一次全量重萃取
   ← 舊的記憶是用 v2 的 prompt 萃出來的,品質與新萃出的不一致。
     要不要重跑取決於你的記憶量與預算

五、評測:用官方框架測自己的資料

Mem0 把整套評測框架開源在 mem0ai/memory-benchmarks ,而且同時支援 Mem0 Cloud 與自架 OSS 後端

1git clone https://github.com/mem0ai/memory-benchmarks.git
2cd memory-benchmarks
3pip install -r requirements.txt
4
5# 測自架 OSS
6cp .env.example .env          # 填 OPENAI_API_KEY
7docker compose up -d          # 起本機 Mem0 server + Qdrant
8# Mem0 server: http://localhost:8888
9# Qdrant:      http://localhost:6333

5.1 三個 benchmark 該怎麼看

Benchmark測什麼規模官方分數
LoCoMo單跳/多跳/開放域/時序回憶92.5(6,956 tokens)
LongMemEval單/多 session、知識更新、時序94.4(6,787 tokens)
BEAM十類任務1M / 10M token64.1 / 48.6

BEAM 的 10M 結果才是真相。從 1M 到 10M,幾個分項的崩塌幅度很說明問題:

分項                    1M      10M     變化
────────────────────────────────────────────
preference_following    88.3 →  90.4    持平(甚至更好)
instruction_following   85.2 →  82.5    輕微下降
knowledge_update        65.0 →  75.0    反而上升
information_extraction  70.0 →  56.3    下降
summarization           63.5 →  46.9    明顯下降
multi_session_reasoning 65.2 →  26.1    ← 崩塌
event_ordering          53.6 →  20.2    ← 崩塌
temporal_reasoning      61.8 →  16.3    ← 崩塌

規律很清楚:「查一個事實」類的任務在大規模下仍然穩健(偏好、指令、知識更新),而「把多個事實按時間或因果串起來」的任務會崩塌。官方也直說這是「open problems across the field」,需要「higher-order representations of how events relate to each other across time」。

對你的產品意義:如果你的功能依賴「記得使用者喜歡什麼」——記憶層很可靠。如果依賴「推理出這些事件的先後順序」——在大規模下不要相信它,設計上要有降級路徑。

5.2 做自己的評測

官方 benchmark 是英文的,跟你的場景大概率不像。建議的做法:

1. 從生產 log 抽 50–100 組 (對話, 後續查詢, 期望撈到的記憶)
   ← 「期望撈到哪條」要人工標,這是全部的成本所在

2. 定義兩個指標:
   · Recall@k:期望的記憶有沒有進 top-k
   · Token 數:實際塞進 prompt 的 token
   ← 兩個都要看。只看 recall 會讓你一路把 top_k 調大

3. 建立基線,然後只改一個變數重跑:
   · 換 embedder
   · 開/關 reranker
   · 調 threshold
   · 換萃取模型
   · 開/關 infer

4. 把這個跑成 CI 的一部分
   ← 記憶系統的品質退化是靜默的。沒有回歸測試,
     你會在使用者抱怨的時候才發現三週前的那次改動出了問題

第 4 點是多數團隊會跳過、然後後悔的那一步。


六、整合生態

Mem0 的整合面很廣,值得知道有哪些,避免重造輪子。

Agent 框架       LangChain / LangGraph / LlamaIndex / CrewAI / AutoGen /
                Agno / Camel AI / OpenAI Agents SDK / Mastra /
                Vercel AI SDK / Strands / Google AI ADK …

AI 編碼工具      Claude Code / Cursor / Codex / OpenCode / Kimi Code /
                Antigravity …(多半透過 MCP)

語音/即時       LiveKit / Pipecat / ElevenLabs

低程式碼         Dify / Flowise / n8n / Zapier

可觀測性         AgentOps / Respan

6.1 MCP:最通用的接法

Mem0 提供 MCP server,這是把記憶接進任何支援 MCP 的客戶端的最短路徑——包括 Claude Code、Cursor 等編碼工具。

這帶出一個有趣的用法:把 Mem0 當成編碼 agent 的長期記憶,記住「這個 repo 的慣例是什麼」「上次為什麼選了這個方案」「哪些檔案碰不得」。這類知識目前多半寫在 CLAUDE.md / AGENTS.md 之類的檔案裡(Mem0 自己的 repo 就有這兩個檔案),但那是靜態的——記憶層能讓它隨著使用累積。

要注意的權衡:編碼場景的記憶如果記錯,代價是 agent 帶著錯誤的假設改程式碼。這比聊天場景記錯偏好嚴重得多。建議搭配 run_id 把實驗性的記憶隔離開,確認有用了再升級到 user_id 作用域。

6.2 框架整合的一個共同陷阱

多數框架整合都提供一個「自動記憶」的 wrapper:每輪對話自動 add()、每次呼叫前自動 search()很方便,也很貴。

Part 2 算過每次 add() 約 $0.002–0.02。自動模式下,一個 20 輪的對話就是 20 次 add()——而其中可能只有 3 輪有值得記的東西。

建議:用框架整合起步,但盡快換成手動控制——自己決定什麼時候呼叫 add()。一個簡單的過濾器(長度、是否第一人稱陳述、是否含決定性動詞)就能砍掉 50–70% 的無效呼叫。


七、成本模型與可觀測性

7.1 錢花在哪裡

┌──────────────────────────────────────────────────────────┐
│  LLM 萃取(占 90%+)                                      │
│  每次 add() 約 $0.002–0.02                                │
│  × 日均 add() 次數                                        │
│  ← 唯一有意義的優化方向                                    │
├──────────────────────────────────────────────────────────┤
│  Embedding(占 5%)                                        │
│  每次 add() 3 批、每次 search() 1 次                       │
│  單價極低(~$0.00002/次)                                  │
├──────────────────────────────────────────────────────────┤
│  向量庫(占 3%)                                           │
│  隨記憶總數線性成長                                        │
│  1536 維 × 4 bytes = 6 KB/向量                             │
├──────────────────────────────────────────────────────────┤
│  Reranker(若開,占 2%)                                   │
│  每次 search() 一次 API 呼叫                               │
└──────────────────────────────────────────────────────────┘

降成本的優先順序(效果由大到小):

  1. 減少 add() 的次數——不是每輪都記。一個前置過濾器的投資報酬率最高。
  2. 對結構化內容用 infer=False——表單欄位、系統事件、明確設定,零 LLM 成本。
  3. 換更便宜的萃取模型——但要先用自己的語料驗證萃取品質。
  4. 其他都是噪音。

7.2 該監控的六個指標

Mem0 沒有內建 metrics 端點,這些要自己埋:

指標怎麼算警訊
add() 的 LLM 呼叫量與成本從 LLM client 埋週環比成長超過對話量的成長 → 萃取變囉嗦了
每次 add() 產生的記憶數回傳陣列長度持續 > 5 → 可能在重複萃取既有記憶(Part 2 的失敗模式)
每使用者記憶總數定期 get_all() 統計活躍使用者 > 200 且同義重複明顯 → 該做合併作業了
search() 的 Recall@k靠標註集,離線跑下降 → 有東西壞了
search()max_possible_score 分布explain=True 抽樣不是 2.5 → 有訊號沒在跑(Part 3、Part 4)
messages 表大小SQL count無限成長 → 清理作業沒跑

第二個指標是最有診斷價值也最少人看的。 如果每次 add() 都產出 8–10 條記憶,而你的對話其實沒那麼多新資訊,八成是 LLM 把既有記憶當成新事實重新輸出了——記憶庫會以每次對話翻倍的速度爆炸。


八、生產檢查清單

安裝與設定

  • pip install "mem0ai[nlp]" 且下載了 spaCy 模型(否則實體訊號靜默失效)
  • 向量庫確認支援 keyword_search——用 explain=Truemax_possible_score 是不是 2.5
  • 版本鎖定,不用 latest(v2→v3 這種改版會直接改變行為)
  • 三個預設值明確寫出:top_kthresholdrerank
  • embedder 在 POC 階段就選定(換了要全量重建)

架構

  • add() 不在請求路徑上——丟背景 task 或佇列
  • search() 在呼叫模型前,結果有篩選後才進 prompt(不是全塞)
  • 有一個 wrapper 強制注入 user_id,業務程式碼碰不到裸的 Mem0(Part 4 第六節)
  • 多進程時 history 不用本機 SQLite

治理(ADD-only 的必要補償)

  • 有週期性的合併去重作業
  • messages 表的清理作業
  • 會過時的事實有設 expiration_date 或有時序補法
  • custom_instructions 要求記憶文字包含日期

安全與合規

  • 刪除流程涵蓋四處:向量庫記憶、實體庫、history 表、messages
  • 已實際跑過一次刪除並到資料庫確認乾淨
  • 知道 messages 表存的是未經萃取的原始對話,並據此評估風險
  • 不把密碼、金鑰、未遮蔽的敏感資料送進 add()
  • server/ 部署的 AUTH_DISABLED 不是 true

品質

  • 有 50–100 組的標註集
  • 標註集跑成 CI 的一部分
  • 每次改 embedder / 模型 / 參數都重跑
  • 監控「每次 add() 產生幾條記憶」

成本

  • 有前置過濾器,不是每輪都 add()
  • 結構化內容走 infer=False
  • LLM 呼叫量有監控與告警

九、為什麼選 X 不選 Y(彙整)

選擇                選 X 的理由                      不選 Y 的理由 / 翻轉條件
──────────────────────────────────────────────────────────────────────────────
OSS                 資料主權、後端自由、成本可控      要自己寫記憶治理
vs Platform         ────────────────────────────────────────────────────────
                    翻轉條件:見第三節的三個訊號。最實際的一條——當你發現
                    自己在寫「哪條才是最新」的邏輯,你正在重造 Supersede。

自己補時序          四個補法工程量都很小             Platform 的時序推理
vs 用 Platform      涵蓋大部分實用價值                LongMemEval 拿 97.0
                    ────────────────────────────────────────────────────────
                    翻轉條件:時序查詢是你產品的核心功能 → 用 Platform 或
                    改用以時序知識圖為核心的系統。偶爾用到 → 自己補就好。

自己補 Merge/Decay  可以照自己的業務規則調           一到兩週工程量 + 持續維護
vs 用 Platform      ────────────────────────────────────────────────────────
                    翻轉條件:這是四個裡最該考慮付錢的一個。合併去重要做對
                    (不誤刪、可追溯、冪等)比看起來難。

不補圖記憶          多數場景實體加權就夠              多跳關係查詢做不到
vs 外掛圖庫         ────────────────────────────────────────────────────────
                    翻轉條件:先確認你真的需要多跳查詢——在真實產品裡它的
                    出現頻率遠低於想像。真的需要 → 考慮專門的時序知識圖系統,
                    而不是在 Mem0 外面補。

手動控制 add()      成本降 50–70%                    要自己判斷什麼值得記
vs 框架的自動記憶   ────────────────────────────────────────────────────────
                    翻轉條件:POC 階段用自動的快速驗證。上線前一定要換手動。

先建標註集          所有調參的前提                   要人工標 50–100 組
vs 靠感覺調參       ────────────────────────────────────────────────────────
                    翻轉條件:無。沒有標註集,你對記憶系統的所有判斷都是猜的。
                    這是整個系列裡我最想強調的一件事。

十、系列導航

五篇走完了。回頭看,Mem0 的整個設計可以收斂成一條主線:

Part 1  問題:對話歷史的成本是二次方成長的,而 context 不是記憶
              → 要把「記什麼」和「取什麼」拆成兩個獨立的問題
                                    │
Part 2  寫入:單次 LLM 呼叫、ADD-only、hash 去重、spaCy 實體連結
              → 放棄了自動更新,換來不可逆錯誤的消失與成本減半
                                    │
Part 3  讀取:語意 + BM25 + 實體三訊號融合,自適應分母
              → 把「誰該排前面」的壓力全部接了下來
                                    │
Part 4  儲存:向量庫是主儲存、實體庫是反向索引、SQL 是稽核
              → 後端選擇決定了上面的機制有沒有真的在跑
                                    │
Part 5  治理:ADD-only 的熵增要靠外部解決
              → 那個「外部」就是 OSS 與 Platform 的分界線

每一層都在為下一層創造條件,而每一個設計決策都有一個明確的代價。這個系列反覆出現的方法論其實只有一句:先確認機制真的在跑,再談調參。

最後三個實務建議:

  1. 先建標註集,再做任何其他事。 50 組 (對話, 查詢, 期望記憶) 是你調校記憶系統的唯一依據。沒有它,換 embedder、開 reranker、調 threshold 全部是在賭。
  2. explain=True 確認三條訊號都在跑。 max_possible_score 不是 2.5,就代表你以為有的東西其實沒有。這個檢查只要一分鐘,卻能解釋大量「為什麼效果不如預期」。
  3. 把 ADD-only 的治理成本正式排進 roadmap。 它不會自己消失,而且它出現的時間點通常是產品剛開始成長、你最忙的時候。不管是自己寫還是付錢買,都要在那之前決定。

Part 4 — 儲存層與後端選型 — 三個 store、25 種向量庫與那個關鍵能力差異

系列全部文章:


本文基於 mem0 main 分支(2026 年 9 月,版本 2.0.20)原始碼與官方文件撰寫。OSS 與 Platform 的差異對照 docs/platform/platform-vs-oss.mdx,遷移清單對照 docs/migration/oss-v2-to-v3.mdx,benchmark 數字與 Dream/Memory Decay 的機制對照 docs/core-concepts/memory-evaluation.mdxdocs/platform/features/。官方明載 benchmark 分數反映的是託管平台(含 OSS 沒有的專有優化),自架版本應預期方向一致但數值不同。成本與工程量估計為量級估算。

Yen

Yen

Yen