はじめに
Gemini APIのコンテキストキャッシングを使えば、共通するプロンプトを一時的にクラウド上に保持しておくことができます。
本記事ではGemini APIのコンテキストキャッシングについて紹介し、実際にコンテキストキャッシングを利用してコードレビューする方法について説明します。
コンテキストキャッシングとは
事前に計算された入力トークンを保存し、再利用できるようにする仕組みです。主なメリットは次のとおりです。
- 大幅な費用削減: サポートされているすべての Gemini 2.5 以降のモデルで、キャッシュに保存されたトークンの料金は標準の入力トークン料金の 10% のみです。暗黙的なキャッシュ保存の場合、キャッシュ ヒットが発生すると、この費用削減が自動的に適用されます。明示的なキャッシュ保存では、この割引が保証されるため、費用削減が予測しやすくなります。
- レイテンシ: キャッシュを使用すると、再計算する代わりに、以前に計算されたコンテンツを検索するため、レイテンシが短縮されます。
(https://cloud.google.com/blog/ja/products/ai-machine-learning/vertex-ai-context-caching/ より抜粋)
料金体系
コンテキストキャッシングの料金は以下の要素で決まります(詳細はPricingを参照)。
| 項目 | 説明 |
|---|---|
| キャッシュ保存料 | キャッシュされたトークン数 × 保存時間(TTL)に応じた料金 |
| キャッシュ使用料 | 通常のトークン料金から最大90%割引(モデルによる) |
割引率:
- Gemini 2.5モデル: 90%割引
- Gemini 2.0モデル: 75%割引
最小トークン数の要件
キャッシュを作成するには、最小トークン数の要件を満たす必要があります。
| モデル | 最小トークン数 |
|---|---|
| Gemini 2.5 Flash | 1,024トークン |
| Gemini 2.5 Pro | 4,096トークン |
| Gemini 3 Pro Preview | 4,096トークン |
実装してみる
コンテキストキャッシングを使ったコードレビューを実装します。
環境構築
まず、必要なパッケージをインストールします。
pip install google-genai
APIキーを環境変数に設定します。
export GOOGLE_API_KEY="your-api-key"
コード規約の準備
今回は例としてGoogle Python Style Guideを使用します。
長いので、ここでは一部抜粋し、日本語訳したものを記載しています
。
STYLE_GUIDE_CONTENT = """
# Google Python Style Guide - コードレビュー基準
## 1. 命名規則(Section 3.16)
### 基本ルール
- モジュール/パッケージ: `lower_with_under`
- クラス: `CapWords`(例: `UserManager`, `HttpClient`)
- 関数/メソッド: `lower_with_under()`(例: `fetch_user_data`, `get_user`)
- 定数: `CAPS_WITH_UNDER`(例: `MAX_RETRY_COUNT`)
### 避けるべき名前
- 単一文字(例外:ループ変数`i`, `j`, `k`)
- camelCaseは使用禁止
## 2. Docstring(Section 3.8)
- 公開APIには必須
- Args, Returns, Raisesセクションを含める
## 3. インポート(Section 2.2, 3.13)
- グループ化順序:標準ライブラリ → サードパーティ → 内部パッケージ
- 関数内でのインポートは禁止
## 4. 例外処理(Section 2.4)
- キャッチオール(`except:`)禁止
- 必ず特定の例外を指定
## 5. デフォルト引数(Section 2.12)
- ミュータブルオブジェクト(`[]`, `{}`)をデフォルト値に使用禁止
## 6. セキュリティ
- SQLインジェクション防止:パラメータ化クエリを使用
"""
キャッシュの作成
コード規約をキャッシュに登録する関数を実装します。
-
system_instruction: レビュアーとしての振る舞いを定義 -
contents: キャッシュするコンテンツ(コード規約) -
ttl: キャッシュの有効期限(秒単位) -
display_name: 管理用の表示名
from google import genai
from google.genai import types
cache = client.caches.create(
model=model,
config=types.CreateCachedContentConfig(
system_instruction=(
"あなたはPythonコードレビューの専門家です。"
"提供されたGoogle Python Style Guideに基づいて、"
"コードをレビューし、具体的な改善点を指摘してください。"
),
contents=[
types.Content(
role="user",
parts=[types.Part(text=STYLE_GUIDE_CONTENT)],
)
],
display_name="google-python-style-guide",
ttl="3600s", # 1時間
),
)
print(f"キャッシュを作成しました: {cache.name}")
print(f"有効期限: {cache.expire_time}")
キャッシュを使用したレビュー
作成したキャッシュを参照してコードレビューを実行します。
prompt = f"""
以下のPythonコードをレビューしてください。
以下の形式で出力してください:
## 概要
## 重要な問題
## 改善提案
## 修正後のコード例
"""
response = client.models.generate_content(
model=model,
contents=prompt,
config=types.GenerateContentConfig(cached_content=cache_name),
)
print(response.text)
実行例
client = genai.Client(api_key=os.environ.get("GOOGLE_API_KEY"))
model = "models/gemini-2.0-flash-001"
# キャッシュを作成
cache_name = create_style_guide_cache(client, model)
# サンプルコードを読み込み
with open("sample_bad_code.py") as f:
sample_code = f.read()
# レビュー実行
result = review_code_with_cache(
client, model, cache_name, sample_code, "sample_bad_code.py"
)
print(result)
効果検証
Gemini APIのレスポンスにはusage_metadataが含まれており、トークン使用量を取得できます。これを使ってキャッシュあり/なしを実際に比較してみましょう。
比較用コード
import time
from google import genai
from google.genai import types
prompt = f"""
以下のPythonコードをレビューしてください。
"""
# --- キャッシュなしでレビュー ---
prompt_without_cache = style_guide + "\n\n---\n\n" + prompt
start_time = time.time()
response_no_cache = client.models.generate_content(
model=model,
contents=prompt_without_cache,
)
time_no_cache = time.time() - start_time
usage_no_cache = response_no_cache.usage_metadata
print("=== キャッシュなし ===")
print(f" 入力トークン数: {usage_no_cache.prompt_token_count}")
print(f" 出力トークン数: {usage_no_cache.candidates_token_count}")
print(f" 処理時間: {time_no_cache:.2f}秒")
# --- キャッシュを作成 ---
cache = client.caches.create(
model=model,
config=types.CreateCachedContentConfig(
system_instruction="Pythonコードレビューの専門家として回答してください。",
contents=[
types.Content(
role="user",
parts=[types.Part(text=style_guide)],
)
],
ttl="3600s",
),
)
# --- キャッシュありでレビュー ---
start_time = time.time()
response_with_cache = client.models.generate_content(
model=model,
contents=prompt,
config=types.GenerateContentConfig(cached_content=cache.name),
)
time_with_cache = time.time() - start_time
usage_with_cache = response_with_cache.usage_metadata
print("\n=== キャッシュあり ===")
print(f" 入力トークン数: {usage_with_cache.prompt_token_count}")
print(f" キャッシュ使用トークン数: {usage_with_cache.cached_content_token_count}")
print(f" 出力トークン数: {usage_with_cache.candidates_token_count}")
print(f" 処理時間: {time_with_cache:.2f}秒")
# --- 比較結果 ---
print("\n=== 比較結果 ===")
token_reduction = (
(usage_no_cache.prompt_token_count - usage_with_cache.prompt_token_count)
/ usage_no_cache.prompt_token_count
* 100
)
print(f" 入力トークン削減率: {token_reduction:.1f}%")
print(f" 処理時間短縮: {time_no_cache - time_with_cache:.2f}秒")
# クリーンアップ
client.caches.delete(name=cache.name)
実行結果
=== キャッシュなし ===
入力トークン数: 2847
出力トークン数: 892
処理時間: 8.34秒
=== キャッシュあり ===
入力トークン数: 156
キャッシュ使用トークン数: 2691
出力トークン数: 876
処理時間: 6.21秒
まとめ
Gemini APIのコンテキストキャッシングを活用することで、長いコード規約であってもコストを抑えながら生成AIに渡すことができます。
いいねやストックがモチベーションに繋がるので、ぜひお願いします!