こんにちは、DX開発事業部の松本です。

早速ですが皆さん、「エージェント開発」やっていますか?
昨年のエンジニア流行語と言っても過言ではない「エージェント開発」。その中でよく聞く「Google Agent Development Kit(ADK)」を皆さんも触られたでしょうか?
私もADKを使用して開発をいくつか行ってきました。
その中で共通してぶち当たった壁があったので、今回勉強も兼ねて記事にしました。
また、Pythonを使用することを前提としているのでご了承ください🙇‍♂️

共通して出た課題

先ほども話に出ました「共通して出た課題」ですが、まずはこちらについてお話しします。
ADKを使用して開発を進めるにあたって何度もこの課題にぶつかりました。(現在進行形でぶつかっています)
開発するシステムやエージェントは様々ですが、どの開発でも確実に!例外なく!絶対に!ぶつかっております。その課題が何かと言いますと「コンテキストウィンドウの圧迫問題」です。
ADKを使用するということは、もちろん行うのは「エージェント開発」です。そしてそのエージェントを開発する際に無くてはならないものは「LLM」ですね。そしてそのLLMに関わる部分で毎回ぶつかっています…🫠

コンテキストウィンドウとは?

そもそもコンテキストウィンドウとは一体何?となっている方もいらっしゃるかもしれないので、振り返りも兼ねて「コンテキスト」と「コンテキストウィンドウ」についてまとめました。

コンテキスト

コンテキストとは、AIエージェントがタスクを実行するために必要な「背景情報」のことです。具体的には下記のようなものが含まれます。

・会話履歴:これまでのユーザーとエージェントのやり取り
・セッション状態:ユーザーの設定や過去の情報
・エージェント情報:現在実行中のエージェントの詳細
・サービス参照:アーティファクト、メモリ、認証などの機能へのアクセス

といった感じで、人間が会話する時の「これまでのやり取り」や「状況」のようなイメージです。

コンテキストウィンドウ

コンテキストウィンドウは、LLMが一度に処理できる情報の「容量制限」のことです。本棚に置ける本の数のようなイメージです。もしこの容量を超えてしまうと

・古い情報が切り捨てられる
・エラーが発生する
・パフォーマンスが低下する

というような感じで、LLMの精度だけでなくシステム全体に影響を与えてしまいます。
このことからAIエージェントのタスクを実行する時には、コンテキストウィンドウに収まるようにプロンプトや処理を書き込んでいく必要があります。

そして今回の「コンテキストウィンドウの圧迫」とは、この「容量」に情報が収まりきっていない状態のことです。

コンテキストウィンドウの圧迫問題の解消

上記でコンテキストウィンドウとは何かがわかりましたね。
そして毎回私はこの「コンテキストウィンドウの圧迫」に苦しめられています…
プロンプトが長くなってしまったり処理を細かくしたりなど様々な要因で、このコンテキストウィンドウの容量をオーバーしてしまいます。

しかし、そこはADK。この問題を解消するための機能が備わっています!!
今回はそのうちの2つほどをご紹介します!

1つ目:コンテキストキャッシング

1つ目はver1.15.0で登場した「コンテキストキャッシング」機能です。
どのような機能かというと、LLMへのリクエストで繰り返し使用される静的なコンテンツ(プロンプトやツールの定義など)をキャッシングし、2回目以降の読み込み量やトークン数を抑え、パフォーマンスを向上させる機能です。
また実装方法としてもかなり簡単なので、私も普段よく使用しています。

アプリケーションレベルでの設定

app = App( 
    name="cached_app",
    root_agent=agent, 
    context_cache_config=ContextCacheConfig( 
        min_tokens=4096, 
        ttl_seconds=600, 
        cache_intervals=3 
    )
)

エージェントレベルでの最適化

agent = LlmAgent( 
    name="optimized_agent", 
    static_instruction="You are a helpful assistant.", # 静的指示 
    instruction="Current task: {task}" # 動的指示 
)

このようにシンプルな記載でかなりのトークン数を抑えることができます。
場合によっては、元々の半分以上のトークンを抑えることができるので、その後の処理がかなりスムーズになります!
しかし気をつけるべきところとして、「static_instruction」の設定だけではなく、「context_cache_config」で明示的な設定を行う必要があるので、気をつけてください。

2つ目:コンテキスト圧縮

2つ目はver1.16.0で登場した「コンテキスト圧縮」機能です。
これは、会話履歴が長くなり過ぎてしまった場合に、古いイベントを要約してコンテキストウィンドウの制限内に収めるための機能です!
先ほどの「コンテキストキャッシング」とは異なり、その名前の通り圧縮処理を行なってくれます。

設定方法

「RunConfig」で「context_window_compression」を設定します。

run_config = RunConfig( 
    context_window_compression=types.ContextWindowCompressionConfig( 
        trigger_tokens=1000, 
        sliding_window=types.SlidingWindow(target_tokens=500), 
    ) 
)

適用箇所

この設定はLLMリクエストに渡されます。

llm_request.live_connect_config.context_window_compression = ( 
    invocation_context.run_config.context_window_compression 
)

こちらも比較的簡単に実装ができ、大きな効力を得ることができます。
履歴が長くなってしまうような対話型のセッション(主に長期的な)には、とても効果的な機能です。

まとめ

以上2つが、今回私がご紹介したかったコンテキストウィンドウの圧迫を解決する機能でした!
いかがでしたでしょうか?
もちろんこれ以外にもコンテキストウィンドウの圧迫のための対策機能や実装方法などはございますが、今回は私が実際に使用してみて、特にトークン数を抑えることができたものをご紹介しました。

とはいえ、この機能を使用してもトークン数がオーバーしてコンテキストウィンドウの圧迫問題を引き起こしてしまうので、より効率の良い処理・簡潔で的確なプロンプトの実装が求められてきます。
なのでこれからもいろいろと試行錯誤し、よりこの機能を活かせるように、より良いコードが書けるよう頑張っていきたい所存です!

今回は以上となります。
ここまで読んでくださって、ありがとうございました!
では皆さん、良いエージェント開発を!!