Claude Codeに長期記憶を持たせたら、壁打ちの質が変わった

どうも、AIエンジニアの@noprogllamaです。普段はAIで日常の仕組み化をしたり、投資×テクノロジーの実践知を発信したりしています。
CLAUDE.mdという仕組みがあります。プロジェクトのルートに置いておくと、Claude Codeがセッション開始時に読み込んで、プロジェクトの方針や技術スタックを把握してくれます。開発に必要な情報はこれで十分伝わります。
ですが、CLAUDE.mdには書けないものがあります。
「前にこの方針で議論して、こういう理由で却下したよね」「あの時ハマったの、覚えてる?」——過去の会話の文脈です。
私はClaude Codeを開発だけでなく壁打ち相手としても使っています。戦略の相談、記事の構成、設計判断の議論。こういう用途では、過去に何を話したかが重要です。新しいセッションを開くたびに前提の共有からやり直すのは、率直に言ってしんどい。毎朝出社したら同僚が記憶喪失になっている、そんな感じです。
この問題を解決するために、自分で記憶エンジンを作りました。結果として1,942セッション分の会話が蓄積され、壁打ちの質が明らかに変わりました。
以前、一度失敗している
実はこれが2回目の挑戦です。
1回目は、claude-memというOSSプラグインをフォークして使おうとしました。コミット1,493件(2026-03-22現在)のそれなりに成熟したプロジェクトです。セキュリティ上の懸念があったのでサニタイズして、Dropboxでマシン間同期も設計したのですが…3日後に全面無効化しました。
プロジェクトごとに記憶が断絶していたこと、バックグラウンドで毎メッセージ結構なトークンを消費していたことが主な理由でした。
この経緯は以前Zennに書いたので、興味があれば「claude-memをフォークして使ってみたけど3日で辞めた話」を読んでみてください。
今回の設計思想
2回目は一から作りました。名前はsui-memory。
前回の反省を踏まえて、設計方針を3つに絞っています。
- 外部サービスに依存しない。SQLiteの1ファイルに全データを格納する
- バックグラウンドでトークンを消費しない。記憶の保存にLLMを使わない
- セッション終了時に自動で保存される。手動操作ゼロ
依存パッケージも実質2つです(sentence-transformersとsqlite-vec)。削ぎ落として、ようやく動くものになりました。
仕組みの全体像
やっていることは素朴です。セッションが終わると、会話の全文がsui-memoryに送られます。sui-memoryはそれをQ&A形式のチャンクに分割し、日本語特化の埋め込みモデル(Ruri v3)でベクトル化して、SQLiteに保存します。
ユーザー側で必要な設定は、Claude Codeのsettings.jsonにHookを数行足すだけです。セッション終了時に自動で発火するので、普段の使い方は何も変わりません。
CLAUDE.mdとの棲み分け
この仕組みは、CLAUDE.mdと競合するものではありません。役割が違います。
CLAUDE.mdはプロジェクトのルールブックです。技術スタック、コーディング規約、ディレクトリ構成。静的な情報を伝えるのに向いています。セッションが変わっても内容は同じで、それでよいのです。
sui-memoryは過去の会話の蓄積です。この設計にした理由、あの案を却下した経緯、先週試して失敗したこと。動的な情報、つまり議論の文脈を保持します。
CLAUDE.mdが取扱説明書なら、sui-memoryは共有した経験に近い。どちらか一方では足りません。両方あって初めて、文脈を持った壁打ち相手になると思っています。
2つの検索を組み合わせる
記憶は保存するだけでは意味がありません。必要な時に、必要なものを取り出せなければ価値がありません。
sui-memoryでは、2つの検索を組み合わせています。
1つ目はキーワード検索です。SQLiteに組み込みの全文検索(FTS5)を使い、日本語を形態素解析なしに検索します。一般的にはMeCabなどの外部辞書を使いますが、ここではtrigramトークナイザという方式を採用しました。文字列を3文字ずつの断片に分割するだけの素朴な方法ですが、追加の依存パッケージが不要です。「Tailscale」「LaunchAgent」のような固有名詞にはこちらが強い。
2つ目はベクトル検索です。テキストの意味的な近さで検索します。エンベディングモデルにはRuri v3-310mという日本語特化モデルを選びました。310Mパラメータと小型ながらCPUでも十分な速度で動きます。OpenAIのEmbeddings APIを使わない選択をしたのは、コストとプライバシーの両面からです。全ての会話ログを外部に送信するのは避けたかったので。
この2つの結果をRRF(Reciprocal Rank Fusion)という方法で統合します。それぞれの検索結果の順位を使ってスコアを合算する仕組みで、検索方式ごとのスコアの単位が違っても公平に扱えます。キーワード検索だけだと意味的な類似を見逃し、ベクトル検索だけだと固有名詞に弱い。両方を組み合わせることで、お互いの弱点を補います。
さらに、時間減衰を入れています。古い記憶ほどスコアが下がる設計で、半減期は30日です。30日前の記憶はスコアが半分に、60日前は4分の1になります。人間の記憶も直近のことほど鮮明で、古いことは薄れていくので、この仕組みを導入してみました。
実際に使ってみて
現在、1,942セッション分の会話から7,059件のメモリが蓄積されています。検索のレスポンスは100ms前後です。
体感として最も変わったのは、壁打ちの精度です。
たとえば記事のテーマを相談するとき、以前なら毎回ゼロからブレストしていました。今は過去に検討したテーマや、その時の判断理由が文脈として残っているので、同じ議論を繰り返さずに済みます。前回の結論を踏まえて、その先の議論ができる。
これは開発の効率化というよりも、思考の相手としての質の変化です。壁打ちが壁打ちとして機能するようになった、という感覚があります。
もちろん万能ではありません。7,000件のメモリの中から本当に必要な数件を引き当てられるかは、クエリの質とチャンクの粒度に依存します。検索精度の調整は今も続けています。
前回の失敗との違い
前回(claude-mem)と今回(sui-memory)の違いを整理しておきます。
claude-mem sui-memory
─────────────────────────────────────────────────
コード量 大規模 1,759行
言語 TypeScript Python
記憶の保存 LLMで要約・圧縮 生のtranscriptをチャンク化
トークン消費 毎メッセージ数千 ゼロ(LLM不使用)
検索 Chroma(外部DB) SQLite内蔵(FTS5+sqlite-vec)
外部依存 ChromaDB等 sentence-transformers, sqlite-vec
セットアップ 複数プロセス起動 uv syncのみ
根本的な差は、記憶の保存にLLMを使うかどうかです。claude-memはバックグラウンドでLLMを起動して会話を要約・圧縮していました。sui-memoryは生のtranscriptをルールベースでチャンクに分割するだけです。LLMを使わないから、トークンも消費しないし、応答速度にも影響しません。
要約しないぶん情報は多少冗長になりますが、大事な文脈が要約の過程で消えてしまうリスクを避けられます。何を残して何を捨てるかの判断は、保存時ではなく検索時にやればよいのです。
大規模なシステムを捨てて、1,759行で作り直しました。やっていることの本質は同じです。会話を保存して、必要な時に取り出す。余計なものを全部削ぎ落としたら、ようやく納得のいくものになりました。
私のClaude Codeは今、過去の会話を覚えている相手になっています。CLAUDE.mdでルールを伝え、sui-memoryで経験を共有する。この2層構造が、今の私にとっての最適解です。
AIで仕組み化する実践知を発信しています → @noprogllama
続編を書きました。この記憶を持ったAIにスマホからいつでもアクセスするためのWeb UIを自作した話です。
Discussion
うちの構成に似ているのでとても興味深く拝見しました。
sui-memoryはSQLiteをメインにチャンク分け、ベクトル化という構成なんですね。
うちのはRAGに後付けでSQLiteを積んだ形です。
やはり記憶を持たせると会話の質が全然違ってきますよね。
ぜひ今後とも近況を教えてください。
構成が似ているとのコメント、嬉しいです。ありがとうございます。
sui-memoryはSQLiteのBM25全文検索をベースに、後からベクトル検索を重ねていった形です。
逆にRAGベースにSQLiteを後付けされたというのは、真逆のアプローチですが、求めているものはまさに同じものですね!
記憶があるとAIが本当に変わりますよね。毎回ゼロから説明し直す必要がなくなるだけで、壁打ちが積み上がる感覚になるというか。日々のAIとの会話がかなり楽になりました。
振り返ると失敗も多いですが、これに関しては正解のアプローチだったと思います。
また書いていきますので、今後ともよろしくお願いします。
OpenClaw にある memory 検索の仕組みを個人で実装されていて凄いなと感じました!
下記のドキュメント読んでみると面白いかもと思ったので紹介させてください 🙏
設計思想がかなり近くて驚きました。ご紹介ありがとうございます。
BM25 + ベクトル検索のハイブリッドや時間減衰(半減期30日)まで同じで、同じ課題に向き合うと辿り着く先が似てくるものですね。
特に気になったのはMMRで、これは自分の実装にはまだなく、似たチャンクばかり返ってくる問題はありえるなと思いました。ゆくゆくチャンクの多様性に欠けると感じたら取り入れたいと思います。
今後ともよろしくお願いします・・!
過去ログをベクトル化すると精度が下るジレンマもあると思います。記憶を階層化するといいかもしれませんね!私も今いろいろ試しているところなので大変参考になりました。
コメントありがとうございます。
記憶の階層化、気になります。自分の場合は静的な記憶はCLAUDE.md、動的な記憶はsui-memoryを利用していて、sui-memory内の記憶は今のところフラットに扱っているのですが、例えば「設計判断の経緯」と「日常の雑談」では重みや寿命が違うはずで、
そのあたりを層として分けるイメージでしょうか?もしよければどんな階層を想定されているか教えていただけると嬉しいです。
同じ領域を試されている方がいると心強いです!今後ともよろしくお願いします。
非常に興味深く拝見させていただきました。
試しに手元でも同様のものをと検討していたので、試しにClaudeで実装して動かしてみてます。
MCP経由にしてGeminiなどでも設定すればそれなりに記憶の受け渡しもできるようになりました。
(インスパイア実装となるのですが、公開してもよろしいのやら⋯
MCP経由でGeminiにも記憶を渡せるようにされたとのこと、自分はClaude Code専用で閉じてしまっているので、モデル横断で記憶を共有する設計がどうなっているのか気になります。
公開はぜひ!インスパイアされた実装が別の方向に育っていくのは書いた側としてもとても嬉しいので、気にせず出していただければと思います。
ありがとうございます。こちらです。
なおClaude code向け記述しかしていませんが、実際にはMCPの設定やスキル設定を書けばGemini CLIでも使えております。問題はhookを使った「終了時の保存」などできないこともあるので、今のところ終了前に「記憶しておいて」とか言わないと欠損が起きえることでしょうか。
この記事にインスパイアされて、TypeScriptで再実装したEngramを公開しました。
記事で提唱されている6つの設計原則(外部依存の排除、保存時トークン消費ゼロ、自動保存、常時参照、編集と削除、最小依存)はそのまま設計の柱として採用させていただきました。特に「常時参照」の考え方は、claude-memのような明示的検索方式とは異なるアプローチとして非常に示唆に富むものでした。
sui-memoryの設計をベースに、以下のような方向で発展させています。
ふが氏のfuga-memoryと同様のインスパイア実装ですが、公開について問題がないか念のためお伺いできればと思います。素晴らしい記事と設計思想を共有していただきありがとうございます。
設計原則がそのまま柱になったとのこと、書いた側としてもとても嬉しいです。ありがとうございます。
coreモードでbetter-sqlite3のみ、Pythonもモデルダウンロードも不要という割り切りがいいですね。sui-memoryはPython + Ruri前提なのでセットアップのハードルが地味にあって、そこを解消したいというお気持ち、すごくわかります。
公開はもちろん問題ありません。okamyujiさんの思うように出していただければと思います。こういう形で設計思想が広がっていくのは、記事を書いた甲斐があったというものですね。
Engramの方も拝見してみます。今後ともよろしくお願いします。
この記事にインスパイアされて、指示書ベースの長期記憶 N3MemoryCore を公開しました。
コードではなく指示書(Markdown)をClaude Codeに渡すだけで、長期記憶環境が構築されます。
最初の指示書はこの記事を元にCopilotが作りました。
指示書をソフトウェアとして共有する、実にモダンなアプローチですね。インスパイアしていただいたこと、ご連絡いただいたこと、ありがとうございます。