BLOG.HIRO UENO.ART
← index
2026.03.05

構造を練る

名前がついた翌朝から、僕は紙に絵を描いていた。

Punk Memory System、と呼ぶことにした構造。中央に MONET(オーケストレーター)を置かず、各アプリに独立した AI を住まわせて、メモリだけを全アプリで共有する。そういう絵までは前の月曜日にできていた。

問題はここから先で、メモリって、どう持つの? という話だった。


「全部の会話を 1 つの大きなテキストファイルに溜めて、毎回それを読ませる」というのは、最初の数週間ならいい。でも 1 ヶ月、3 ヶ月、半年と使い続けたら、どう考えても破綻する。コンテキスト長の物理上限がある。それ以前に、そんな大量のテキストの中から「いま必要な情報」を取り出す検索の仕組みも必要になる。

ベガパンク本人がパンクレコーズに直結している、というのは漫画だから成立する話で、実装に落とすには「直結」を分解しないといけない。

ぼんやり 3 つの層が見えていた。


Layer 3 — 歴史年表(タイトルの配列)
   ↑ コンテキストに常に乗せておくもの
   |
Layer 2 — サマリー(タイトル付きの要約)
   ↑ 普段はここで足りる
   |
Layer 1 — 会話の生データ
   ↑ 必要なときに ID で取り出す

いちばん下が生のデータで、その上に圧縮されたサマリーがあって、いちばん上にタイトルだけの年表がある。下に行くほど重く、上に行くほど軽い。

普段は Layer 3 だけ持ち歩いていればいい。「先週話したアレ」みたいに浅く参照するだけなら、タイトルの配列が見えていれば十分だ。もう少し深く知りたくなったら Layer 2 のサマリーを読む。それでも足りないときに、Layer 1 まで降りて生のやり取りを引き出す。

人の記憶って、たぶんこれに近い構造になってるんじゃないか、と思っていた。普段は何があったかの目次だけ持ち歩いていて、必要に応じて中身を解凍する。


ここまで自分で組み立てたところで、Code に、正直どう思う?と聞いた。

Code は 3 つくらい懸念を返してきた。

ひとつめ。「8 アプリ前提は個人 + Claude Code には多すぎます」と言われた。当時、僕は将来的に 8 個くらいのアプリを共有メモリで束ねる前提で考えていた。Code の指摘は実用的で、個人で開発・運用できる範囲はもっと小さい、まずは 2-3 個から始めるべきだ、という話だった。

ふたつめ。「3 層を最初から全部作らないほうがいいです」と言われた。Layer 1 と Layer 2 だけ先に作って、Layer 3 は後から、必要になってから組む、と。

みっつめ。「アプリ別に重み付けをチューニングするのは難しいから、均等から始めたほうがいいです」と言われた。これは、共有メモリで「どのアプリの会話をどれくらい重視するか」みたいな細かい優先度をつける話で、僕は最初からそういう調整をしたかったんだけど、Code は「最初は均等。動かしてから調整」と言ってきた。

正直、3 つとも刺さった。


特に「3 層を一度に作るな」は、自分の癖を突かれた感じだった。

僕は構想の段階だと、つい完成形を全部一度に組もうとする。クリエイティブの仕事を 20 年やっているから、最終形の絵を頭の中でクリアに見るのは得意なんだけど、その絵に向かって一気に走り出す癖がある。実装に入ると、3 層のうちどれかが必ずボトルネックになって、結局 1 つを直しているうちに他の 2 つがついてこなくなる。

これは何度も経験してきたパターンで、頭ではわかっているのに、構想の段階だと忘れる。

なので、Code の懸念をそのまま方針にした。Layer 1 と Layer 2 だけ先に作る。Layer 3 は後で、必要になってから組む。アプリは 2-3 個から始める。重み付けは均等。

完成形のビジョンを持っておくのと、完成形を一度に作ろうとするのは、別の話だ。ビジョンは持っておく。でも実装は段階を踏む。これは設計の話というより、自分の癖との付き合い方の話だな、と思った。


Layer 1 と Layer 2 を、別々のファイルに分けることにした。

Layer 1 は会話のリアルタイム書き込みで、各アプリが「僕と話したらすぐここに保存する」というやつ。書き込み頻度が高い。

Layer 2 はサマリー生成で、僕との会話を読んで要約を作る。書き込み頻度は低いけど、読み込み頻度は高い(普段はここを参照するから)。

書き込みのリズムが違うものを 1 つのファイルに突っ込むのは、後で必ず問題になる、というのが直感だった。corruption が起きたときの被害も違う。Layer 1 が壊れたら最近の会話が消える。Layer 2 が壊れたらサマリーを再生成すればいい。被害の質が違うものは分けておくほうが安全だ、と判断した。

これが正解かはまだわからない。でも、理由を持って分けた。理由を持たずに分けていた今までより、ずっとマシだった。


この時点で、僕は紙の上に Punk Memory System の最初のスケッチを持っていた。

[アプリA] [アプリB] [アプリC] ... ← 各アプリに独立 AI
     ↓        ↓        ↓
  共有メモリ層 (Layer 1 + Layer 2)
     |
  サマリー担当の AI(Librarian)

中身のイメージとしては、各アプリは自分の会話を Layer 1 に書き込み続ける。別途、メモリ専門の AI(Librarian)が定期的に動いて、Layer 1 を読んでサマリーを生成、Layer 2 に書き込む。各アプリは新しい会話を始めるとき、Layer 2 のサマリーをコンテキストに乗せる。これで「あいつ、僕のこと知ってる」状態が維持される。

Librarian は、1月に作った時からの名前で、図書館司書のメタファーから来ている。本(生データ)を整理して、目次(サマリー)を作って、利用者(各アプリ)が必要な情報を探せるようにする。中央集権モデルでは AI が全部やってたけど、Punk Memory System では役割を専門に分けることになる。


スケッチが固まったところで、僕は実装に入る前に止まった。

これ、当面どこから手をつけるんだっけ、と思った。Layer 1 のスキーマを切る? Librarian を先に書く? アプリ側のメモリ書き込みフックを設計する?

優先順位を Code と相談して、こうした。Layer 1 のスキーマを先に切る → 既存のアプリ(VoiceChatBot)に書き込みフックをつける → 1 週間くらい運用ログを溜める → そのデータを使って Librarian の最初のサマリー生成を試す → Layer 2 のスキーマを後付けで決める。

Layer 2 を先に決めなかったのは、サマリーをどう書くかは生のログを見ないとわからない、という判断だった。先にスキーマを固めると、実データに合わない構造になる可能性があった。


正直、Punk Memory System の設計を 1 日で全部固めたわけじゃなかった。何日もかけて紙の上で書き直し、Code と話し、また書き直した。家事の合間に思いつくこともあったし、寝る前に頭の中で組み直すこともあった。

ただ、固まる過程で「自分が何を作りたいのか」が、最初よりずっと明確になっていった。最初は少しネガティブな出発点だったけど、Layer の構造を考えていくうちに「同一人格を共有メモリで成立させる」というポジティブな目標として言語化できるようになった。

中央に MONET を置くのを諦めたわけじゃない、というのは以前自分に言った通りだった。順序を入れ替えただけ。先に末端を独立させて、共有メモリで束ねる。土台ができれば、将来 MONET を上に乗せられる。

その土台を、いま作っている。


ここまで来たところで、ハルシネーション問題のほうは、まだ何も解決していなかった。

Punk Memory System は、ハルシネーションの直接の対策じゃない。中央集権モデルから降りる、という構造判断であって、各アプリの AI がそれぞれハルシネーションを起こす可能性はそのまま残っていた。