MicroArchitectures
H.Ueda
Programmer
ブログ
LLMのメモリ管理に「論理プログラミング」の手法を取り入れてみた話
今回は、脆弱性調査におけるLLMの活用を模索する中で見つけた I accidentally turned LLM memory into program analysis という記事の内容を参考に、LLMの記憶(メモリ)をプログラム解析のように管理するアプローチについて整理してみます。
中々面白そうな記事でした。LLMのメモリがプログラムの解析中の状態に似ていると言うのは、ありがち間違いではない気がします。
LLM(大規模言語モデル)を長時間にわたる複雑な調査、例えば脆弱性の探索などに使っていると、ある共通の壁に突き当たることがあります。それは、モデルが「以前に確定した事実」を見失ったり、すでに否定された仮定に基づいて推論を続けてしまうという問題です。
この記事では、その解決策として「Datalog」というプログラム解析でよく使われる手法をメモリ管理に応用する、面白い試みが紹介されていました。
LLMが抱える「記憶の矛盾」という課題
LLMエージェントに複雑なコードベースの解析を任せると、最初は優秀に動いてくれます。しかし、数時間が経過すると以下のような現象が起こり始めます。
- すでに「不可能」と判断したはずの攻撃手法を再び提案してくる
- 調査の過程で「誤り」だと判明した情報を、依然として正しい前提として使い続ける
- 「それは間違っている」と指摘しても、その間違いから導き出された他の結論まで修正してくれない
一般的なLLMのメモリシステム(RAG:検索拡張生成)では、過去の会話や情報をベクトル化して保存し、必要に応じて検索します。しかし、これでは「情報の断片」を取り出せても、「情報の論理性」を維持することが難しいという側面があります。
たとえば、以下のような推論の積み重ねがあったとします。
- 観察 A: 攻撃者が
object_aを操作できる - 観察 B:
object_aはobject_bを参照している - 観察 C:
object_bはカーネルオブジェクトである - 結論: よって、攻撃者はカーネルオブジェクトを操作できる可能性がある
ここまでは良いのですが、2時間後に調査を進めた結果、「実は観察 B(参照関係)は間違いだった」とわかった場合、通常のメモリシステムでは「観察 B は間違い」という新しい事実が追加されるだけで、それまでの「結論」が自動的に取り消されるわけではありません。
プログラム解析の考え方を応用する
元記事の筆者は、この状況が「プログラム解析」の仕組みに似ていることに気づきました。プログラム解析の世界では、いくつかの事実とルールを定義し、それらから導き出される「不動点(それ以上新しい事実が増えない状態)」を計算します。
ここで登場するのが、Datalog という宣言型の論理プログラミング言語です。
Datalog による推論のイメージ
Datalogでは、以下のように事実とルールを記述します。
/* 事実の定義 */
controls(attacker, object_a).
points_to(object_a, object_b).
kernel_object(object_b).
/* ルールの定義:もしAがBを制御し、BがCを指し、Cがカーネルなら、Aはカーネルを制御できる */
controls_kernel_object(Attacker) :-
controls(Attacker, ObjectA),
points_to(ObjectA, ObjectB),
kernel_object(ObjectB).
この仕組みの優れた点は、「前提となる事実が消えたら、そこから導かれた結論も自動的に消える」 ということです。
もし points_to(object_a, object_b) という事実が削除されれば、controls_kernel_object(attacker) という結論も存在しなくなります。これをLLMのメモリに応用すれば、情報の整合性を保てるのではないか、というのが筆者のアイデアです。
メモリシステムの仕組み
この「論理的なメモリ」は、以下のような流れで動作します。
flowchart TD
A["LLMによる調査・観察"] --> B["観察結果を事実 (Fact) として抽出"]
B --> C["Datalogエンジンへ登録"]
C --> D["定義されたルールに基づき自動推論"]
D --> E["現在の『有効な結論』をモデルに提供"]
F["調査が進み、矛盾が判明"] --> G["特定の事実を削除 (Retract)"]
G --> C
C -- "影響を受ける結論が自動消滅" --> E
このように、LLM自身にすべての文脈を覚えさせておくのではなく、LLMが見つけた個々の事実を「論理エンジン」という外部の構造化されたメモリに預けるイメージです。
従来のRAGと論理メモリの比較
| 特徴 | 従来のベクトル検索 (RAG) | 論理メモリ (Datalog) |
|---|---|---|
| 検索手法 | 意味の近さ(類似性) | 論理的なつながり |
| 整合性の維持 | 困難(矛盾する情報が混在する) | 容易(前提が崩れれば結論も消える) |
| 得意なこと | 過去の似た情報の参照 | 複雑な依存関係の追跡 |
| データの形式 | 自然文の断片 | 構造化された「事実」と「ルール」 |
このアプローチの利点
この手法を導入することで、LLMは常に「現時点で論理的に正しいとわかっていること」だけに集中できるようになります。
特に脆弱性調査のような、「AならばB、BならばC」といった積み重ねが重要な領域では、この「事実の自動更新(取り消し)」機能が大きな効果を発揮しそうです。LLMに「何が正解か」を判断させる負担を減らし、ロジックの管理を堅牢なシステム側に任せるという考え方は、エージェントの信頼性を高めるための一つの鍵になるかもしれません。
まとめ
LLMのメモリを単なる「過去ログの検索」として捉えるのではなく、プログラム解析のような「論理的な状態管理」として扱うという視点は非常に新鮮です。
もちろん、あらゆる情報を構造化されたルールに落とし込むのは大変そうですが、特定のドメイン(セキュリティ調査やバグ探索など)に特化させるのであれば、こちらの方がハルシネーションを抑えつつ深い調査ができるようになるのではないかと感じました。
このような「LLM」と「伝統的な論理エンジン」を組み合わせるハイブリッドなアプローチは、今後さらに増えていくのかもしれません。