「BabyAGIやAutoGPTのような自律型エージェントを作ってみたけれど、少し複雑なタスクを投げるとAPIコストが青天井になってしまった」
最近、開発現場ではこのような課題が頻繁に議論されています。プロトタイプ段階では数百円で済んでいたものが、実運用を見据えてループ回数を増やしたり、メモリ(記憶)を強化したりした途端、一回の実行で数千トークンを消費し続けるモンスターに変わる。これは、多くの開発者が直面する「自律型エージェントの成長痛」と言えるでしょう。
エージェントが賢く振る舞うためには、過去の行動履歴や思考プロセスといった「コンテキスト」が必要です。しかし、それを全てプロンプトに詰め込めば、コンテキストウィンドウはすぐに溢れ、コストは爆発し、レスポンス速度(レイテンシ)は低下します。対話の自然さと業務要件のバランスを保つためには、この問題への対処が不可欠です。
ここで多くの人が陥る誤解があります。それは、「過去のログを要約すればいい」という安直な解決策に飛びついてしまうことです。
実は、人間にとって読みやすい「要約」と、LLM(大規模言語モデル)にとって理解しやすい「圧縮」は、全く異なる概念です。ここを混同したままシステムを組むと、エージェントは重要な指示を見落とし、期待した動作をしてくれなくなります。
今回は、単なる節約テクニックとしてのプロンプト短縮ではなく、エージェントのパフォーマンスを維持しながら情報密度を極限まで高める「データ処理パイプラインとしてのプロンプト圧縮」について、アーキテクチャの視点から解説します。
自律型エージェントにおける「記憶」とコストのジレンマ
自律型エージェントの設計において、多くのプロジェクトで共通して重要視されるのが「記憶の鮮度と密度」です。エージェントにとっての記憶とは、すなわちプロンプトに含まれるコンテキスト情報のことを指します。
エージェントの思考ログが引き起こすトークン爆発
自律型エージェント、特にReAct(Reasoning + Acting)パターンの実装では、モデルは「観測(Observation)」「思考(Thought)」「行動(Action)」のサイクルを繰り返します。タスクが完了するまで、このサイクルは履歴として蓄積され、次のステップの入力として再利用されます。
例えば、調査タスクでエージェントが5回検索を繰り返したと仮定します。初期のプロンプトが1,000トークンだったとしても、各ステップで検索結果と思考プロセスが追加されていくため、5ターン目には入力が10,000トークンを超えているケースは珍しくありません。
現在、APIの標準モデルは大きく移行しています。OpenAI APIではGPT-4oなどの旧モデルが廃止され、より長い文脈理解と高度な推論を備えたGPT-5.2(InstantおよびThinking)が新たな主力となりました。また、AnthropicのClaudeでは、ベータ版ながら100万トークンという膨大なコンテキストウィンドウをサポートしています。しかし、このようにモデルのコンテキストウィンドウが大幅に拡大されたとしても、コスト構造の課題は依然として残ります。
多くのAPI課金モデルでは、入力トークンに対しても課金が発生します。1ターン目のコストだけでなく、過去の全履歴を毎回送信することで、n回目のターンでは 1 + 2 + ... + n のように、総トークン消費量が二次関数的に増大してしまうのです。高性能なAPIモデルの単価が最適化されたとしても、扱う情報量が爆発的に増えれば、結果としてコストは膨れ上がります。
コストだけではない:レイテンシと精度のトレードオフ
問題は予算だけではありません。入力トークンが増えれば増えるほど、APIが最初のトークンを出力するまでの時間(TTFT: Time To First Token)は長くなります。ユーザーを待たせる時間が長くなるだけでなく、システム全体の処理スループットが低下します。
さらに深刻なのが「Lost in the Middle」現象です。近年の研究でも指摘されている通り、コンテキストウィンドウが長くなると、AIモデルは入力の中間部分にある情報を無視しやすくなる傾向があります。つまり、情報を詰め込めば詰め込むほど、エージェントは過去の重要な制約条件や文脈を「忘れる」リスクが高まるのです。最新のChatGPTやClaudeでは長い文脈の理解力や検証可能な推論能力が大きく向上していますが、それでも無尽蔵にログを投入することは、精度低下の要因になり得ます。
データ処理としての「コンテキスト管理」の必要性
このジレンマを解消するためには、「全ての情報を保持する」という考え方を捨て、「タスク達成に必要な情報だけを蒸留する」という発想の転換が必要です。
これはもはや、単なるプロンプトの記述テクニックという領域を超えています。入力データを分析し、ノイズを除去し、重要度に基づいてフィルタリングを行う、一種のETL(Extract, Transform, Load)プロセスとしてコンテキスト管理を捉える必要があります。
最近の動向として、ClaudeのCompaction機能のように、コンテキスト上限に近づくと自動でサマリーを生成し、無限に近い会話を実現する仕組みや、タスクの複雑度に応じて思考の深さを自動調整するAdaptive Thinkingといった機能も登場しています。こうした最新のAPI機能を積極的に活用しつつ、システム側でも不要な履歴を適切に圧縮・要約するパイプラインを構築することが、コストと性能を両立する鍵となります。
プロンプト圧縮のメカニズム:情報の「蒸留」とは何か
では、具体的にどうやって情報を減らせばいいのでしょうか。ここで重要になるのが、「要約(Summarization)」と「圧縮(Compression)」の違いです。
構文的圧縮 vs 意味論的圧縮
プロンプト圧縮には大きく分けて二つのアプローチがあります。
一つは構文的圧縮です。これは、空白、改行、ストップワード(「の」「は」「です」など)を削除する手法です。人間には読みづらくなりますが、LLMはある程度文脈を補完して理解できます。しかし、これによる削減率はせいぜい10〜20%程度で、根本的な解決にはなりません。
もう一つが意味論的圧縮です。これは、文章の意味(セマンティクス)を保ったまま、より少ないトークンで表現し直す、あるいは情報の重要度に基づいて内容を間引く手法です。
情報エントロピーとLLMの理解能力
情報理論の観点から見ると、言語には多くの冗長性が含まれています。LLMは次に続く言葉を予測する確率モデルですから、「予測しやすい言葉」は情報量が低く、「予測しにくい言葉」は情報量が高いと言えます。
プロンプト圧縮の核心は、この「情報エントロピー」を利用することにあります。LLMにとって予測可能な(当たり前の)情報は削除しても文脈の理解に影響を与えません。逆に、固有名詞や数値、否定命令などの予測しにくい情報は、削除すると意味が大きく変わってしまいます。
要約(Summarization)と圧縮(Compression)の決定的な違い
ここで冒頭の誤解に戻りましょう。
- 要約: 人間が読んで理解できるように、文章を短く再構成すること。
- 圧縮: LLMがタスクを実行するために必要な情報密度(ベクトルとしての意味)を維持したまま、トークン数を減らすこと。
例えば、エージェントのログに「エラーが発生しました。再試行します」という記述が10回あったとします。
人間向けの要約なら「何度かエラーが出たが再試行した」となるでしょう。しかし、LLM向けの圧縮では、この情報自体がタスク解決に不要(ノイズ)であれば、バッサリと削除する、あるいは「Error_Retry_Count: 10」というメタデータに変換する方が有効な場合があります。
自律型エージェントにおいては、人間にとっての可読性よりも、モデルにとっての「解釈可能性」と「トークン効率」を優先すべきなのです。
ステージ1:データクレンジングと前処理
高度なアルゴリズムを導入する前に、まずは基本的なデータクレンジングを行いましょう。これだけでコストの3割程度を削減できることもあります。
冗長なシステムプロンプトのダイエット
多くの開発者が、システムプロンプト(System Message)に丁寧な言葉を使いすぎています。「あなたは親切なアシスタントです。ユーザーの質問に対して、以下の手順で回答してください...」といった記述は、実はかなり削れます。
指示は命令形にし、敬語を省きます。「回答せよ」「手順に従え」といった具合です。また、同じ意味の指示を繰り返していないかチェックしてください。プロンプトが長くなると、開発過程での継ぎ足しによって重複が発生しがちです。
思考プロセス(Chain of Thought)の事後フィルタリング
自律型エージェントは「思考(Thought)」を出力することで推論精度を高めます(Chain of Thought)。しかし、一度タスクが完了してしまえば、その過程にあった「迷い」や「試行錯誤」のログは、次のステップにとってノイズになることが多いです。
例えば、エージェントが「Aという方法を試す...失敗。Bを試す...成功」というログを残した場合、履歴として保持すべきは「Bで成功した」という事実だけです。タスク完了時やステップの区切りで、失敗した試行のログを削除、または「Method A failed」程度に短縮する処理を挟むことをお勧めします。
JSON/XML構造の最適化とトークン節約
エージェント間の通信やツール呼び出しにJSONを使うのは一般的ですが、JSONのキー名や括弧もトークンを消費します。
{
"thought": "ユーザーの意図を理解しました",
"action": "search",
"parameters": {
"query": "AI トレンド"
}
}
このような構造を毎回送受信するのは無駄が多いです。独自の短縮記法(例えば Thought: ... | Act: search(AI トレンド))を定義し、システムプロンプトでパース方法を一言教えるだけで、構造化データのトークン数を半分以下に抑えることができます。
ステージ2:高度な圧縮アルゴリズムの実装
前処理だけでは限界がある場合、より技術的な圧縮アプローチを採用します。ここでは、現在注目されているいくつかの手法を紹介します。
選択的コンテキスト(Selective Context)によるフィルタリング
「Selective Context」は、入力テキスト内の各トークンの「自己情報量(Self-Information)」を計算し、情報量が低い(つまり予測可能な)トークンを削除する手法です。
具体的には、小さな言語モデル(Llamaの最新軽量モデルや1B〜3BクラスのSLMなど)を使って、プロンプト内の各文やフレーズのPerplexity(困惑度)を測定します。Perplexityが低い部分は「文脈から容易に推測可能」であると判断し、削除または要約します。
これにより、文法的には少し崩れた文章になる可能性がありますが、LLMはキーワード間の関係性から意味を復元できるため、タスクの遂行能力は維持されます。計算リソースの少ないエッジ環境でも運用しやすいのが利点です。
LLMLinguaなどの蒸留モデル活用
最近注目されているのが、Microsoftの研究者らが提案した「LLMLingua」のようなプロンプト圧縮専用のフレームワークです。
LLMLinguaは、小さなモデル(Small LM)を使って、大きなモデル(Large LM)への入力プロンプトを圧縮します。単にトークンを削るだけでなく、「ターゲットとなる大きなモデルが正しく理解できるか」という観点で情報の取捨選択を行うのが特徴です。
この手法の利点は、圧縮率が高い(時には20倍以上)にもかかわらず、推論やRAG(検索拡張生成)などのタスクにおいて精度低下が極めて少ない点です。APIの間にこの「圧縮レイヤー」を挟むことで、高性能モデルへの入力コストを劇的に下げることが期待できます。
ベクトルデータベースによる動的コンテキスト注入(RAG)
これは厳密には圧縮ではありませんが、コンテキストウィンドウを節約する王道の手法です。エージェントの過去の全履歴をプロンプトに入れるのではなく、全てVector DBに保存しておき、現在のタスクに関連するログだけを検索してプロンプトに注入します。
長期的に稼働するエージェントの場合、この「外部記憶」のアプローチは必須です。さらに、現在では単なる類似度検索にとどまらず、以下のような進化型RAG(Advanced RAG)のアプローチも検討すべきでしょう。
- ハイブリッド検索: キーワード検索とベクトル検索を組み合わせ、精度の高い情報を抽出する。
- GraphRAG: ナレッジグラフを用いて情報の関連性を構造化し、より深い文脈を理解させる。
- マルチモーダル対応: テキストだけでなく画像の埋め込み検索にも対応し、多様な情報をコンテキストとして扱う。
ただし、直近の文脈(Recency)が失われるリスクがあるため、「時間的減衰」を考慮したスコアリングや、直近N件のログは必ず含めるといったハイブリッドな設計が求められます。
参考リンク
圧縮パイプラインの設計と組み込み
これらの技術を、実際にどうシステムに組み込むか。ここではアーキテクチャ設計の話をします。
エージェントループへのミドルウェアとしての実装
プロンプト圧縮は、エージェントのメインロジックの中にベタ書きするのではなく、入出力を加工する「ミドルウェア」として実装すべきです。
LangChainなどを使っている場合、LLMへのリクエストを送る直前にフックする形で圧縮ロジックを挿入します。これにより、エージェントの思考ロジック(プロンプトの内容そのもの)を変更することなく、裏側でデータ量を最適化できます。
圧縮率とタスク難易度の動的調整
常に最大強度で圧縮するのが正解とは限りません。複雑な推論が必要なタスクでは、冗長な情報がヒントになることもあるからです。
実務において推奨されるのは、タスクの難易度や現在のトークン消費量に応じて圧縮率を動的に変える設計です。例えば、コンテキストウィンドウの使用率が50%以下のときは軽いクレンジングのみ行い、80%を超えたらLLMLinguaによる強力な圧縮を発動させる、といった具合です。ユーザーの発話パターンやタスクの特性を分析し、適切な対話フローと圧縮率を組み合わせることが重要です。
キャッシュ戦略によるAPIコール削減
圧縮処理自体にも計算コスト(時間やGPUリソース)がかかります。毎回ゼロから圧縮するのではなく、過去の履歴部分ですでに圧縮済みのものはキャッシュしておき、新たに追加されたログだけを処理して結合する仕組みを作ると効率的です。
特に、KVキャッシュ(Key-Value Cache)の概念を応用し、プロンプトの不変部分(システムプロンプトや数ターン前の履歴)を再計算しないようにすることで、レイテンシを最小限に抑えられます。
品質管理:圧縮による「健忘症」を防ぐ評価指標
プロンプト圧縮にはリスクがあります。それは、重要な指示や制約条件が欠落してしまう「健忘症」です。これを防ぐための品質管理(QA)プロセスは欠かせません。
情報の損失率とタスク成功率の相関
圧縮アルゴリズムを導入する際は、必ずA/Bテストを実施して効果を検証してください。圧縮なし(ベースライン)と、圧縮ありのパターンで、同じタスクセットを実行させ、ユーザーテストと改善のサイクルを回すことが不可欠です。
見るべき指標は以下の通りです。
- トークン削減率: どれだけコストが下がったか。
- タスク成功率: 圧縮によってエージェントがタスクを完了できなくならなかったか。
- 指示遵守率: 「JSONで出力せよ」などの制約が守られているか。
ハルシネーション(幻覚)の検知
圧縮しすぎると、LLMは足りない情報を勝手に補完して嘘をつく(ハルシネーション)ことがあります。特に、数値データや固有名詞が圧縮によって曖昧になっていないか注意が必要です。
これを自動検知するために、圧縮後のプロンプトを別のLLM(安価なモデルで可)に読ませ、「このプロンプトから元の指示の意図を復元できるか?」という逆変換テストを行うのも有効な手法です。
圧縮パイプラインのユニットテスト手法
開発フローの中に、プロンプト圧縮のユニットテストを組み込みましょう。「重要なキーワードリスト」を定義し、圧縮後のテキストにそれらが含まれているかをチェックする簡単なスクリプトを用意するだけでも、事故は大幅に防げます。
まとめ
自律型エージェントの開発は、賢さを追求するフェーズから、持続可能性を追求するフェーズへと移行しています。プロンプト圧縮は、単なるコスト削減策ではなく、エージェントを長期的に安定稼働させるための必須インフラです。
- 要約ではなく圧縮: LLMのための情報密度最適化を意識する。
- 段階的な処理: クレンジングから始め、必要に応じて高度な蒸留モデルを適用する。
- 品質の監視: コスト削減と引き換えに精度が落ちていないか、常にテストする。
これらを実装することで、トークンコストを半減させつつ、キビキビと動くエージェントを構築することが可能です。
しかし、独自の圧縮パイプラインを構築し、既存のエージェントシステムに統合するのは、高度なエンジニアリング知識と試行錯誤を要します。特に、業務特有のドメイン知識を損なわずに圧縮を行うには、汎用的なツールだけでは対応しきれないケースも多々あります。
もし、AIエージェントのランニングコストやレスポンス速度の改善に限界を感じている場合は、専門家に相談して現状のプロンプト構造を診断し、最適な圧縮アーキテクチャを検討することをおすすめします。適切な設計と継続的な改善サイクルを通じて、賢く効率的なエージェントを構築していきましょう。
コメント