用一台 Mac mini 跑你自己的 AI Agent 記憶引擎——Memory Hall 入門

你在做 AI agent,每個 agent 都會產生記憶——對話、決策、實驗結果。這些記憶要放哪?Memory Hall 讓「自建記憶層」從「最麻煩的選項」變成三個命令的事。這篇介紹它是什麼、怎麼用、跟 mem0 差在哪。

用一台 Mac mini 跑你自己的 AI Agent 記憶引擎——Memory Hall 入門

你在做 AI agent,每個 agent 都會產生記憶——對話、決策、實驗結果、外部查到的事實。這些記憶要放哪?

三個選項:

  • 放 OpenAI / Anthropic 的 memory:綁死在他們的 session / workspace 概念裡
  • 放 mem0 / Zep 之類的 SaaS:API 可控但部署在別人家
  • 放自己的:自由度最高,但你要自己寫

第三條路原本是最麻煩的。Memory Hall 把它變成三個命令的事。

git clone https://github.com/MakiDevelop/memory-hall
cd memory-hall && docker compose up -d
curl -X POST http://localhost:9100/v1/memory/write -d '...'

這篇是入門介紹——不講哲學、不談反省,單純告訴你這是什麼、能做什麼、怎麼用


Memory Hall 是什麼

一句話:一個在你自己的機器上跑的 AI agent 記憶引擎

三個零件:

  • SQLite:資料放一個 .sqlite3 檔,要搬家 mv 就好
  • sqlite-vec:向量索引是 SQLite 的 virtual table,沒有「再起一個 vector DB」的麻煩
  • Ollama(或你自選的 embedder):把 content 轉成 embedding,offload 到家裡任何一台 GPU 機器

三種入口:

  • HTTP APIPOST /v1/memory/write / search):最通用
  • CLImh serve / mh reindex-fts):運維用
  • Python embeddedfrom memory_hall import ...):沙盒 / 零網路環境用

Quickstart:三步跑起來

Step 1. 抓 repo + 啟動

git clone https://github.com/MakiDevelop/memory-hall
cd memory-hall
docker compose up -d

預設會在 localhost:9100 開 HTTP server,資料寫進 ./data/memory-hall.sqlite3

如果你家裡有 Ollama,Memory Hall 會連到 http://host.docker.internal:11434bge-m3 embedder。沒 Ollama 也沒關係——寫入會回 202 Accepted + sync_status=pending,背景 worker 會在 Ollama 上線後自動補 index。

Step 2. 寫一筆記憶

curl -X POST http://localhost:9100/v1/memory/write \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "my-agent",
    "namespace": "shared",
    "type": "episode",
    "content": "今天完成了 Memory Hall v0.2 的 deploy",
    "tags": ["milestone", "memory-hall"]
  }'

回傳:

{
  "entry_id": "01KPJ...",
  "embedded": true,
  "sync_status": "embedded",
  "created": true
}

內建 content_hash dedup——同樣內容再寫一次會拿回既有 entry_id,不會重複。

Step 3. 搜它

curl -X POST http://localhost:9100/v1/memory/search \
  -H "Content-Type: application/json" \
  -d '{
    "query": "v0.2 進度",
    "mode": "hybrid",
    "limit": 5
  }'

mode 三選一:

  • hybrid:BM25 lexical + bge-m3 semantic 融合(預設,命中率最好)
  • lexical:純 keyword 比對
  • semantic:純向量相似度

CJK 原生:中文 query 真的會命中

大部分 OSS memory engine 用 SQLite 的 unicode61 tokenizer,對中文是災難——因為它把一整串無空白的中文當一個 token,substring 都搜不到。

Memory Hall 用 jieba 預切詞。差別直接看數字:

# 寫一筆純中文的記憶
curl ... -d '{"content": "最近又撞牆了,sqlite-vec 的 ARM64 wheel 是 32-bit"}'

# 查 "撞牆"
curl ... -d '{"query": "撞牆", "mode": "lexical"}'

v0.1(unicode61)BM25 score:0(miss)
v0.2(jieba pre-tokenize)BM25 score:0.26(hit)


Python Embedded:零網路場景用

不想 / 不能跑 HTTP?直接 import:

import asyncio
from memory_hall import Settings, build_runtime
from memory_hall.models import WriteMemoryRequest, SearchMemoryRequest

async def main():
    settings = Settings(
        database_path="./data/memhall.sqlite3",
        vector_database_path="./data/memhall-vectors.sqlite3",
        ollama_base_url="http://localhost:11434",
    )
    runtime = build_runtime(settings)
    await runtime.start()

    await runtime.write_entry(WriteMemoryRequest(
        agent_id="sandbox",
        namespace="shared",
        type="note",
        content="寫進 embedded runtime 不需要網路",
    ))

    results = await runtime.search_entries(SearchMemoryRequest(
        query="embedded",
        mode="hybrid",
        limit=3,
    ))

    await runtime.stop()

asyncio.run(main())

這條路徑是為了 sandbox agent 設計的——有些 CLI agent(Codex headless / Gemini 某些配置)連 localhost TCP 都被擋,只能走 in-process。


部署拓樸:從 laptop 到家用伺服器

Memory Hall 跟你的機器規模 adapt:

A. 最小:一台 laptop

[你的 MacBook]
├── Docker Desktop
│   └── memory-hall container (port 9100)
└── Ollama(macOS native,不要放 Docker 裡會慢)

每個 agent 寫進 localhost:9100。適合:個人 PoC、demo、offline 工作。

B. 家用伺服器

[Mac mini / 小主機]
└── memory-hall container(24/7 跑)
         ↑
         │  Tailscale
         ↓
[DGX Spark / 其他 GPU 機]
└── Ollama bge-m3 (OLLAMA_KEEP_ALIVE=-1)

Memory Hall 和 embedder 分開部署——embedder 常吃記憶體,放有 GPU 的機器。我家裡是 DGX Spark(128GB 統一記憶體)跑 bge-m3,Memory Hall 跑在 Mac mini。

C. 多機冷備

[Mac mini #1 primary]
└── memory-hall:0.2.0 container running

          │ rsync /5 min
          ↓

[Mac mini #2 cold standby]
└── memory-hall:0.2.0 container created (stopped)

primary 掛掉 → 手動 docker start memory-hall on #2 接手。不是真正的 HA(沒共識、沒自動 failover),但對家用 / 個人來說,rsync 冷備等於 80% 的實 HA 價值,維護成本是 0。


為什麼不用 mem0(實際踩過的六個坑)

mem0 是市面上最成熟的 AI agent memory SaaS。我用了幾個月,把它當我七位一體 stack 的記憶層。最後決定自己寫,理由是實戰踩到的:

1. SaaS-only 卡死沒網路場景

我的 agent stack 有一部分跑在沒網路的環境——Codex CLI 的 headless 模式、Gemini CLI 某些配置、air-gapped 的機器、Claude Code 的 sandbox agent。SaaS-only 直接卡。我需要 Python import 就能跑的記憶層(Memory Hall 的 embedded mode)。

2. 中文 recall 極低

我的記憶內容 70% 是中文。mem0 / 大部分 OSS memory engine 的預設索引對中文 query 命中率極低——原因是 unicode61 tokenizer 把一整串無空白中文當一個 token,substring 都搜不到。純 CJK query 幾乎全 miss。

Memory Hall 用 jieba 預切詞解決這件事。

3. 版本 API 節奏我不能 pin

mem0 的服務端 API / 檢索行為會隨他們 roadmap 變動。agent stack 的基礎依賴不能綁在外部的演進節奏上——我需要版本釘在我的 lock file 裡,而不是被動接受服務端升級。

4. 黑盒無法 debug

recall 結果奇怪的時候,我沒辦法看他們 server 在做什麼。對 agent stack 這種「每次查詢都要信任」的基礎設施,黑盒讓你連「這個 query 為什麼 miss」都回答不了。

Memory Hall 是 SQLite——你可以直接 sqlite3 memhall.sqlite3 開進去看 FTS5 索引長什麼樣、BM25 分數怎麼算。

5. 搬家成本

真的決定換 backend,mem0 的 export API 出來的 schema 還要自己轉換成下一家的格式。Memory Hall 的「搬家」是 mv memhall.sqlite3 /path/to/new/host/,一個檔案的事。

6. 定價與供應商風險

SaaS 月費會變、API 會變、公司可能被收購或轉向。agent stack 的底層不要有這種變數——今天你在 500 entries,明天 50k entries,pricing 曲線不是你能控制的。

Memory Hall 的成本就是你家那台機器的電力。entry 數量不影響月費(因為沒有月費)。


不是說 Memory Hall 比 mem0 好。是說 SaaS 的 trade-off 對我這個使用情境不 work。

Memory Hall mem0
部署 你家 / 自己的雲 / laptop 他們的 cloud
資料位置 你的 SQLite file 他們的 DB
Offline / sandbox 支援(embedded mode) 不支援
CJK jieba 原生 英文優先
Version pin 你的 lock file 服務端節奏
Debug SQLite 直接看 黑盒
搬家 mv 一個 file export API + 轉換
Embedder 選擇 你選 他們的
Lock-in 零(Apache 2.0) 中到高
成本 0 月費 按量計費

你的情況如果以上 6 點都不是問題,mem0 的 UX 更精緻、功能更完整,直接用它省事。

但如果這 6 點任何一條你也踩到過——sandbox 卡死 / CJK miss / 版本被動 / debug 無門 / 搬家痛 / pricing 焦慮——Memory Hall 值得試。


現在能做 / 現在不能做

v0.2 能做

  • HTTP / CLI / Python embedded 三種入口
  • 多租戶 schema from day one
  • CJK jieba 分詞,recall 有保證
  • 寫入 durability + concurrency benchmark 全綠(50-way burst 零流失)
  • 寫入不阻塞:202 accepted pattern,embedder 掛了也不掉資料
  • Docker 單 container or docker compose 部署

v0.2 還沒做(刻意 / 不刻意)

Feature 為什麼現在不做 什麼時候做
MCP server use case 還沒浮現,protocol 本身還在動 v0.3(1-2 週內)
Auth 個人 / home lab 用不到,早期挑錯 pattern 難改 有 production exposure 需求時
Replica / HA SQLite 的價值就是單機簡單,做 HA 要換 adapter 換 Postgres adapter 時(v2.0+)
Enrichment 刻意不做。engine 只管儲存,enrichment 在上層 永遠不在 memhall repo 做

這些決策的完整 rationale 在另一篇 三個月的 over-design 反省


什麼樣的人適合現在就用?

適合

  • 個人開發者 / 小團隊做 AI agent,需要本地可控的記憶層
  • 寫的記憶主要是中文 / 中英混合,對 CJK recall 敏感
  • 要 sandbox / offline / 零網路場景(Codex CLI / Gemini CLI / air-gapped)
  • 有一台 Mac mini、小 server、或任何能跑 Docker 的機器
  • 對「資料放自己家」有偏執

暫時不適合

  • 需要多地多中心 HA(換 Postgres + pgvector 吧)
  • 要百萬 entry 以上的生產規模(sqlite-vec 舒服範圍 ~100k)
  • 完全沒空做任何 devops(SaaS 比較適合你)

怎麼試

git clone https://github.com/MakiDevelop/memory-hall
cd memory-hall
docker compose up -d
curl http://localhost:9100/v1/health

看到 {"status":"ok","storage":"ok","vector_store":"ok","embedder":"ok"} 就可以開始寫記憶了。

有問題、有建議、有想加的 feature,去 GitHub 開 issue:

OSS: github.com/MakiDevelop/memory-hall


我是江中喬,一位具有 TPM 與產品管理背景的 AI 系統建構者,目前專注於 AI 認知增強系統與多 Agent 協作架構的設計與實踐。