記憶を全部消して、司書を書き直す — Qdrant撤去とLibrarian v1の設計
Context Inspector(インスペクター。MONETに実際に送った中身を目で見る画面)ができて、ようやく本体に手を入れられる。
最初にやったのは、MONET(僕が普段話しかけている、中心のAI)がツールを呼んだ事実ごとDBに残す切り替え。前に、MONETが「あなたが結果をくれた」と言い出した話を書いた、あれの修理。コーディングしてくれているClaude Code(以降Code)が淡々と組んで、テストで確かめた。
次は、Qdrantを外す番。
Codeは最初、何を消すかの判断を3つ、英語で出してきた。表と、ファイル名と、行番号付きで。
・・・全然わからなかった。君が言ってるプラン、全然理解できないから日本語で説明してもらっていい?と返した。
技術的には正確だったんだと思う。でも僕はプログラマじゃないんだよね。どのファイルの何行目かを並べられても、それが何のためなのかが先に無いと判断できない。
Codeは仕切り直して、何のシステムで、何を変えて、だから何を決めてほしいのか、を日本語の文章で書き直してきた。それなら判断できた。3つとも迷わなかった。
1つ目。MONETが自分で記憶を検索したり保存したりするツールは、両方消す。
2つ目。Librarian(ライブラリアン。裏でメモリを整理する司書役AI)の古いコードは、全部消す。一部だけ消すつもりだったのが、依存をたどると1つ消せば3つが動かなくなる作りだった。部分的に残すと、半分壊れたまま残る。
3つ目。その他、見つかった古いファイルも全部消す。
今までの記憶は消えるけど、それはまた入れ直せばいい。どうしてもQdrantを戻したくなったら、Gitがあるでしょ、と伝えた。
消してみたら、予想よりずっと大きな塊が崩れた(!)
23ファイル、追加30行、削除6,723行。積み上げじゃなくて、解体の日だった。
途中でCodeがいくつか拾ってきた。Qdrant(前の記事で外すと決めた検索用データベース)のDockerコンテナが、誰にも使われないまま5週間起動しっぱなしだった。Macの裏では、古いLibrarianを定期的に起こす仕組みがまだ2本動いていた。いつもダブルクリックで起動していたランチャーは、Qdrantを立ち上げる手順が残っていて、このまま使ったら起動の途中で落ちていたはず。
使っていないものが、使っていないまま動き続けていた。Qdrantの2ヶ月と同じ構図が、まだ足元に残っていた。
全部消したあと、自分でランチャーをダブルクリックしてMONETと話してみた。
普通に話せる。APIも動いている。そしてMONETは、過去のことは何も覚えていない、と正直に言った。
記憶の中身はゼロ。見えているのは今のスレッドだけ。完全な記憶喪失。
でもこれは、壊れたんじゃなくて、正しい中間地点だった。
じゃあこの先、MONETはどうやって思い出すのか。聞いたら、Codeがブリーフィングブックのたとえで説明してきた。
MONETは会議の出席者。Librarianは、会議の前に資料をまとめて机の上に置いておくアシスタント。MONETは会議中に資料室へ走らない。机の上のブックを読むだけ。
今までは、MONETが会話の途中で自分で記憶を検索しに行く作りだった。何を探すか、いつ探すかをMONETが判断する。そうすると、探しに行った結果がそのまま会話に流れ込んで、また混ざる。
新しい作りでは、何を机に置くかを決めるのはLibrarian。そのLibrarianに何を書かせるかを決めるのは僕。MONETは読むだけ。
その日は寝て、翌朝、Librarianの設計に入った。ここは設計だけで、コードはまだ。
入口で正直に言った。自分で設計して、自分でアイデアを出して、全部君に丸投げしておいて、全部俺が忘れてる。
言いながら、ふと思った。脳の記憶の整理って、睡眠中にやってるんじゃなかったっけ。俺のLibrarianが機能してない(笑)
でもそれで、作ろうとしているものの形がはっきりした。Librarianは、MONETが寝ている間に一日の記憶を整理する係。人間が寝ている間にやっていることを、代わりにやる。
一番時間がかかったのは、Librarianへの指示書(SP=システムプロンプト。AIへの事前の指示書)だった。
Codeの最初の案は、よくある形だった。良い例を並べて、「WRONG:」と書いた悪い例も並べて、禁止する言い回しのリストを作る。「HARD RULE」「MUST」が並ぶ。
読んでいて、見覚えがあった。
それって、前のMONETのSPと同じ構造じゃないか、と思って作業を止めた。
前に、脅迫的なSPの話を書いた。「絶対にするな」「捏造は禁止」を並べた指示書が、むしろ嘘を誘っていた。それを書き直したばかりなのに、今度はCodeが、Librarian向けに同じ書き方を始めていた。
同じCodeは、自分の強制的な書き方に自分では気づけない。AIがAI向けの指示を書くと、無意識にそっちへ寄る。
書き直した後の一文はこうなった。
変更前:
HARD RULE: Every bullet MUST contain a timestamp anchor...
変更後:
Each entry needs an anchor. Without an anchor, an entry is a guess, not a record.
禁止するんじゃなくて、理由で導く。悪い例は載せず、良い例だけ置く。書き終わったら、別のClaudeに英語でレビューさせて、1〜2日寝かせてから読み直す。書き方の手順まで、設計書に入れてもらった。
途中でもう1回止めた。
Codeが、スレッドが終わった時にもLibrarianを走らせるべきか、と提案してきた。
CMS(Context Management System。MONETの会話の記憶を整理する仕組み)の全体のゴールは、スレッドを切り替えないことでしょ、と返した。
スレッドを切り替えずに話し続けても、しまう時に仕分けが済んでいる。そのために組んできた仕組みに、スレッドの区切りを前提にした動きを足したら、逆戻りになる。
設計がだいたい形になったところで、Codeに聞いてみた。これって面白いシステムだと思う?忖度抜きで。
返ってきた答えは、半分は褒めて、半分は褒めなかった。
新しいのは、パネルの開閉を分類の合図にすること。記憶の圧縮を、ベクトルじゃなく人間が読める年表で持つこと。一方で、記憶を何層かに分けて持つこと自体は、MemGPT(今のLetta)などの先行研究がある。裏で要約を作り続けるのも、既にあるパターン。
面白いのは手法そのものより、一人のユーザーが何年も使う、中身が見える、持ち運べる、という僕の使い方にぴったり合わせてあるところだ、と。
日本語なのに、結構ガチで忖度なしで言ってくれましたね、と返した。
この日も、コードは1行も書いていない。書いたのはLibrarianの設計書、約600行。
MONETは、まだ何も覚えていない。机の上のブックを書く係は、設計書の中にしかいない。