2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GeminiのコンテキストキャッシングでAIレビューのコストを下げる

Last updated at Posted at 2025-12-22

はじめに

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に渡すことができます。

いいねやストックがモチベーションに繋がるので、ぜひお願いします!

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?