R-Mem
April 13, 2026 · View on GitHub
R-Mem
AI Agent のための長期メモリ — Rust で実装
mem0 のメモリアーキテクチャを Rust で研究する軽量実装。
シングルバイナリ。SQLite バックエンド。Python 不要。
Note
本プロジェクトは学習目的で、mem0 の優れたメモリアーキテクチャを Rust で再実装したものです。オリジナルの設計は mem0 チームの功績です。これは代替品ではなく、異なる言語によるアーキテクチャの研究です。ディスカッション、アイデア、コントリビューションを歓迎します!
なぜ R-Mem か?
mem0 は優れた設計のメモリシステムであり、豊富な plugin エコシステムを持っています。R-Mem はより狭い問いを立てています:コアのメモリロジックだけを Rust で書き直し、完全に SQLite をバックエンドにしたらどうなるか?
結果は同じ三層アーキテクチャ — vector memory、graph memory、history — と 階層アーカイブ システムを 2,826 行の Rust で実現。外部サービス不要。バイナリ一つ。トレードオフは明確:統合の数は mem0 よりはるかに少ないが、運用オーバーヘッドはほぼゼロ。
R-Mem は RustClaw から生まれました — 私たちのミニマリスト Rust AI agent フレームワークです。RustClaw にはその哲学に合ったメモリレイヤーが必要でした:シングルバイナリ、外部サービスゼロ。そこで mem0 のアーキテクチャを研究し、Rust で再構築しました。
| R-Mem | mem0 | |
| 📦 バイナリ | 3.6 MB 静的リンク | Python + pip(豊富なエコシステム) |
| 💾 アイドル RSS | < 10 MB | 200 MB+(より多くの機能をロード) |
| 📝 コード | 2,826 行 | ~91,500 行(26+ 種の store driver) |
| 🔍 Vector | SQLite + FTS5 | Qdrant、Chroma、Pinecone… |
| 🕸️ Graph | SQLite のみ | Neo4j / Memgraph |
| 🤖 LLM | OpenAI、Anthropic、Ollama | OpenAI、Anthropic など |
| 🗄️ Archive | 階層メモリ + fallback 検索 | — |
mem0 の数字は豊かなエコシステムを反映しています — より多くの store、より多くの統合、より多くの柔軟性。R-Mem は最小限のフットプリントのためにそれらを意図的にトレードオフしています。
R-Mem が mem0 に追加する機能
| 機能 | R-Mem | mem0 |
|---|---|---|
| 階層アーカイブ | 削除/更新されたメモリを保存 + fallback 検索 | 削除されたら消失 |
| FTS5 プリフィルタ | 2 段階検索:キーワード → vector(19 倍高速) | vector のみ |
| MCP Server | 内蔵 rustmem mcp、Claude Code / Cursor 対応 | 提供なし |
| 依存ゼロのデプロイ | シングルバイナリ、SQLite、Docker 不要 | Python + pip + vector DB + graph DB |
| Anthropic ネイティブ対応 | Claude API を直接サポート | OpenAI 互換プロキシ経由 |
| 設定可能なパイプライン | [memory] セクション:閾値や上限などすべて調整可能 | ハードコードされたデフォルト |
| メモリカテゴリ | 自動分類:preference, personal, plan, professional, health | 非構造化 |
🔍 仕組み
Input text
│
├─ 📦 Vector Memory ──────────────────────────────────
│ │
│ ├─ LLM が事実を抽出
│ │ → ["Name is Alice", "Works at Google"]
│ │
│ ├─ Embedding → cosine similarity 検索
│ │ (FTS5 プリフィルタ + vector ランキング)
│ │
│ ├─ Integer ID mapping
│ │ (LLM の UUID ハルシネーション防止)
│ │
│ ├─ LLM が各事実について判定:
│ │ ├─ ADD 新しい情報
│ │ ├─ UPDATE より具体的 → 旧バージョンをアーカイブ
│ │ ├─ DELETE 矛盾 → 旧バージョンをアーカイブ
│ │ └─ NONE 重複 — スキップ
│ │
│ └─ アクション実行 + 履歴に書き込み
│
├─ 🕸️ Graph Memory ──────────────────────────────────
│ │
│ ├─ LLM がエンティティ + 関係を抽出
│ ├─ 競合検出(古いデータを soft-delete、新しいデータを追加)
│ └─ 多値 vs 単値の関係処理
│
└─ 🗄️ Archive ───────────────────────────────────────
│
├─ 削除/更新されたメモリを embedding 付きで保存
├─ アクティブな結果が弱い場合の fallback 検索
└─ アーカイブが閾値を超えると自動圧縮
🚀 クイックスタート
前提条件
| 要件 | インストール |
|---|---|
| Rust 1.75+ | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh |
| LLM バックエンド | Ollama(ローカル)、OpenAI、または Anthropic |
ビルド & 実行
git clone https://github.com/Adaimade/R-Mem.git && cd R-Mem
cargo build --release
# → target/release/rustmem(3.6 MB)
設定
プロジェクトルートに rustmem.toml を作成:
| Ollama(ローカル) | OpenAI | Anthropic |
|
|
|
注意: Anthropic は embedding モデルを提供していないため、
[llm]で Anthropic を使用する場合でも[embedding]は OpenAI または Ollama を使用します。
🔗 統合ガイド
⚠️ MemoryManager を構築するだけでは不十分
最も一般的な統合ミス:MemoryManager を初期化したものの、会話ループで add() や search() を一度も呼び出さないこと。メモリシステムは存在するが使われていない — ユーザーが言ったことは何も記憶されません。
正しい会話ループ
毎ターン、2 つのメモリ操作を含める必要があります:
- LLM 呼び出し前 — 想起(関連するメモリを検索)
- LLM 呼び出し後 — 学習(新しい事実を抽出して保存)
loop {
user_message = receive()
// 1. 想起 — LLM を呼び出す前に
memories = rmem.search(user_id, user_message, limit=10)
context = format_as_context(memories)
// 2. メモリコンテキスト付きで LLM を呼び出す
response = llm.chat(system_prompt + context + user_message)
// 3. 学習 — 応答後に
rmem.add(user_id, user_message)
send(response)
}
メモリコンテキストの形式
search() の結果を LLM が理解できるコンテキストにフォーマットします:
[Memory]
このユーザーについての既知の事実:
- ユーザーの名前は Alice
- ユーザーはダークモードを好む
- ユーザーは Rust プロジェクトに取り組んでいる
これを system prompt 内またはユーザーメッセージの前に配置して、LLM が参照できるようにします。
マルチスコープパターン
アプリが複数のチャネル(例:Telegram + Discord)にサービスを提供する場合、3 つのスコープレイヤーを使用します:
| スコープ | 用途 | ID の例 |
|---|---|---|
| local | 単一の会話 / グループ | telegram:group_123 |
| user | チャネル横断の個人メモリ | user:456 |
| global | 全ユーザー共有 | global:system |
想起時に結果をマージします:
local_results = search("telegram:group_123", query)
user_results = search("user:456", query)
global_results = search("global:system", query)
all = deduplicate(local + user + global)
よくある間違い
- ❌ MemoryManager を初期化するがループで
search()/add()を呼ばない - ❌ 学習のみで想起しない(メモリは保存されるが取得されない)
- ❌ 想起のみで学習しない(古いメモリを読むが新しいものを学習しない)
- ❌ LLM 呼び出し前に
add()を実行する(現在のメッセージが既知の事実として扱われる)
📖 使い方
CLI
# メモリを追加
rustmem add -u alice "My name is Alice and I work at Google. I love sushi."
# セマンティック検索
rustmem search -u alice "What does Alice eat?"
# ユーザーの全メモリを一覧
rustmem list -u alice
# グラフ関係を表示
rustmem graph -u alice
# REST API サーバーを起動
rustmem server
REST API
rustmem server で起動後:
# ➕ メモリを追加
curl -X POST http://localhost:8019/memories/add \
-H 'Content-Type: application/json' \
-d '{"user_id": "alice", "text": "I moved to Tokyo last month"}'
# 🔍 検索
curl -X POST http://localhost:8019/memories/search \
-H 'Content-Type: application/json' \
-d '{"user_id": "alice", "query": "where does she live", "limit": 5}'
# 📋 全件取得
curl http://localhost:8019/memories?user_id=alice
# 🏷️ カテゴリでフィルタ(preference, personal, plan, professional, health, misc)
curl http://localhost:8019/memories?user_id=alice&category=preference
# 🗑️ 削除
curl -X DELETE http://localhost:8019/memories/{id}
# 📜 履歴
curl http://localhost:8019/memories/{id}/history
# 🗄️ アーカイブされたメモリを表示
curl http://localhost:8019/archive?user_id=alice
# 🕸️ グラフ関係を表示
curl http://localhost:8019/graph?user_id=alice
AI Agent へのドロップイン
# mem0(以前)
from mem0 import Memory
m = Memory()
m.add("Alice loves sushi", user_id="alice")
# R-Mem(以後 — HTTP に切り替えるだけ)
import httpx
httpx.post("http://localhost:8019/memories/add",
json={"user_id": "alice", "text": "Alice loves sushi"})
🔌 MCP Server
R-Mem は MCP server として動作します — 1 コマンドで Claude Code や Cursor に長期メモリを付与:
# Claude Code
claude mcp add rustmem -- /path/to/rustmem mcp
# Cursor (.cursor/mcp.json)
{
"mcpServers": {
"rustmem": {
"command": "/path/to/rustmem",
"args": ["mcp"]
}
}
}
7 つの tools: add_memory、search_memory、list_memories、get_memory、delete_memory、get_graph、reset_memories
🏗️ アーキテクチャ
src/
├── main.rs CLI エントリポイント(clap)
├── config.rs TOML + 環境変数設定
├── server.rs REST API(axum)
├── mcp.rs MCP server(rmcp)— stdio 経由の 7 tools
├── memory.rs コアオーケストレータ — 階層メモリパイプライン
├── extract.rs LLM 呼び出し:OpenAI + Anthropic native
├── embedding.rs OpenAI 互換 embedding クライアント
├── store.rs SQLite vector store(WAL + FTS5 + archive)
└── graph.rs SQLite graph store(soft-delete、多値関係)
9 ファイル。2,826 行。3.6 MB バイナリ。外部サービスゼロ。
🗺️ ロードマップ
| ステータス | 機能 | 説明 |
|---|---|---|
| ✅ | crates.io に公開 | cargo install rustmem — ワンライナーインストール |
| ✅ | MCP Server | rustmem mcp — stdio 経由の 7 tools、Claude Code / Cursor 対応 |
| ✅ | 階層アーカイブ | 削除/更新されたメモリを保存 + fallback 検索 |
| ✅ | FTS5 2 段階検索 | キーワードプリフィルタ + vector 再ランキング — 19 倍高速 |
| ✅ | メモリカテゴリ | 自動分類:preference, personal, plan, professional, health |
| ✅ | Anthropic Native | Claude API の直接サポート(プロキシ不要) |
| ✅ | Agent SDK(lib crate) | Rust コードから rustmem::{memory, store, graph} を直接使用 |
| ✅ | LongMemEval Benchmark | gpt-4o-mini で 48.2%、mem0(約 49%)にほぼ匹敵 |
| ✅ | Production Audit | 11 項目のセキュリティ/安定性修正、25 個のユニットテスト、cargo bench |
| 🔲 | Episodic Memory | タスク実行履歴(tool 呼び出し、パラメータ、結果) |
| 🔲 | User Preference Model | セッション横断のユーザースタイルと行動モデリング |
| 🔲 | Skill Abstraction | 繰り返される成功パターンを skill として自動抽出 |
| 🔲 | バッチインポート | 既存の mem0 エクスポートデータを読み込み |
| 🔲 | マルチモーダル | 画像/音声メモリサポート |
| 🔲 | Dashboard | メモリ検査用の軽量 web UI |
R-Mem v0.3.0 は学習プロジェクトとして機能完備です。コアアーキテクチャは安定しており、本番レベルの堅牢化済みです。コミュニティからの貢献、fork、探索を歓迎します — issue または PR をお気軽にどうぞ。
MIT License · v0.3.0
Ad Huang が Claude Code で構築