今回はコンテキストウインドウの押し出しの正体に迫りたいと思います。特にチャットエージェントを使うケースにおいてはこの仕組みが使われていると推測します。AI利用時に我々は非常に高価なVRAM(GPUメモリ)という椅子を奪い合っているとも言えます。誰かのコンテキストがVRAM上に展開され続けているとは考えにくいことに気付けば理解が容易になるでしょう。
1. 会話の正体:ステートレスなモデルと「文脈の再構築」
まず、LLMの最も重要な特性を理解する必要があります。
LLMの基盤となるモデル自体は、基本的に状態を持たない(ステートレス) な計算機です。人間の脳のように、前の応答の内容を「自己の記憶」として保持することはありません。
では、なぜ会話が続いているように見えるのでしょうか?
それは、システムが各応答のたびに、過去の会話履歴の全てと最新の質問を結合し、一つの長いプロンプトとしてモデルに毎回再入力しているからです。これを文脈の再構築と呼びます。
例えば、以下の様な会話があったとします。
- ユーザ「今日の渋谷の天気は?」
- エージェント「今日の渋谷は晴れです」
- ユーザ「明日の渋谷の天気は?」
エージェントという仕組みが明日の天気を尋ねた際のリクエストを 「今日の渋谷の天気は?」「今日の渋谷は晴れです」「明日の渋谷の天気は?」 という一連の文字列にして再構築しているのです。
LLMから見れば、会話の継続とは、プロンプトの長さに合わせて過去のデータが 「再入力され続けている」 状態に過ぎません。そして、この再入力されたデータこそが「短期記憶」として機能するコンテキストウィンドウです。
2. VRAMの物理的制約:コンテキストウィンドウの限界
会話の履歴を毎回再入力する仕組みは、LLMのアーキテクチャに由来する物理的な限界に直面します。それが、モデルが一度に処理できる最大トークン数を定めるコンテキストウィンドウの制約です。
この制約は、主に二つの要因から生じます。
A. $O(n^2)$ の計算コスト
現代のLLMの中核であるトランスフォーマーは、アテンション(注意)メカニズムを使用します。このアテンション計算に必要な時間は、入力トークン数($n$)の二乗 ($O(n^2)$) に比例して増加します。トークン数が倍になると、計算負荷は4倍になるため、無限にコンテキストを広げると、処理コストと時間が非現実的になります。
B. VRAM(GPUメモリ)の容量限界
さらに現実的な問題が、VRAM(GPUメモリ)の容量限界です。モデルは推論を行う際、その巨大なパラメータ(重み)自体をVRAMにロードします。これに加えて、入力されたプロンプト(長文の履歴)の処理中に生成されるすべての中間データ(アクティベーション)をVRAMに保持する必要があります。
会話が長くなり、トークン数が増加すると、この中間データの量が爆発的に増え、有限なVRAMを圧迫します。
「コンテキスト押し出し」の真実
VRAMの限界を超過する事態を避け、モデルの安定動作を確保するため、システムはプロンプトの合計トークン数がコンテキストウィンドウの最大値を超過する場合、最も古い会話の履歴をリクエストから除外します。そして、「コンテキストウィンドウの容量内に収まった、最新の部分の履歴」のみを最新の質問と結合し、モデルへのリクエストとして生成します。
モデルは、リクエストに含まれなかった情報(除外された履歴) を「今回の入力データに含まれていなかった」としか認識できません。
したがって、コンテキストの押し出しは、モデルの「忘却」ではなく、「物理的制約によるデータ管理の結果であり、最初から入力されていない事実を知らないが故の幻想とも言える」のです。LLM自体にもTruncateという機能がありますが、最初から渡さないことでトークン効率も上がるので椅子取りゲームのスループット(回転率) を高めることに貢献していると言えるでしょう。
3. 永続的な外部記憶:長期的な知識の維持
この短期記憶の限界を克服するために、LLMシステムは永続的な外部記憶を利用します。
ベクトル/グラフデータベースの役割
会話履歴が VRAM 上の一時的なデータであるのに対し、ベクトルデータベースやグラフデータベースは、知識や文書を埋め込みとして永続的なストレージに保存します。これらは、会話がリセットされても情報が失われない「長期記憶」として機能します。
記憶の復元(RAG)
この外部記憶の仕組みは、RAG(検索拡張生成、Retrieval-Augmented Generation) によって実用化されています。
- トリガー(検索): ユーザーの最新の質問をトリガーとして、データベースから関連情報が検索されます。
- コンテキストへの注入: 取り出された関連情報(文書のスニペットなど)は、最新のプロンプトの一部としてLLMの現在のコンテキストウィンドウに注入されます。
これにより、LLMは短期記憶(会話履歴)が削られても、外部の知識を参照し、一貫性のある応答を生成することが出来ますが、外部記憶はトークンに分割されている特性からチャンク欠落を発生させることがあるという 事実に注意する必要があります。
ここまでをフローチャートで表すとこの様になります。
結論:積み上げられた長文プロンプトの克服
コンテキスト押し出しの真実を理解することは、LLMを賢く使いこなすための第一歩です。
LLMは記憶力に欠けるわけではなく、物理的な制約内で動作する高度な計算機です。会話の継続とは、制御が難しい 「積み上げられた長文プロンプト」 を管理し続ける作業に他なりません。
この仕組みを踏まえた上で、LLMの限界を克服するための戦略は次の二点に集約されます。
- 高密度なプロンプト設計: 重要な前提やルールは、会話の中盤で流されるリスクを避けるため、繰り返し、かつ簡潔に与えることで、限られたコンテキストウィンドウ内で情報の密度を高める。
- 外部知識の活用: 知識の永続化が必要な場合は、RAGなどの仕組みを利用し、外部データベース(長期記憶) との連携を前提としたシステム設計を行う。
勘の鋭い方なら気付いたことでしょう。これはチャットエージェントというツールが隠蔽しているだけのマルチエージェントではないか?と。まさにその通りで、我々は知らず知らずのうちにマルチエージェントを使っていたということになります。そのマルチエージェントを受動的に使い続けるか、能動的に使いこなすかという選択こそがコンテキストエンジニリングの本質とも言えるでしょう。