[ADK] 1.15.0で追加された Context Cachingと Static Instruction
こんにちは、サントリーこと大橋です。
本日(2025/09/26)、Agent Development Kit(以降ADK) 1.15.0と1.15.1がリリースされました。
※ 1.15.1はbugfixリリースです。
今回のリリースで追加された主な機能は以下です。
1.15.0 (2025-09-24)
機能 (Features)
- [Core]
-
[Context Caching]
- コンテキストキャッシュをサポート (c66245a)
- 明示的なコンテキストキャッシュの自動作成とライフサイクル管理をサポート。
使用法:App(root_agent=..., plugins=..., context_cache_config=...)
- 明示的なコンテキストキャッシュの自動作成とライフサイクル管理をサポート。
- 静的インストラクションで非テキストコンテンツをサポート (61213ce)
- 静的インストラクションをサポート (9be9cc2)
- 変更されない静的インストラクションをインストラクションの先頭に配置することをサポート。
静的インストラクションはコンテンツとしてinline_dataとfile_dataをサポート。
動的インストラクションはLlmRequestの末尾に移動し、プレフィックスキャッシュのマッチングサイズを増加。
使用法:LlmAgent(model=..., static_instruction=types.Content(parts=...), ...)
- 変更されない静的インストラクションをインストラクションの先頭に配置することをサポート。
- コンテキストキャッシュをサポート (c66245a)
- [Telemetry]
-
[Services]
- セッションからメモリを生成するエンドポイントを追加 (2595824)
- [Tools]
- [Evals]
-
[Samples]
- BigQueryサンプルエージェントをADCですぐに実行できるように修正 (10cf377)
バグ修正 (Bug Fixes)
- eval実行後にrunnerを閉じるように修正 (86ee6e3)
- エージェントの出力をstateに保存する際にthought partを除外 (632bf8b)
- LiteLlmストリーミング応答の空のfunction chunkを無視 (8a92fd1)
-
McpTool
にraw_mcp_tool
メソッドを導入し、基盤となるMCPツールへの直接アクセスを提供 (6158075) -
columns
を直接変更する代わりにコピーを作成するように修正 (aef1ee9) - LLM応答でのラテン文字のエスケープを防止 (c9ea80a)
- remote_a2a_agent.pyでClientFactoryを再作成する際にconsumersとtransport registryを保持するように修正 (6bd33e1)
- fastapi 0.117.1でサポートされていない'type': 'unknown'をtest_common.pyから削除 (3745221)
ドキュメント (Documentation)
-
after_agent_callback
のドキュメントを修正 (b9735b2)
他にも多くの機能追加、バグフィックス、改善が行われています。
今回はこの中で、パフォーマンスとコスト効率を大きく改善する可能性を秘めた「Context Caching」と「Static Instruction」について深掘りしていきたいと思います。
課題: 毎回同じ長文コンテキストを送るのは非効率
AIエージェント、特に大量の背景情報やドキュメントを読み込んでタスクを実行するタイプのエージェントを開発していると、ある課題に直面します。それは、「LLMを呼び出すたびに、同じ長大なコンテキストを毎回プロンプトに含めなければならない」という問題です。
例えば、以下のようなケースです。
- RAGエージェント: ユーザーの質問に関連する広範な社内ドキュメントを検索し、その内容をコンテキストとしてLLMに渡す。
- Few-shotプロンプト: 高度なタスクをこなすために、多くの具体例をプロンプトに含める。
- 複雑なシステム指示: エージェントの役割、制約、出力形式などを詳細に記述した長文のシステムインストラクションを与える。
これらのコンテキストは、会話のターンごとにはほとんど変化しません。しかし、従来のLLMのAPI呼び出しでは、変化するユーザーの質問と一緒に、この不変の長文コンテキストも毎回送信する必要がありました。
従来のADKでは、LlmAgentのinstruction
が長くなるほど、ユーザーのメッセージ内容にかかわらず、1ターンあたりのデータ量(トークン数)が増加し、コンテキストウィンドウを消費してしまっていました。
これは、主に2つの大きな課題を生み出します。
- レイテンシの増加: 送信するデータ量(トークン数)が多いほど、APIの応答にかかる時間が長くなります。
- コストの増大: 多くのLLMサービスは、入力トークン数に基づいて課金されます。毎回同じコンテキストを送信することは、無駄なコストを発生させる原因となります。
この課題を解決するため、Gemini APIなどのLLMでは、一度処理したコンテキストを保持しておく「コンテキストキャッシュ」という仕組みが備わっています。ADK 1.15.0では、この機能を活用するための仕組みが導入されました。
ADK 1.15.0におけるContext CachingとStatic Instruction
今回のアップデートの核心は、Static Instruction
とContext Caching
という2つの新機能を組み合わせることで、上記課題を解決する点にあります。
Static Instruction
Static Instruction
は、LlmAgent
に追加された新しいパラメータです。その名の通り、会話のターン間で「変化しない静的な指示」を定義するために使います。
これまでinstruction
パラメータでは{}
プレースホルダーを利用することで動的にシステム指示を作成することができました。(例: {state.some_value}
)
この機能により、instruction
では動的な部分と静的な部分を混在させていましたが、static_instruction
を使うことで、これらを明確に分離できます。
-
static_instruction
: 長大なドキュメント、Few-shotの例、基本的な役割設定など、不変のコンテキストをここに記述します。 -
instruction
: セッションの状態など、ターンごとに変化する動的なコンテキストをここに記述します。
リリースノートにあるように、ADKの内部では、静的な指示がプロンプトの先頭に、動的な指示が末尾に配置されるように再構成されます。これにより、LLMのキャッシュがヒットしやすくなるのです。
Context Caching
Context Caching
は、App
クラスで設定できる新しい機能です。static_instruction
で定義された不変のコンテキストを、LLM側でキャッシュするように設定します。
一度キャッシュが作成されると、2回目以降のAPI呼び出しでは、ADKはキャッシュのIDと動的なコンテキスト(新しいユーザーの質問など)だけを送信します。LLMはキャッシュされた内容を再利用し、新しい部分だけを処理するため、応答が高速化され、入力トークン数も大幅に削減されます。
これにより、開発者はLLMのキャッシュ機能を意識することなく、ADKの作法に則って実装するだけで、エージェントのパフォーマンスとコスト効率を自然に向上させられるようになりました。
使用例
それでは、実際のコードで使い方を見ていきましょう。
LlmAgent
でstatic_instruction
を定義し、それをApp
のcontext_cache_config
で有効化するのが基本的な流れです。
from google.adk.agents import Agent
from google.adk.apps import App, ContextCacheConfig
from google.genai import types
import datetime
# 1. 静的なコンテキストを定義
# ここでは例として、長文のドキュメントを想定
long_document = "これは非常に長いドキュメントで、エージェントが常に参照する必要があります..." * 100
static_parts = [types.Part(text=long_document)]
# 2. LlmAgentで static_instruction を設定
dynamic_instruction = f"""
セッション開始時刻: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
あなたは....
"""
document_based_agent = Agent(
model='gemini-2.5-flash',
name='document_agent',
# instructionには動的な部分のみを残す(もしくは空にする)
instruction=dynamic_instruction,
# 新しいパラメータに静的コンテキストを渡す
static_instruction=types.Content(parts=static_parts),
)
# 3. AppでContext Cachingを有効化
app = App(
name='cached_agent_app',
root_agent=document_based_agent,
context_cache_config=ContextCacheConfig(
min_tokens=4096,
ttl_seconds=600, # 10 mins for research sessions
cache_intervals=3, # Maximum invocations before cache refresh
)
)
# あとは、このappインスタンスをRunnerに渡して実行するだけです。
# runner = InMemoryRunner(app=app)
# runner.run(...)
なおキャッシュのパフォーマンスはgoogle.adk.utils.cache_performance_analyzer.py
のCachePerformanceAnalyzer
を利用して分析できます。
具体的な利用方法や、キャッシュの効き具合はADKのsampleに計測用のAgentがありますので、動かしてみると良いと思います。
※実行結果を貼りたかったのですが、内容が大きくなりすぎたのとキャッシュ効いたねってぐらいの結果だったので割愛します。
まとめ
今回はADK 1.15.0で追加されたContext Caching
とStatic Instruction
について解説しました。
この2つの機能を組み合わせることで、開発者はLLMのキャッシュメカニズムを最大限に活用し、エージェントの応答速度とコスト効率を劇的に改善できます。特に、大量の固定情報を参照する必要があるエージェントを構築する際には、必須の機能となるでしょう。
これまでパフォーマンスやコストの観点からためらっていたような、長文コンテキストを必要とする複雑なエージェントの開発が、より現実的になったと言えます。
お知らせ/宣伝
先日、ADKユーザー向けのイベント「ADK UG #0」が開催され、ADK開発者が集う日本語のDiscordコミュニティが誕生しました。ADKに関する情報交換や議論に興味がある方は、ぜひご参加ください!
また、ADKの最新のコミットログやリリースノートを分かりやすく解説するPodcastを、月・水・金に配信しています。ADKの動向を追いかけたい方は、ぜひ聴いてみてください。
Discussion