三只貓
Rich Mindset Zone
richmindsetzone.com
← All posts

Rust + SQLite + Graph:Mnemo 的 Local-First AI Memory 架構深度拆解

如果你呢半年有用過任何 AI coding agent,你大概已經撞過呢幅牆:每次開新 session,個 agent 就失憶。唔係「記性唔好」,而係 stateless 嘅架構先天決定咗佢每句話都係由零開始。我哋嘅解法一直係餵更多 context、寫更長嘅 system prompt、或者開 cloud-based memory service。但呢啲全部係治標。

Mnemo 揀咗一條完全唔同嘅路:用 Rust 寫一個 local-first 嘅 AI memory layer,以 SQLite 做 storage、petgraph 做 knowledge graph,出嚟嘅係一個 single binary、zero runtime dependency、可以放入任何 LLM workflow 嘅記憶系統。本文唔係介紹文,而係深入睇佢嘅 architecture decisions——點解係 Rust?點解係 graph 而唔係 vector-only?點解要 session-scoped scoring?呢啲選擇背後嘅 trade-off 先係值得我哋香港 developer 留意的嘢。

Rust 嘅選擇:唔係 performance,而係 deployability

好多 projects 揀 Rust 係因為快。Mnemo 揀 Rust,我認為更核心嘅原因係 deployability。呢個記憶 layer 嘅設計目標係「任何 LLM 都可以用」,意味住佢要俾人 embed 落去 Python、Node.js、或者直接俾 Claude Code / Cursor 嘅 MCP server 叫。如果佢用 Python 寫,你就要成個 Python runtime + pip dependencies;如果用 Go 寫,CGO 嘅 cross-compilation 會搞到你喊。

Rust 編譯出嚟嘅 single binary,static link 晒所有 dependencies(包括 SQLite),放喺 server 又好、local machine 又好、甚至 Raspberry Pi 都好,chmod +x 就行得。呢種「zero friction distribution」對於一個 infra component 嚟講係決定性嘅優勢。加上 Rust 嘅 memory safety guarantee——記憶系統處理嘅就係 memory,如果個 memory layer 自己都有 memory leak 就諷刺了——呢個 consistency 唔係性能問題,而係信任問題。

另一個層面係 FFI 嘅易用性。Mnemo 可以 expose C ABI,然後任何語言都可以 call。Python 用 ctypes、Node 用 napi-rs、甚至 Swift 都可以直接 bind。呢種語言無關嘅 interface 設計,係一個 infra project 成熟嘅標誌。

SQLite + petgraph:點解唔用 vector database?

當你諗到「AI memory」,多數人第一個反應係 vector database。Chroma、Pinecone、Weaviate——成個生態都係圍繞 embedding similarity 去建構。Mnemo 嘅做法係 graph-first:用 SQLite 儲存 entities 同 relations,用 petgraph 做 in-memory graph traversal,然後先 optional 用 vector search 做補充。

點解要咁做?因為 AI agent memory 嘅查詢模式同 RAG 好唔同。RAG 嘅典型 query 係「搵同呢段 text 相似嘅 documents」,用 cosine similarity 就搞定。但 agent memory 嘅 query 係「我上次係點樣解決呢個 dependency injection 問題嘅?」或者「呢個 project 用緊邊個 logging framework?點解當初咁揀?」呢啲問題涉及到 entity resolution 同 relation traversal——你唔只需要搵到一個 document,你需要沿住關係鏈行一兩步:project → decision → rationale。

Graph 喺呢度嘅優勢係 exact match 同 multi-hop traversal。Vector similarity 可以話你知「呢段 text 有八成似」,但 exact match 先可以話你知「呢個就係你上個星期 commit 嗰個 decision」。Mnemo 嘅 entity deduplication 機制就係靠 graph 嘅 identity resolution:當你 write 一個 memory 提及「use SQLite for storage」,而之前已經有一個 entity「storage backend: SQLite」,graph 會 merge 或 link 而非 duplication。

Session-scoped scoring 係另一個 graph-first 先做到嘅嘢。每個 memory entry 嘅 relevance score 唔係 global 嘅,而係相對於當前 session context 計算。當 agent 喺 debugging session 入面,architecture decision 嘅 score 會低過最近嗰個 bug fix 嘅 record。呢種 contextual weighting 喺 flat vector store 好難做,但喺 graph 上面加上 temporal edges 同 session-context nodes 就自然好多。

Multi-hop traversal 同 memory decay 嘅實際設計

講到 multi-hop traversal,其實係 Mnemo 最值得拆解嘅部分。假設 agent 要回答一個問題:「點解我哋當初唔用 PostgreSQL?」呢個唔係一個 fact retrieval,而係一個 reasoning path:搵到 decision record → 睇到佢嘅 context(當時 scalability requirement 未確定)→ 搵到 alternative considered(PostgreSQL, MySQL, SQLite)→ 睇返 pros/cons 嘅 analysis。呢個就係 3-hop traversal。

Mnemo 嘅 petgraph 實作將每個 memory entry 當做一個 node,唔同類型嘅 edges 代表唔同關係(caused_bysupersedesreferencescontradicts)。Traversal 嘅深度同廣度可以根據當前 token budget 同 context window 去 adjust。呢個 dynamic control 係實務上好重要——你唔想一個 traversal 行到成個 graph 都翻出來,然後 exceed context window。

Memory decay 嘅設計亦值得一提。Mnemo 用 Weibull distribution 去 model 遺忘曲線(取代咗早期嘅 Ebbinghaus curve),因為 Weibull 有更大嘅 flexibility 去 fit 實際使用 pattern。關鍵 insight 係:唔同類型嘅 memory 應該有唔同嘅 decay rate。一個「bug fix」可能喺 fix 之後一個星期就冇用,但一個「architecture decision」可能要 keep 幾個月。Mnemo 呢種 type-aware decay 係將 memory 當做 first-class citizen 去設計,而唔係事後先加嘅 feature。

Contradiction detection 仲進一步。當新 memory 同現有 graph 入面嘅某個 node 有衝突,Mnemo 唔係就咁 overwrite,而係 create 一個新 node 加上 contradicts edge,然後將舊 node 嘅 score 降低但唔刪除。呢個設計容許 agent 睇到 decision evolution——你點樣由一個諗法轉去另一個,而唔係得個最終結果。

無 cloud、無 config、無 runtime:local-first 嘅工程取捨

Mnemo 自稱「local-first」,呢個唔係 marketing term 而係 engineering constraint。成個系統嘅設計假設係:network 可能唔存在、latency 必須 predictable、data 必須喺你控制之下。呢個 constraint 推出來嘅 design 同 cloud-native memory system 好唔同。

第一,SQLite 做 storage 意味住 write contention 要喺 application layer 解決。Mnemo 用 WAL mode + 精細嘅 transaction batching 去 minimis lock contention。對於 single-agent use case 嚟講呢個已經夠用,但如果要 multiple agents 同時寫入同一個 memory file,SQLite 嘅瓶頸就會出現。呢個係一個 conscious trade-off——Mnemo 揀咗 simplicity over scalability。

第二,冇 cloud 意味住 cross-device sync 係你自己嘅責任。Mnemo 唔 try to solve distributed memory sync,而係俾你 access 到 raw SQLite file,你自己用 Syncthing / iCloud / Dropbox 去 sync。呢個係好老實嘅設計——與其做一個半桶水嘅 sync layer,不如俾你用地獄級成熟嘅 tooling。

第三,BM25 + vector + graph 嘅 triple retrieval 係為咗補償 local-only 嘅 limitation。Cloud memory system 可以用 huge embedding model、可以用 reranker、可以用 LLM-as-judge。Local-first 冇呢個 luxury,所以要喺 algorithmic layer 做多啲嘢:BM25 做 keyword exact match、vector 做 semantic similarity、graph 做 relation traversal。三個結果 fusion 之後再 scoring,出嚟嘅 recall 可以去到接近 cloud solution,但 latency 係單 digit milliseconds 而唔係幾百 ms。

對香港嘅獨立開發者或者細 team 嚟講,呢種 philosophy 特別有吸引力。唔使你開 account、唔使你畀 credit card、唔使你擔心 vendor lock-in。你ctrl+c ctrl+v 個 binary 去新 server,就係咁簡單。

結語:Memory 嘅 architecture 問題唔可以用 API 解決

回望 Mnemo 嘅設計,最值得學習嘅唔係 Rust 或者 petgraph 嘅技術細節,而係一個 philosophy:AI agent memory 係一個 architecture 問題,唔係一個 API 問題。市場上有大把 memory-as-a-service 嘅 product,佢哋解決嘅係 deployment friction,而唔係 memory 嘅 fundamental problem——點樣 structure、retrieve、同 evolve agent 嘅 knowledge。

Mnemo 嘅 graph-first 路線、SQLite 嘅 embedded-first 選擇、session-scoped 嘅 contextual scoring,呢啲唔係 random decisions 而係一條 consistent 嘅設計鏈。如果你而家正喺度 build 或者 integrate AI agent memory,我建議你做三件事:

一、搞清楚你嘅 agent 需要咩類型嘅 memory。如果只係要 session context,一條 FIFO queue 就已經夠。如果你需要跨 session 嘅 knowledge 累積,先值得考慮 graph-based system。 二、唔好假設 cloud memory 係 default。Local-first 嘅 memory layer 唔單止平啲、快啲、重複可靠啲,而且逼你思考 memory 嘅 data model——呢個思考過程本身就有價值。 三、去 read Mnemo 嘅 source code(github.com/zaydmulani09/mnemo)。呢個 project 得幾個月大,codebase 仲細,但入面嘅 trade-off 決策已經好清晰。喺 AI tooling 圈入面,呢種「先諗清楚架構再 code」嘅態度越嚟越少見。