はじめに
これまで3回にわたり、Personal AIの記憶について考えてきた。
第1部では、日々の会話や日記を「概念ID」として整理する方法を考えた。
第2部では、LLMが現在の会話から注目すべき概念を推論する仕組みを紹介した。
第3部では、概念と経験を分離した。
そして最終回。
これまでの会話や日記を読み込ませるだけで、Personal AIの記憶を構築できないだろうか。
今回のテーマは、過去ログからの学習と、その記憶を利用した推論である。
1. 過去ログをそのまま検索する必要はない
例えば、次のような過去ログがある。
10月20日、丹沢山に登った。
途中から雨になり、下山時には暗くなった。
同行者とライトを使って下山した。
通常のRAGなら、この文章をEmbeddingして検索対象にする。
しかし、今回の構想では、まずLLMに概念を抽出させる。
ID1:登山
ID2:丹沢山
ID3:雨
ID4:同行者
ID5:暗闇
ID6:ライト
そして、これらを一つの経験に結び付ける。
E101:丹沢山での登山
E101 ─ ID1
E101 ─ ID2
E101 ─ ID3
E101 ─ ID4
E101 ─ ID5
E101 ─ ID6
ここで重要なのは、日記を捨てるわけではないことだ。
元の日記は経験IDに紐付けて保存しておく。
概念IDは、そこへアクセスするための索引になる。
2. 概念同士の結合を学習する
次に、過去ログに登場する概念の関係を集計する。
例えば、次のようなログがあるとする。
E101:友人と登山した。
とても楽しかった。
E102:仕事で疲れたので山へ行った。
良い気分転換になった。
E103:友人と食事した。
お腹いっぱいになった。
LLMはそれぞれの経験から概念と関係性を抽出する。
例えば、
登山 ─ 友人
登山 ─ 楽しい
登山 ─ 気分転換
食事 ─ 満腹感
食事 ─ 友人
ここで、概念同士の結合に重みを持たせる。
同じ関係が複数の経験で確認されれば、結合は強くなる。
ただし、単に同じ文章に登場しただけで強い関連があるとは限らない。
そのため、LLMには概念の抽出だけでなく、文章の中で実際に関係が示されているかも判断させる。
そして、抽出した結合と、その根拠となる経験IDを保存する。
これが、今回のPersonal AIにおける「学習」である。
LLM自身のパラメータを更新するわけではない。
個人の経験に基づいて、概念間の結合構造を更新する。
3. まずはSQLiteだけで十分
今回必要なデータは4種類である。
| テーブル | 保存する内容 |
|---|---|
| concepts | 概念IDと名称 |
| experiences | 経験IDと元の記録 |
| concept_links | 概念間の結合重み |
| experience_links | 概念と経験の関連 |
この程度なら、最初からNeo4jやベクトルDBを導入する必要はない。
SQLiteで十分に試作できる。
重要なのはデータベースの種類ではなく、LLMが概念を同定し、適切な結合を形成できるかどうかだ。
4. 過去ログから記憶を生成する
処理は次のようになる。
Telegram・LINE・音声・日記
↓
LLMがログを解析
↓
経験と概念を抽出
↓
既存概念IDと照合
↓
新しい経験IDを保存
↓
概念間の結合を更新
↓
Personal Memory
LLMへの指示も複雑にする必要はない。
例えば、次のようなプロンプトが考えられる。
あなたは個人の記憶を整理するAIです。
入力された会話や日記から、
経験と関連する概念を抽出してください。
既存の概念がある場合は、そのIDを再利用してください。
新しい概念が必要なら、候補として追加してください。
概念同士に明確な関連がある場合は、
その関係を抽出してください。
推測した内容と明示された事実は区別してください。
結果はJSON形式で返してください。
例えば、LLMが次のようなデータを返す。
{
"experience": {
"title": "丹沢山での登山",
"content": "友人と丹沢山に登った"
},
"concepts": [
"登山",
"丹沢山",
"友人"
],
"connections": [
["登山", "丹沢山"],
["登山", "友人"]
]
}
ここでは、読みやすさのために概念名を使用している。
実際の保存時には、既存IDを照合し、概念IDと経験IDに変換する。
こうして日記を一件ずつ登録していけば、個人の概念空間が形成される。
5. 重みは経験によって変化する
結合重みをどう更新するか。
最初は、単純な方法でよい。
例えば、結合の強度を0から1の範囲で表現する。
新しい独立した経験で同じ関係が確認された場合、少しだけ強化する。
def strengthen(weight, learning_rate=0.1):
return weight + learning_rate * (1 - weight)
例えば、現在の結合重みが0.5なら、更新後は0.55になる。
同じ経験のログを何度も処理して重みが増えないよう、経験IDによる重複チェックも必要だ。
また、本人が後から発言を訂正した場合は、結合を再評価する。
この方法が最適というわけではないが、初期実装としては十分に単純だ。
6. 学習した記憶をどう使うのか
次に、記憶を利用する。
例えば、ユーザーが次のように発言したとする。
「最近、気分転換できていない」
LLMは、この発言から「気分転換」という概念IDを選択する。
その概念に強く関連するIDを取得する。
気分転換
↓
登山
↓
過去の登山経験
そして、関連する経験IDから過去の日記を取得する。
ここでLLMに渡すのは、概念名だけではない。
実際に経験した出来事である。
例えば、過去の日記で登山が良い気分転換になったと記録されていれば、LLMはその経験を踏まえた提案ができる。
単に「気分転換には登山がおすすめです」と答えるのではなく、
「以前、仕事で疲れたときに登山へ行き、気分転換になったと記録されていますね」
といった回答が可能になる。
もちろん、現在も登山を希望しているとは限らない。
過去の経験は判断材料であって、現在の意思を決めつけるものではない。
7. 新しい経験が、次の回答を変える
ここでPersonal AIとして重要な循環が生まれる。
会話・経験
↓
概念を抽出
↓
経験IDを保存
↓
結合重みを更新
↓
次の会話で関連記憶を取得
↓
LLMが推論
↓
新しい経験
毎日の会話によって、概念間の結合が少しずつ変化する。
例えば、以前は登山と気分転換の結合が強かったとしても、最近は音楽や食事の話が増えるかもしれない。
その経験が記録されれば、関連する結合も変化する。
つまり、同じ質問をしたとしても、過去の経験の蓄積によって取得される記憶が変わる。
ここに、Personal AIとしての適応が生まれる。
8. Attentionと概念圧縮の関係
今回の構想は、TransformerのAttentionから着想を得ている。
しかし、実装を整理してみると、本質はAttentionそのものではなかった。
自然言語の記録を、一度概念へ整理すること。
そして、現在の文脈から注目する概念を選び、その概念に結び付いた経験を取り出すこと。
この二段階の構造に意味がある。
従来型RAG
質問 → 文章検索 → 回答
今回のPersonal RAG
質問
↓
注目概念ID
↓
関連する概念ID
↓
経験ID
↓
過去の記録
↓
回答
概念同士の結合は、日々の経験によって変化する。
そのため、単なる固定辞書とは違う。
また、概念IDを使うからといって、必ずしも高次元のEmbeddingが必要になるわけではない。
概念数が比較的少ないうちは、LLMによるID選択とSQLiteによる関連検索だけでも実験できる。
最初から仕組みを複雑にする必要はない。
9. 構想から実装へ
最終的なアーキテクチャは、次のようになる。
過去ログ・新しい会話
│
▼
LLM
概念・経験の抽出
│
▼
Personal Memory
┌────────────────┐
│ Concept ID │
│ Experience ID │
│ Connection │
│ Weight │
└────────────────┘
▲
│
概念IDを検索
│
LLM
現在の会話
│
▼
関連する経験を取得
│
▼
LLMによる推論
│
▼
回答・行動・記録
既存のPersonal AI Agentへ統合する場合も、Redmineやブログ生成Agentを改修する必要は必ずしもない。
会話を解釈する段階でPersonal Memoryへアクセスできるようにすればよい。
過去ログの取り込みと、新しい会話の記録を同じ仕組みで処理する。
そこから概念と経験の結合が更新される。
これが、今回目指した記憶アーキテクチャの基本形である。
10. まとめ ― AIに必要なのは、巨大な記憶なのか
全4回にわたって、Personal AIの記憶について考えてきた。
最初は、TransformerのAttentionを外部記憶に応用するという発想だった。
そこから、概念ID、経験ID、結合重みというデータモデルへ整理してきた。
最終的にたどり着いたのは、比較的シンプルな構造である。
日々の経験を概念へ圧縮し、概念同士の結合を更新し、その概念から必要な経験へ戻る。
これなら、個人の記憶を持たせるために、LLMそのものを毎回ファインチューニングする必要はない。
また、最初から巨大なベクトルDBや複雑なGraphRAGを導入する必要もない。
まずは小さな概念空間を作り、過去ログから学習させる。
そして、日々の会話を通じて結合を育てていく。
もちろん、これだけで人間の記憶を完全に再現できるわけではない。
概念抽出の精度、結合重みの妥当性、誤った記憶の修正など、検証すべき問題は残る。
しかし、技術的な出発点としては十分ではないだろうか。
人間は誰かの名前を聞いたとき、その人との会話を一字一句、全文検索しているわけではない。
その人と過ごした場所、出来事、交わした言葉、そして思い出が結び付いている。
それに近い仕組みを、LLMと小さな概念データモデルで実現できないか。
それが今回の試みだった。
LLMを個人向けに育てるのではなく、LLMが参照する個人の記憶を育てる。
この考え方を、今後のPersonal AI Agentの実装に取り入れていきたい。
全4部・完
タグ: LLM / RAG / Python / SQLite / PersonalAI
