チャットエージェントを使う際にその裏側で我々はどの様にコミュニケーションをとっているのか考えたことはありますか?
Garbage In, Garbage Out(ゴミを入れたら、ゴミが出てくる)とはうまく言ったもので、今回はチャット形式のAI活用が非常に制御が難しいものである理由を見ていきましょう。
1. 標準的な会話履歴の配列構造
LLMは、ユーザーとの対話を以下のようなJSON形式の配列として受け取ります。この構造は、会話の履歴を時系列で保持し、各ターンが話者の役割(role)および内容(content)で構成されます。
[
{"role": "user", "content": "ReactでUserProfileコンポーネントを作って"},
{"role": "assistant", "content": "UserProfileコンポーネントのコード:..."},
/** 中略 */
{"role": "user", "content": "さっきのコードに状態を追加して"}
]
- 構造の特徴:
- 各ターンはrole(user、assistant、および設定用のsystemなど)とcontent(実際のテキスト)で構成。
- 配列は時系列順で、最新のターンが最後に位置します。
- モデルは、この配列全体を一つのコンテキストとして処理し、最新のターンを現在のタスクとして認識するよう設計されています。
- 最新のターンの役割:
最新のターン(配列の最後の要素)は、ユーザーの現在の意図やタスクを定義します。上記の例では「さっきのコードに状態を追加して」が最新のタスクであり、モデルはこれを主軸に処理を進めます。 - 過去のターンの役割:
それ以外のターン(過去の対話)は、コンテキスト提供の補助として機能します。たとえば、「UserProfileコンポーネント」のコードが最新のタスクに関連する情報として参照されます。
この配列構造自体はシンプルですが、モデルがどのターンをどの程度重視するかは、内部のアテンション機構による動的な重み計算に依存します。
2. 問題と最新ターンの認識の課題
LLMは、最新のターンを優先的に処理するよう訓練されていますが、以下のような課題が存在します。
問題点
- アテンションの焦点移動(コンテキストドリフト):
最新のターンが短く曖昧であったり、過去のターンに強力なキーワードや関連性の高い詳細な情報が含まれている場合、モデルが過去のターンに過剰にフォーカスする可能性があります。これは、アテンション機構が最新ターンよりも過去の関連性の高い情報に、意図せず高い重みを割り当ててしまう現象です。 - 長距離依存性(コンテキストの希薄化):
長い会話履歴では、トランスフォーマーモデルの性質上、配列の先頭に近い古いターンの影響力が低下する傾向があります。これは、アテンション機構が時間的に遠い情報を「薄く」扱うためです(近年のモデル改良により以前よりは緩和傾向にあります)。ユーザーが明示的に古いターンを参照した場合でも、モデルが適切に情報を拾い上げられる保証はありません。 - 曖昧さによる応答のブレ:
最新のターンが曖昧(例: 「続きをやって」「それについてもっと教えて」)だと、モデルはどの過去のターンが関連するかを正確に判断できず、意図しない過去の文脈に引きずられ、不安定な結果を生成するリスクが高まります。
最新の認識の期待値
LLMは、トランスフォーマーモデルのアテンション機構を活用し、最新のターンに高い重みを割り当てるよう訓練されています。具体的には: - 最新のターンはタスクの「アンカー」(Queryトークン)として機能し、モデルはこれを基にコンテキストを構築します。
- 過去のターンは、最新のターンとの意味的関連性に基づいて参照され(Key/Valueトークン)、関連性の高い情報(例: キーワード、具体的なコード)が優先的に抽出されます。
しかし、この「最新のターンを優先する」という動作は、モデルの訓練データや入力内容に依存する期待値でしかありません。実際の動作は、コンテキスト全体のトークン間の関連性や、アテンションスコアの動的な計算結果に左右されます。
3. アテンション機構に大きく依存した設計の課題
LLMの会話履歴処理は、トランスフォーマーの自己アテンション機構に大きく依存していますが、この依存は設計上の課題を浮き彫りにします。
アテンション機構の限界
-
動的な重み計算の不確実性:
アテンション機構は、トークン間の関連性を動的に計算しますが、ユーザーが意図した優先順位を完全に反映する保証はありません。最新のターンが短くても、過去のターンが詳細で情報量が圧倒的に多い場合、アテンション機構は後者に高い重みを割り当て、タスクの実行を妨げることがあります。 -
コンテキストドリフトの発生 (Context Drift):
アテンション機構が、意図したアンカーである最新のターンから焦点を外して、過去の会話履歴に含まれる強力なキーワードや詳細な情報に過剰にフォーカスしてしまう現象です。これにより、モデルは最新のタスクを実行する代わりに、過去の文脈に基づいた不適切な応答や、既に完了したタスクの再処理を行うリスクが高まります。これは、アテンションスコアが最新のターンよりも過去の関連性の高い情報に、モデルの意図とは異なって高い重みを割り当ててしまうことで引き起こされます。 -
動作の非制御性(ブラックボックス性):
アテンションスコアの具体的な計算は、モデルの内部状態に依存し、ユーザーが直接制御できないブラックボックスです。これにより、最新のターンが期待通りに優先されるかどうかは、入力の書き方(プロンプト)や履歴の構造に強く依存します。 -
トークン効率とパフォーマンスのトレードオフ:
長い会話履歴では、関連性の低い古いターンがコンテキストに含まれることで、トークン制限を圧迫し、処理効率が低下します。特にアテンション機構の計算量はトークン数の二乗 ($O(N^2)$) に比例するため、推論コストを上昇させるリスクがあります。
設計上のトレードオフとその影響
以下のような履歴の場合、アテンション機構への過度な依存が問題を引き起こします:
[
{"role": "user", "content": "詳細なコメント付きでReactコンポーネントを作って"},
{"role": "assistant", "content": "詳細なコメント付きのコード:..."},
{"role": "user", "content": "状態を追加して"}
]
- 期待される動作: モデルは「状態を追加して」にフォーカスし、前のコードに状態管理を追加します。
- 発生しうる問題: 過去の「詳細なコメント付き」という文脈が強力なアテンションスコアを持つ場合、モデルがタスクの本質である状態追加よりも、コメントの再生成や冗長な説明に時間を費やし、タスクの達成度が低下する可能性があります。
このようなケースは、アテンション機構が最新のタスクを正しく優先するかどうかを 「プロンプトの記述力」と「モデルの訓練傾向」に委ねていることを示しています。
結論
我々がチャットエージェントを活用する裏では単に誰が何を言ったかの配列のやり取りが行われており、トークン数が増えれば増えるほどにコンテキストの把握は難しいものとなります。チャットエージェントにはメッセージのタイミングからやり直す(リバート)機能を用意しているものもありますが、途中の対話は消え去り再構築することは困難です。ゴミを入れてしまえば、上限を迎えて切り捨てられない限りは配列の要素として残り続けます。
履歴を要約してエージェントに与えればコンテキストが綺麗になるという誤解もありますが、これは長大な配列に巨大な要素を追加するだけの愚策でしかありません。素直に新しいセッションを立ち上げるべきです。
求める答えに辿り着くまでの試行錯誤はまるでシュタインズ・ゲートの世界線を乗り越えようという試みにも通じるものがありますね。今日はこの言葉で締めましょう。
あれー。まゆしぃの懐中止まっちゃってるー。おかしいなぁ…さっきねじ巻いたばっかりなのに…