測試環境: Mac Studio M3 Ultra · 96GB RAM · Apple Silicon MPS 加速
數據規模: 117 個 Markdown 源文件 · 879 條記憶段落 · 7,911 次跨數據庫寫入
嵌入模型: BGE-m3(BAAI,1024 維,本地推理)
為什麼需要十個數據庫?
在 AI 記憶系統的設計中,一個核心問題是:用什麼數據庫來存儲和搜索記憶?
傳統的單一數據庫方案有一個致命缺陷:沒有任何一個數據庫能同時做好向量語義搜索、全文關鍵字匹配、關係圖遍歷、SQL 聚合查詢、亞毫秒級快取。就像你不會用菜刀去開罐頭,每種查詢都需要最適合它的引擎。
「Polyglot Persistence 的核心思想:不是把數據存十份,而是用十種不同的方式理解同一份數據。」
MemoryHub v2.0 實現了這個理念:文本進入 → BGE-m3 模型嵌入一次(1024 維向量)→ 同時寫入十個後端。每個後端保留同一份數據的不同「視角」,讓每種類型的查詢都能找到最優解。
十個後端及其角色
| 後端 | 類型 | 核心能力 | 在這個系統的角色 |
|---|---|---|---|
| 🧠 Qdrant | 專用向量庫 | 語義相似度搜索 | 🏆 主力搜索引擎 |
| 📦 Chroma | 嵌入式向量庫 | 輕量本地向量 | 🪶 備援引擎 |
| 🪶 LanceDB | 列式向量庫 | 大規模分析查詢 | 📊 分析型查詢 |
| 🗃️ SQLite-vec | SQL + 向量 | 嵌入式 SQL 查詢 | 📝 離線場景 |
| 🔍 FAISS | 純向量索引 | 暴力搜索天花板 | ⚡ 速度之王 |
| ⚡ Redis | 內存鍵值庫 | 亞毫秒讀取 | 🚀 熱數據快取 |
| 🐘 PostgreSQL | 關係型 + 向量 | SQL JOIN / 聚合 | 🏛️ 結構化查詢 |
| 🔎 Elasticsearch | 全文搜索引擎 | 倒排索引關鍵字 | 📖 關鍵字搜索 |
| 🍃 MongoDB | 文檔數據庫 | 靈活 Schema | 📄 半結構化存儲 |
| 🔗 Neo4j | 圖數據庫 | 關係圖遍歷 | 🕸️ 實體關聯查詢 |
導入實測:117 文件 → 7,911 次寫入
數據來源
測試數據來自君澤智庫 AI 助理(UltraClaw)的完整記憶庫:每日工作日誌、長期記憶 MEMORY.md、項目檔案、踩坑記錄、系統配置等共 117 個 Markdown 文件。
導入管線
每條數據經過完全相同的處理流程,模擬真實的 MemoryHub 捕獲管線:
源文件 (.md)
↓ 按 ## 標題分段(每段 ≤1,800 字符)
BGE-m3 嵌入(1024 維向量,Apple Silicon MPS 加速)
↓ 一次嵌入,十路寫入
Qdrant ✓ Chroma ✓ LanceDB ✓ SQLite-vec ✓ FAISS ✓
Redis ✓ PostgreSQL ✓ Elasticsearch ✗ MongoDB ✓ Neo4j ✓
| 指標 | 數值 |
|---|---|
| 源文件 | 117 |
| 生成段落 | 879 |
| 寫入總次數 | 7,911(9 後端 × 879) |
| 失敗次數 | 0 |
| 總耗時 | 5.2 分鐘 |
| 穩態速度 | ~3 條/秒 |
Elasticsearch OOM
Elasticsearch 在導入過程中因 Docker 容器 OOM(內存不足)退出(exit code 137)。Mac Studio 同時運行 10 個數據庫容器 + BGE-m3 嵌入模型,內存壓力極大。ES 被暫時禁用,其餘九個後端全部成功。
⚠️ 教訓: 在單機環境運行 10 個數據庫時,Elasticsearch 需要至少 1-2GB 的堆內存配置(
-e ES_JAVA_OPTS="-Xms512m -Xmx512m"),否則 JVM 容易被 OOM Killer 終止。
搜索評測:九大後端同台競技
測試方法
使用相同查詢關鍵詞 「香港照相機公司 張總 併購 千年健康」,對九個在線後端分別執行語義搜索。記錄最高相關度分數、命中數量、查詢耗時、以及 Top-1 結果的內容。所有後端使用相同的 BGE-m3 查詢向量。
搜索結果總表
| # | 後端 | 最高分 | 命中 | 耗時 | Top-1 內容摘要 |
|---|---|---|---|---|---|
| 🥇 | Qdrant | 0.738 | 5 | 66ms | 「張總已轉向香港照相機公司併購標的」 |
| 🥈 | FAISS | 0.707 | 5 | 3ms | 同上 |
| 🥉 | MongoDB | 0.707 | 5 | 107ms | 同上 |
| 4 | LanceDB | 0.587 | 5 | 197ms | 同上 |
| 5 | SQLite-vec | 0.707 | 5 | 260ms | 同上 |
| 6 | Chroma | 0.294 | 5 | 300ms | 同上(但分數腰斬) |
| 7 | Neo4j | 0.707 | 5 | 573ms | 同上 |
| 8 | Redis | 0.707 | 5 | 996ms | 同上 |
| 9 | PostgreSQL | 0.000 | 0 | 504ms | N/A(Bug) |
核心發現一:分數為什麼不一樣?
這是這次評測最關鍵的發現。所有後端存儲的是完全相同的向量,搜索時使用的也是完全相同的查詢向量。但結果的相關度分數卻天差地別。
分數差異的三層原因
-
Qdrant(0.738)— 原生 Cosine + HNSW 索引優化
Qdrant 是專用向量數據庫,內置 Cosine Distance 的 HNSW(Hierarchical Navigable Small World)索引。算法層面的優化讓它不僅快,而且精準度最高。 -
FAISS / SQLite / MongoDB / Redis / Neo4j(0.707)— 手動 Cosine Similarity
這些後端本身不具備原生向量搜索能力。評測中使用了 numpy 手動計算 Cosine Similarity(np.dot / (norm1 * norm2))。所有後端分數一致,因為用的是同一套公式。 -
LanceDB(0.587)和 Chroma(0.294)— 內部距離度量不同
LanceDB 默認使用 L2/Euclidean 距離而非 Cosine,導致分數偏低。Chroma 使用自己的 HNSW Cosine 實現,但精度有明顯折損(分數直接腰斬)。
「Qdrant 的 0.738 和 Chroma 的 0.294 之間的差距,不是數據不同,而是距離度量算法的不同。」
核心發現二:速度之爭 — 索引 vs 暴力搜索
搜索耗時對比
| FAISS | 3ms | | Qdrant | 66ms | | MongoDB | 107ms | | LanceDB | 197ms | | SQLite-vec | 260ms | | Chroma | 300ms | | Neo4j | 573ms | | Redis | 996ms |
FAISS 3ms 的秘訣: 它是 Facebook 開發的純 C++ 向量索引庫,使用 IndexFlatIP(內積)暴力搜索。沒有任何網絡開銷、沒有 JSON 序列化、沒有查詢解析——就是赤裸裸的矩陣運算。在 3,245 個 1024 維向量中搜索,3ms 是 CPU 級別的天花板。
Redis 996ms 的教訓: Redis 作為內存數據庫本該最快,但評測中反而是最慢的。原因是每次搜索需要遍歷 500 個 key,每個 key 做一次 JSON.GET 操作 + numpy 向量計算。Redis 的優勢在於已知 key 的點查詢(亞毫秒),而非全表掃描。
💡 關鍵洞察: 向量搜索的速度瓶頸不在「計算」,而在「數據傳輸」。FAISS 因為零網絡開銷而最快;Redis 因為 500 次獨立請求而最慢。
每個後端的最佳場景
| 使用場景 | 推薦後端 | 原因 |
|---|---|---|
| 🎯 日常語義搜索 | Qdrant | 最高相關度 0.74 + 66ms 延遲 |
| ⚡ 高吞吐批量搜索 | FAISS | 3ms 極速,無需 Docker |
| 🔗 關係脈絡查詢 | Neo4j | 「張總→哪些項目→哪些會議」圖遍歷 |
| 📖 關鍵字全文搜索 | Elasticsearch | 倒排索引(需解決 OOM) |
| 🏛️ SQL 聚合報表 | PostgreSQL | JOIN、GROUP BY、時間範圍過濾 |
| 🗂️ 靈活 Schema 存儲 | MongoDB | 不同格式的記憶混存,107ms 實用 |
| 🚀 熱數據即時快取 | Redis | 亞毫秒點查詢 |
| 🪶 離線/嵌入式場景 | SQLite-vec / Chroma | 一個文件搞定,不需 Docker |
踩坑記錄
| # | 問題 | 根因 | 狀態 |
|---|---|---|---|
| 1 | ES OOM 退出 | JVM 堆內存不足,被系統 OOM Killer 終止 | ⚠️ 加內存限制重啟 |
| 2 | PG 向量字串化 | psycopg2 返回字串而非 Python list | ⚠️ 需 json.loads() |
| 3 | SQLite/FAISS 路徑錯誤 | 配置文件路徑與代碼默認路徑不一致 | ✅ 已修復 |
| 4 | Routing 未覆蓋部分後端 | multi_save routing 遺漏 SQLite-vec 和 FAISS |
⚠️ 架構級 bug |
結論
「Polyglot Persistence 不是學術概念,而是經過 7,911 次寫入驗證的工程實踐。十個數據庫各司其職,Qdrant 是語義之王,FAISS 是速度之王,Neo4j 是關係之王。」
三個關鍵結論
-
向量搜索的「相關度」由距離度量決定,不是由數據庫品牌決定。
Qdrant 的 0.738 vs Chroma 的 0.294,差距來自算法實現,而非數據差異。選擇向量數據庫時,必須測試其實際的距離度量精度。 -
「一次嵌入、多路寫入」的架構是可行的,且開銷可控。
879 條數據在 5.2 分鐘內完成 7,911 次寫入,穩態速度 ~3 條/秒。瓶頸在各後端的寫入延遲,而非嵌入計算(嵌入僅 18-42ms)。 -
沒有銀彈。每種查詢用最適合的引擎。
日常對話用 Qdrant 語義搜索、報表分析用 PostgreSQL SQL、關係脈絡用 Neo4j 圖遍歷、全文匹配用 Elasticsearch——這不是冗餘,這是把對的工具用在對的場景。
下一步
後續計劃修復 PostgreSQL 向量反序列化和 Elasticsearch OOM 問題,補齊十後端全覆蓋;並在真實用戶場景中測試混合查詢(Multi-Engine Fusion Search)——同時調用多個後端、合併排序結果的搜索質量。
評測執行:UltraClaw · 君澤智庫 AI 助理 · 2026 年 5 月 22 日
數據來源:MemoryHub v2.0 · BGE-m3 · Mac Studio M3 Ultra