Claude Codeは非常に優秀なAIコーディングアシスタントですが、致命的な弱点があります。セッションをまたいで記憶を持てないことです。
「先週Dockerfileの設計について議論した内容」「このプロジェクトではTypeScriptのstrictモードを避ける理由」「以前のリファクタリングで失敗したアプローチ」──こうした文脈はセッションが切れた瞬間に消えます。毎回一から説明し直すコストは、熟練するほど大きく感じられるはずです。
この問題に対するシンプルかつ技術的に面白いアプローチが、SQLite+ベクトル検索を組み合わせた自作メモリシステム「sui-memory」です。本記事では、その設計思想と中核技術を徹底的に掘り下げます。
- Claude Codeのメモリには3つのアプローチがある
- sui-memoryの全体アーキテクチャ
- 中核技術① sqlite-vec──シングルファイルで動くベクトル検索
- 中核技術② Ruri v3-310m──315Mパラメータで1Bクラスを超える日本語埋め込み
- 中核技術③ FTS5 trigram──形態素解析なしで日本語キーワード検索
- 中核技術④ RRF──異なる検索システムを公平に統合する
- 中核技術⑤ 時間減衰──古い記憶を自動的に下げる
- Q&Aチャンク分割の設計思想
- Claude Code Hooksとの連携
- claude-memとの比較──LLMを使う派 vs 使わない派
- 導入ステップ
- CLAUDE.mdとの役割分担を設計する
- SQLiteのスキーマ設計
- ハイブリッド検索が実際に機能する場面
- 記憶の質を上げる工夫
- プライバシーとセキュリティの観点
- 長期運用のポイント
- ベクトル検索のパフォーマンス最適化
- よくある質問
- まとめ
Claude Codeのメモリには3つのアプローチがある
sui-memoryの話に入る前に、現時点でClaude Codeに「記憶」を持たせる手段を整理します。大きく3種類あります。
| アプローチ | 仕組み | 更新頻度 | 適した情報 |
|---|---|---|---|
| CLAUDE.md | Markdownをコンテキストに自動注入 | 手動・低頻度 | 技術スタック・コーディング規約・恒久ルール |
| Auto Memory | Claude Code公式の自動メモリ機能 | 会話ごとに自動 | ユーザーの好み・繰り返し指示・フィードバック |
| 外部ベクトルDB(sui-memory) | SQLite+ベクトル検索で全会話を永続化 | セッション終了ごとに自動 | 過去の議論・決定の経緯・試行錯誤の記録 |
CLAUDE.mdは「静的な取扱説明書」、Auto Memoryは「よく使う付箋メモ」、sui-memoryは「過去の経験・エピソード記憶」と捉えると分かりやすいです。この3層が揃って初めて、Claude Codeは本当の意味で「あなたの仕事を知っている」状態に近づきます。
Auto Memory機能についてはClaude CodeのAuto Memory機能を徹底解説、CLAUDE.mdの設計についてはCLAUDE.mdで実現するClaude Codeのカスタマイズも参考にしてください。
sui-memoryの全体アーキテクチャ
sui-memoryの最大の特徴は「LLMを一切使わない」設計です。記憶を保存するために別のAIを呼ぶと、それ自体がAPIコストを消費するという逆説が生まれます。sui-memoryはその問題をルールベース処理とローカルモデルで完全に回避しています。
システム全体の流れは以下のとおりです。
sui-memoryのデータフロー
① セッション終了時にClaude Code Hooksが発火
② 会話のtranscriptをQ&Aチャンク形式に分割(ルールベース、LLM不使用)
③ Ruri v3-310mで各チャンクをベクトル化(ローカル処理)
④ SQLiteに保存(FTS5インデックス+vec0テーブル)
⑤ 次のセッション開始時:クエリをFTS5とベクトル検索で並列検索
⑥ RRF(Reciprocal Rank Fusion)で結果を統合
⑦ 時間減衰スコアで直近の記憶を優遇
⑧ 上位チャンクをClaude Codeのコンテキストに注入
すべてローカルで完結します。SQLiteはシングルファイルで動き、外部サービスは一切不要です。実際に7,000件以上のメモリを格納した状態でも検索は100ms前後で完了するという実績があります。
中核技術① sqlite-vec──シングルファイルで動くベクトル検索
ベクトル検索といえば最初に思い浮かぶのはpgvectorやChromaDBかもしれませんが、sui-memoryが選んだのはsqlite-vecです。
sqlite-vecはSQLiteの拡張機能として動くベクトル検索ライブラリで、Mozilla Buildersの支援を受けてAlex Garciaが開発しました。
pip install sqlite-vec
仮想テーブル「vec0」に埋め込みベクトルを格納し、KNN(K近傍)検索をSQL文で実行できます。
-- テーブル作成 CREATE VIRTUAL TABLE vec_memories USING vec0( memory_id INTEGER PRIMARY KEY, embedding float[768] ); -- ベクトル保存 INSERT INTO vec_memories(memory_id, embedding) VALUES (1, '[0.12, -0.34, ...]'); -- KNN検索(上位10件) SELECT memory_id, distance FROM vec_memories WHERE embedding MATCH '[0.15, -0.31, ...]' ORDER BY distance LIMIT 10;
pgvectorとの使い分けは明快です。
| 観点 | sqlite-vec | pgvector |
|---|---|---|
| デプロイ | 単一ファイル、サーバー不要 | PostgreSQLサーバーが必要 |
| スケール | 個人・小規模向け | エンタープライズ・高並列向け |
| インストール | pip install sqlite-vecのみ |
PostgreSQLセットアップが必要 |
| 近似検索(ANN) | フラット(全数スキャン) | HNSW / IVFFlat対応 |
| 最適用途 | ローカルメモリ・ユーザー単位DB | 大規模本番システム |
個人用の長期メモリシステムでは、数万件規模のベクトルをフラットサーチしても十分高速です。データベース管理の複雑さを持ち込まず、Pythonスクリプト1本で完結できるsqlite-vecは正しい選択です。
中核技術② Ruri v3-310m──315Mパラメータで1Bクラスを超える日本語埋め込み
ベクトル化に使うモデルの選定は、システム全体の性能を大きく左右します。sui-memoryが選んだのはRuri v3-310m(cl-nagoya/ruri-v3-310m)です。
Ruri v3は名古屋大学が開発した日本語特化の埋め込みモデルで、2024年9月にリリースされました。ベースにはsbintuitions/modernbert-ja-310mを使用しており、技術仕様は以下のとおりです。
| 項目 | 詳細 |
|---|---|
| パラメータ数 | 315M(旧Ruri-largeとほぼ同等) |
| 出力次元 | 768次元 |
| 最大シーケンス長 | 8,192トークン(旧版の16倍) |
| 語彙数 | 100,000トークン(旧版の3倍超) |
| ライセンス | Apache 2.0 |
特筆すべきはJMTEBスコアです。日本語テキスト埋め込みの標準ベンチマークで、Ruri v3-310mは平均77.24を記録しています。
| モデル | JMTEB平均 | パラメータ数 |
|---|---|---|
| Ruri v3-310m(★) | 77.24 | 315M |
| PLaMo-Embedding-1B | 76.10 | 1.05B |
| Sarashina-embedding-v1-1b | 75.50 | 1.22B |
| text-embedding-3-large(OpenAI) | 73.97 | 非公開 |
| Ruri-large(旧版) | 73.31 | 337M相当 |
| multilingual-e5-large | 70.90 | 560M |
| text-embedding-3-small(OpenAI) | 69.18 | 非公開 |
315Mのモデルが1Bを超えるモデルを上回り、OpenAIの最上位埋め込みモデルも凌駕しています。これは日本語に特化した設計の成果です。汎用多言語モデルとは根本的に異なるアプローチで日本語を処理しています。
もう一つ重要なのがプレフィックス設計です。Ruri v3では用途に応じてテキストの先頭に特定の文字列を付与します。
| 用途 | プレフィックス |
|---|---|
| 検索クエリ | "検索クエリ: " |
| 検索文書(保存するメモリ) | "検索文書: " |
| 分類・クラスタリング | "トピック: " |
| 通常エンコード | なし |
クエリと文書に異なるプレフィックスを付けることで、非対称な検索(短いクエリで長い文書を探す)の精度が上がります。sui-memoryの実装でもこのプレフィックス設計が活用されています。
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("cl-nagoya/ruri-v3-310m")
# 記憶を保存するとき(文書用プレフィックス)
memory_chunks = ["Dockerfileの設計について議論した", "TypeScriptのstrictモードを無効にした理由"]
doc_embeddings = model.encode(
["検索文書: " + chunk for chunk in memory_chunks]
)
# 記憶を検索するとき(クエリ用プレフィックス)
query = "Docker設定の経緯を教えて"
query_embedding = model.encode("検索クエリ: " + query)
中核技術③ FTS5 trigram──形態素解析なしで日本語キーワード検索
ベクトル検索は意味的な類似性に強いですが、「あの変数名はなんだったか」「Tailscaleの設定ファイルはどこにあったか」といったキーワード完全一致には弱い面があります。これを補うのがSQLite FTS5のtrigramトークナイザです。
trigramとはテキストを3文字単位で連続的に切り出す手法です。
trigram分割の例
「検索システム」→「検索シ」「索シス」「シスて」「ステム」
MeCabなどの形態素解析器なしで、SQLiteのみで全文検索インデックスを構築できます。
ただし日本語には課題があります。1〜2文字のクエリに対してtrigramが生成できず検索できないのです。sui-memoryはこれをパディング文字(絵文字2文字など)をテキスト末尾に付加することで解決しています。
CREATE VIRTUAL TABLE fts_memories USING fts5( content, content="memories", content_rowid="id", tokenize="trigram" );
中核技術④ RRF──異なる検索システムを公平に統合する
FTS5(キーワード検索)とsqlite-vec(ベクトル検索)は単位が全く異なるスコアを返します。BM25スコアと余弦距離を直接比較・加算することはできません。この問題を解決するのがRRF(Reciprocal Rank Fusion)です。
RRFはスコアの絶対値ではなく「順位」だけを使って統合します。数式は非常にシンプルです。
RRFスコアの計算式
RRF_score(d) = Σ 1 / (k + rank_i(d))
d:ドキュメント、rank_i(d):検索システムiでの順位(1始まり)、k:スムージング定数(通常60)
たとえばあるドキュメントがFTS5検索で1位、ベクトル検索で3位だった場合のRRFスコアは次のとおりです。
# k=60の場合
rrf_score = 1/(60+1) + 1/(60+3)
= 0.01639 + 0.01587
= 0.03226
# 両方1位の場合(最高スコア)
rrf_max = 1/(60+1) + 1/(60+1) = 0.03279
kに60を使う理由は、Cormackら(2009)の原論文で多くのデータセットにおいて最良の結果を示すことが実験的に確認されているためです。RRFのメリットは2点あります。① スコアの正規化が不要(単位が違っても順位に変換すれば統合できる)、② 両システムにヒットしたドキュメントが自然に上位に来る(両方の検索で見つかった記憶が最も関連性が高い)。
WITH fts AS (
SELECT rowid, rank AS fts_rank
FROM fts_memories
WHERE fts_memories MATCH ?
),
vec AS (
SELECT memory_id,
ROW_NUMBER() OVER (ORDER BY distance) AS vec_rank
FROM vec_memories
WHERE embedding MATCH ?
)
SELECT
COALESCE(fts.rowid, vec.memory_id) AS id,
(1.0 / (60 + COALESCE(fts.fts_rank, 1000))) +
(1.0 / (60 + COALESCE(vec.vec_rank, 1000))) AS rrf_score
FROM fts
FULL OUTER JOIN vec ON fts.rowid = vec.memory_id
ORDER BY rrf_score DESC
LIMIT 20;
中核技術⑤ 時間減衰──古い記憶を自動的に下げる
RRFで統合したスコアにさらに時間減衰をかけます。3年前の議論より昨日の決定のほうが現在の仕事に関係が高い、という直感をスコアに反映します。
import math
from datetime import datetime
def apply_time_decay(rrf_score: float, created_at: datetime,
half_life_days: int = 30) -> float:
"""
半減期30日の指数減衰でスコアを調整する。
- 30日後 → ×0.5
- 60日後 → ×0.25
- 90日後 → ×0.125
"""
days_elapsed = (datetime.now() - created_at).days
decay = math.exp(-math.log(2) * days_elapsed / half_life_days)
return rrf_score * decay
半減期を30日に設定するとちょうどよい粒度になります。先月の議論はまだ参照されやすく、半年前の決定は自然に埋もれていきます。もちろんこの値はプロジェクトの性質に応じて調整可能です。
Q&Aチャンク分割の設計思想
会話全体をそのままベクトル化しても検索精度は上がりません。「どのページをどう設計したか」と「なぜそのアプローチを選んだか」が同じチャンクに混在すると、関係ない情報まで引っかかってしまいます。
sui-memoryは会話をQ&Aペア形式のチャンクに分割します。「ユーザーの問い」と「Claudeの回答」を1セットとして保存することで、検索クエリ(ユーザーが問う形式)と保存データの形式が対応し、検索精度が向上します。
Q&Aチャンク分割の例
Q: Dockerfileのベースイメージを何にするか
A: node:20-alpineを選択。理由はイメージサイズが小さくCI/CDが速いため。ただしnpmパッケージによってはglibc依存があるためmuslビルドに注意が必要。
このQ&Aペアをひとつのチャンクとしてベクトル化・FTS5インデックス化します。LLMによる要約を使わないため、Claude側の解釈バイアスが入らず、原文に忠実な記憶が残ります。
Claude Code Hooksとの連携
sui-memoryはClaude Code Hooksと組み合わせることで、完全自動のメモリシステムになります。Claude Code Hooksの詳細も参照してください。
メモリシステムで使うフックは主に2つです。
| フック名 | タイミング | sui-memoryでの用途 |
|---|---|---|
Stop |
Claudeが応答を完了したとき | 会話内容をQ&Aチャンクに分割してSQLiteに保存 |
UserPromptSubmit |
ユーザーがメッセージを送信する前 | 関連する過去の記憶を検索してコンテキストに注入 |
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "python /path/to/sui_memory.py save --session $CLAUDE_SESSION_ID"
}
]
}
],
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "python /path/to/sui_memory.py recall --query "$CLAUDE_USER_PROMPT""
}
]
}
]
}
}
Stopフックでセッション終了時に記憶を保存し、UserPromptSubmitフックで次の質問の前に関連記憶を自動注入します。ユーザーは何もしなくても、Claude Codeが過去の文脈を踏まえた回答をするようになります。
フックの設定は.claude/settings.json(プロジェクトローカル)または~/.claude/settings.json(グローバル)に記述します。設定の詳細はClaude Code設定ガイドを参照してください。
claude-memとの比較──LLMを使う派 vs 使わない派
同じ「Claude Codeへの記憶追加」を目的とした類似ツールにclaude-memがあります。設計思想が大きく異なるため、両者の違いを理解しておくと自分に合ったツールを選べます。
| 観点 | sui-memory | claude-mem |
|---|---|---|
| 実装言語 | Python | Node.js / Bun |
| 記憶の生成方式 | ルールベース分割(LLM不使用) | LLMで観察記録を自動生成 |
| APIトークンコスト | ゼロ(完全ローカル処理) | セッションごとに数千〜数万トークン消費 |
| 検索システム | FTS5 + sqlite-vec + RRF | ChromaDB(セマンティック) + SQL |
| 時間減衰 | あり(半減期30日) | なし |
| 外部API依存 | なし(完全オフライン動作可) | Claude / Gemini API必須 |
| インストール手順 | 手動設定が必要 | /plugin install claude-memで完結 |
| デーモン | なし(フック時のみ起動) | 常駐ワーカー(ポート37777) |
| 日本語対応 | Ruri v3で最適化済み | 多言語対応(最適化なし) |
claude-memは「記憶を賢くLLMが整理してくれる」という体験を重視した設計です。セットアップが簡単で、AIが自動的に重要な情報を抽出・要約します。一方でAPIコストが継続的にかかります。
sui-memoryは「生の会話を忠実に保存し、検索精度で勝負する」設計です。コストゼロ・オフライン動作・日本語特化という点で、特に日本語でのコーディング作業が多いエンジニアに向いています。
導入ステップ
sui-memoryの導入手順を簡単にまとめます。詳細はGitHubリポジトリを参照してください。
pip install sqlite-vec sentence-transformers
from sentence_transformers import SentenceTransformer
# 初回実行時に自動ダウンロード(約600MB)
model = SentenceTransformer("cl-nagoya/ruri-v3-310m")
git clone https://github.com/noprogllama/sui-memory cd sui-memory
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "python /path/to/sui-memory/sui_memory.py save"
}
]
}
]
}
}
注意:Ruri v3-310mは初回ダウンロード時に約600MBのファイルをローカルにキャッシュします。ネットワーク環境と空きストレージを事前に確認してください。2回目以降はオフラインで動作します。
CLAUDE.mdとの役割分担を設計する
sui-memoryを導入したあとも、CLAUDE.mdの役割は変わりません。両者は補完関係にあります。
| 情報の種類 | 保存先 | 更新タイミング |
|---|---|---|
| 技術スタック・バージョン | CLAUDE.md | 手動・プロジェクト設定時 |
| コーディング規約・命名ルール | CLAUDE.md | 手動・規約変更時 |
| 過去の議論・設計の経緯 | sui-memory | 自動・セッション終了時 |
| 試行錯誤の記録・失敗例 | sui-memory | 自動・セッション終了時 |
| ユーザーの好み・作業スタイル | Auto Memory | 自動・随時 |
CLAUDE.mdには「変わらないルール」を書き、sui-memoryには「積み重なっていく経験」が入ります。前者は取扱説明書、後者は仕事のlog(日誌)と捉えるとイメージしやすいです。メモリ戦略の全体像についてはClaude Codeのメモリ戦略ガイドも参照してください。
SQLiteのスキーマ設計
sui-memoryのSQLiteスキーマを概念的に理解しておくと、カスタマイズがしやすくなります。主要なテーブルは3つです。
-- メインの記憶テーブル CREATE TABLE memories ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, created_at REAL NOT NULL, -- Unix timestamp chunk_type TEXT NOT NULL, -- 'qa', 'summary', etc. question TEXT, -- Q&Aのユーザー側 answer TEXT NOT NULL, -- Q&AのClaude側 content TEXT NOT NULL -- 検索用の統合テキスト ); -- FTS5 全文検索インデックス CREATE VIRTUAL TABLE fts_memories USING fts5( content, content="memories", content_rowid="id", tokenize="trigram" ); -- sqlite-vec ベクトルテーブル CREATE VIRTUAL TABLE vec_memories USING vec0( memory_id INTEGER PRIMARY KEY, embedding float[768] -- Ruri v3-310mの出力次元 );
設計のポイントはmemoriesテーブルに生のQ&Aテキストを保存し、fts_memoriesとvec_memoriesがそれぞれ独立したインデックスとして機能する点です。検索はインデックスを使い、結果のメタデータはmemoriesから取得します。
またcreated_atをUnix timestampで保存することで、時間減衰計算をSQLクエリ内で直接行えます。
SELECT
m.id,
m.content,
m.created_at,
-- RRFスコアに時間減衰をかける(半減期30日)
rrf.score * EXP(
-0.693 * (UNIXEPOCH('now') - m.created_at) / (30 * 86400)
) AS final_score
FROM memories m
JOIN rrf_results rrf ON m.id = rrf.memory_id
ORDER BY final_score DESC
LIMIT 10;
ハイブリッド検索が実際に機能する場面
FTS5とベクトル検索を組み合わせる意義を、具体例で確認します。
| 検索クエリ | FTS5が強い理由 | ベクトル検索が強い理由 |
|---|---|---|
| 「Tailscale」の設定 | 固有名詞の完全一致に強い | 「VPN設定」「ネットワーク接続」も同時に拾える |
| エラーコードで検索 | 「TS2345」等の記号・数字に強い | 同じエラーの別表現も拾える |
| 「なぜこのアーキテクチャを選んだか」 | 「アーキテクチャ」「選んだ」はヒットしやすい | 「設計方針」「採用理由」等の意味的な検索に強い |
| 「先週失敗したアプローチ」 | 「失敗」「アプローチ」でヒット | 「うまくいかなかった」「断念した」等の表現も拾える |
RRFでこれらを統合することで、キーワード検索の確実性とベクトル検索の柔軟性の両方を得られます。どちらか一方だけでは取りこぼしが生まれる検索が、ハイブリッドで補完されます。
記憶の質を上げる工夫
システムを導入しただけでは、記憶の質は会話の質に依存します。より有用な記憶が蓄積されるよう、いくつかの工夫が効果的です。
良い記憶を蓄積するための習慣
① 意思決定の理由を明示する
「このライブラリを選んだ理由は〇〇だから」という形で会話すると、なぜその選択をしたかが記憶に残ります。単に「これを実装して」より「〇〇の制約があるのでこのアプローチで実装して」の方が有用な記憶になります。
② 失敗した試みも記録する
「このアプローチを試したがうまくいかなかった」という会話も重要な記憶です。次回同じ失敗を繰り返さないために機能します。
③ セッションの最後にまとめを求める
「今日の作業で決まったことをまとめて」とClaude Codeに依頼する習慣をつけると、Q&Aチャンク以外に構造化されたサマリーチャンクが生成されます。
プライバシーとセキュリティの観点
コーディングの会話にはプロジェクトの設計情報や認証情報が含まれることがあります。sui-memoryがすべてローカルで完結することの意味を、セキュリティの観点で整理します。
| 観点 | sui-memory | クラウドベースの記憶システム |
|---|---|---|
| データの保存場所 | ローカルSQLiteファイル(自分のマシン) | 外部サーバー(プロバイダー管理) |
| 機密情報のリスク | 外部送信なし。ファイルパーミッション管理で十分 | データが外部に送信される |
| ネットワーク障害の影響 | 完全オフラインで動作 | ネットワーク障害時に記憶が使えない |
| サービス終了リスク | なし(自分でデータを所有) | サービス終了でデータが失われる可能性 |
ローカルファイルのセキュリティ管理
SQLiteファイルには会話の全履歴が入ります。chmod 600で適切なパーミッションを設定し、ファイルのバックアップ先(クラウドストレージ等)も暗号化されているかを確認してください。特に業務で機密性の高いプロジェクトに使う場合は、SQLiteファイルをGit管理から除外することも重要です。
長期運用のポイント
sui-memoryを長期的に使い続けるうえで知っておくべき点をまとめます。
定期的な再ランク計算は不要
時間減衰は検索時にリアルタイムで計算されます。バッチ処理でスコアを事前計算する必要はありません。これによりストレージ効率が高く保たれます。
古いデータのアーカイブ
半年〜1年前のデータは時間減衰によって検索結果の上位に出てくることがほぼなくなります。ただし削除は不可逆なので、別テーブルへのアーカイブが安全です。
-- 180日以上前のメモリをアーカイブテーブルに移動
INSERT INTO memories_archive
SELECT * FROM memories
WHERE created_at < UNIXEPOCH('now') - 180 * 86400;
DELETE FROM memories
WHERE created_at < UNIXEPOCH('now') - 180 * 86400;
-- SQLiteファイルを最適化
VACUUM;
Ruri v3モデルのバージョン管理
Ruri v3-310mが更新された場合、既存ベクトルと新版モデルのベクトル空間が異なります。モデルをアップデートする際はrebuildコマンドで全メモリを再ベクトル化する必要があります。sui-memoryはこのrebuildコマンドを提供しています。
# sui-memoryのrebuildコマンド python sui_memory.py rebuild --model cl-nagoya/ruri-v3-310m # 処理時間の目安:1,000件あたり約30秒(CPU動作時)
ベクトル検索のパフォーマンス最適化
sqlite-vecはフラットサーチ(全数スキャン)のため、データ件数が増えると検索速度が線形に低下します。個人用途での実用的な上限と対策を把握しておきましょう。
| メモリ件数 | ベクトル検索時間(目安) | 対策 |
|---|---|---|
| 〜5,000件 | 50ms以下 | 特に不要 |
| 5,000〜20,000件 | 50〜200ms | 古いデータのアーカイブを検討 |
| 20,000件〜 | 200ms〜 | 検索対象を直近N日間に絞るフィルタを追加 |
大量データへの対策として最も効果的なのは、検索前にFTS5でフィルタリングする手法です。まずキーワード検索で候補を絞り込み、その候補集合だけにベクトル検索をかけることで全数スキャンを回避できます。
# Step 1: FTS5で候補集合を取得(高速)
fts_candidates = db.execute(
"SELECT rowid FROM fts_memories WHERE fts_memories MATCH ?",
[query]
).fetchall()
candidate_ids = [row[0] for row in fts_candidates]
if not candidate_ids:
# キーワードヒットなし → ベクトル検索のみに切り替え
candidate_ids = None
# Step 2: 候補集合内でベクトル検索(件数を制限)
if candidate_ids:
placeholders = ",".join("?" * len(candidate_ids))
vec_results = db.execute(
f"""
SELECT memory_id, distance
FROM vec_memories
WHERE memory_id IN ({placeholders})
AND embedding MATCH ?
ORDER BY distance LIMIT 20
""",
candidate_ids + [query_embedding_str]
).fetchall()
よくある質問
VACUUMや古いデータのアーカイブを検討するのは数万件を超えてからで十分です。~/.claude/CLAUDE.mdに書き込みます。sui-memoryは全セッションの会話をSQLiteに保存します。役割が異なるため競合しません。.claude/settings.jsonのHooksコマンドにパスを設定する際は、Windowsのパス区切り(バックスラッシュ)に注意が必要です。WSL2内で動かす方がパス問題を回避しやすい場合があります。session_idやproject_idでフィルタリングする方法があります。全プロジェクト共有の方が「横断的な経験」を参照できる利点もありますが、プロジェクトの機密性が高い場合は分離を検討してください。まとめ
sui-memoryは「LLMを使わない」「コストゼロ」「オフライン完結」という3つの原則で設計されたClaude Code向け長期メモリシステムです。
使われている技術はどれも理にかなっています。個人メモリにはシングルファイルのsqlite-vecで十分、日本語処理にはJMTEBトップクラスのRuri v3-310m、キーワード検索と意味検索の統合にはRRFが最適解です。FTS5 trigramで形態素解析なしに日本語全文検索を実現し、時間減衰で直近の文脈を優遇する。各要素の組み合わせが全体として機能する、良い設計です。
Claude Codeを日常的に使っている方で「毎回同じ説明をしている」と感じているなら、sui-memoryは試す価値があります。セットアップはやや手動ですが、一度動き出せばその後は完全自動です。
Claude Codeの活用をさらに深めたい方は、Claude Code完全ガイドやHooks活用ガイドもあわせて参照してください。

