◉GEMINI LABEN
●ARGON — gemini-4-argon が 10/13 に GA。複雑なコーディング・エージェント・数学・科学向けです●DEEP RES — deep-research-pro-preview-12-2025 は 10/23 に停止、残り6日。移行先は deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 が GA(10/06)。gemini-3.1-flash-image は非推奨で停止日は未発表です●MCP — ツール結果が 8.5万トークンに膨らんだ事例を、ADK で 310 トークンに包んで抑えた報告が出ています●FLASH — gemini-3.7-flash と 3.5-flash は新しい Flash モデルに自動で回されます(10/08)●NEW — クラッシュ報告を毎回ゼロから読ませない — 既知バグ早見表を先に grep し…●ARGON — gemini-4-argon が 10/13 に GA。複雑なコーディング・エージェント・数学・科学向けです●DEEP RES — deep-research-pro-preview-12-2025 は 10/23 に停止、残り6日。移行先は deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 が GA(10/06)。gemini-3.1-flash-image は非推奨で停止日は未発表です●MCP — ツール結果が 8.5万トークンに膨らんだ事例を、ADK で 310 トークンに包んで抑えた報告が出ています●FLASH — gemini-3.7-flash と 3.5-flash は新しい Flash モデルに自動で回されます(10/08)●NEW — クラッシュ報告を毎回ゼロから読ませない — 既知バグ早見表を先に grep し…
記事一覧/API / SDK
◈ API / SDK/2026-03-14中級

Gemini API のコストを送信前に見積もる — count_tokens 実践とトークン最適化

Gemini API の count_tokens でリクエスト前にトークン数とコストを見積もる方法をまとめました。テキストと画像のトークンの数え方、月額コストを概算する計算機の作り方、キャッシュやモデル選択で費用を下げる3つの実践、再試行を減らす工夫を扱います。

Gemini API248トークン6コスト管理17最適化

課金される前にトークンを数える

Gemini API の請求は、やり取りしたトークン数で決まります。やっかいなのは、プロンプトに長いコンテキストや画像を載せると、思っていたより一気にトークンが膨らむことです。私は壁紙アプリのレビューを Gemini で分類する小さな機能を運用していますが、最初に試作したときは、レビュー本文に商品説明やテンプレ文を丸ごと添付してしまい、1件あたりの入力トークンが想定の3倍に膨れていました。

ありがたいことに、Gemini には送信前にトークン数を測る count_tokens が用意されています。しかもこの呼び出し自体は無料です。実際に課金されるリクエストを投げる前に、入力がどれくらいのトークンを消費するのかを確かめられます。まずはこれを習慣にするだけで、コストの当たりは大きく外れなくなります。

from google import genai
 
client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
 
response = client.models.count_tokens(
    model="gemini-2.5-flash",
    contents="Gemini API でアプリのレビューを感情分類したいです。",
)
 
print(f"入力トークン数: {response.total_tokens}")
# 入力トークン数: 18

count_tokens が返すのは入力側のトークン数です。出力トークンは生成してみるまで確定しませんが、max_output_tokens で上限を決めておけば、出力側の最悪値も先に見積もれます。

トークンという単位の感覚をつかむ

トークンは言語モデルが処理する最小単位です。1トークンはおおよそ英語4文字に相当しますが、言語や記号で大きく変わります。日次の概算を素早く立てるときは、次の目安が役立ちます。

英語の散文 : 約 1 単語 = 1.3 トークン
日本語の文 : 約 1 文字 = 1 トークン
ソースコード : 約 1 行 = 10〜20 トークン
画像 : 解像度に応じて 数百〜2,000 トークン前後

この感覚があると、「このプロンプトはざっくり何トークンか」を暗算でき、count_tokens の結果が桁違いに出たときに「何かを余分に渡している」と気づけます。私の場合、レビュー分類で入力が膨らんだ原因は、毎回同じ分類ルール(数千文字)をユーザーメッセージ側に貼り付けていたことでした。これは後述するキャッシュで解決できます。

テキストと画像のトークンを数える

Gemini はテキストだけでなく画像や動画も扱えます。マルチモーダルのリクエストでは画像が入力トークンの大半を占めることも珍しくないので、テキスト単体のときより一段慎重に測っておきます。画像は types.Part.from_bytes でそのまま contents に混ぜられます。

import pathlib
from google import genai
from google.genai import types
 
client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
 
image_bytes = pathlib.Path("screenshot.png").read_bytes()
 
response = client.models.count_tokens(
    model="gemini-2.5-flash",
    contents=[
        types.Part.from_bytes(data=image_bytes, mime_type="image/png"),
        "このスクリーンショットの主要な要素を3つ挙げてください。",
    ],
)
 
print(f"テキスト+画像の入力トークン: {response.total_tokens}")

画像のトークンは解像度に依存します。同じ被写体でも高解像度のまま送ると数倍に増えるため、分類や要約のように細部が要らない用途では、送信前に長辺を 1,024px 程度へリサイズするだけで入力トークンを実測で半分以下に抑えられました。

月額コストを概算する計算機

トークン数が読めるようになったら、料金表と掛け合わせて月額を概算します。料金は改定されるので、最新値は必ず公式の料金ページで確認し、コードのなかは一箇所にまとめておくのが安全です。下記は 2026年6月時点のおおよその単価(100万トークンあたり・米ドル)を入れた例です。

class GeminiCostCalculator:
    """Gemini API のコストを概算する。単価は要・最新確認。"""
 
    # 100万トークンあたりの単価 (USD) — 2026年6月時点の目安
    PRICING = {
        "gemini-2.5-flash": {"input": 0.30, "output": 2.50},
        "gemini-2.5-pro":   {"input": 1.25, "output": 10.00},  # 200k超は input/output が上振れ
    }
 
    @classmethod
    def request_cost(cls, input_tokens, output_tokens, model="gemini-2.5-flash"):
        if model not in cls.PRICING:
            raise ValueError(f"未知のモデル: {model}")
        p = cls.PRICING[model]
        input_cost = input_tokens / 1_000_000 * p["input"]
        output_cost = output_tokens / 1_000_000 * p["output"]
        return round(input_cost + output_cost, 6)
 
    @classmethod
    def monthly_cost(cls, daily_requests, avg_in, avg_out, model="gemini-2.5-flash"):
        per_day = cls.request_cost(avg_in, avg_out, model) * daily_requests
        return round(per_day * 30, 2)
 
 
# 1日 1,000 件、平均 入力500 / 出力300 トークンを Flash で処理した場合
monthly = GeminiCostCalculator.monthly_cost(1000, 500, 300, "gemini-2.5-flash")
print(f"月額の概算: ${monthly}")

ここで効いてくるのがモデル選択です。同じ処理を Pro と Flash で見積もると、入力単価で 4倍前後、出力単価ではさらに開きます。レビュー分類のように判断が単純な処理は Flash で十分で、私はこの一本化だけで月のAPI費を体感で半分以下にできました。複雑な推論や長文生成だけ Pro に回す、という振り分けが現実的です。広告(AdMob)収益とサーバー費の差が手元に残る額を決める、という感覚で個人開発を続けてきました。だからこそ API 費のような変動コストは、できるだけ送信前に読み切っておきたいのです。

コストを下げる3つの実践

1. 繰り返すコンテキストはキャッシュに逃がす

同じ指示文や長い参照ドキュメントを毎回プロンプトに貼ると、その分だけ入力トークンを毎回払うことになります。Gemini のコンテキストキャッシュを使うと、再利用部分のトークンを割引価格で読めます。2.5 系では自動で効く暗黙キャッシュもありますが、確実に効かせたい固定文は明示的に登録するのが堅実です。

from google import genai
from google.genai import types
 
client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
 
cache = client.caches.create(
    model="gemini-2.5-flash",
    config=types.CreateCachedContentConfig(
        system_instruction="あなたはアプリレビューを5段階の感情で分類する担当者です。",
        contents=["(ここに長い分類ルールや判定例をまとめて入れる)"],
        ttl="3600s",
    ),
)
 
response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="星1:起動するたびに落ちます。最悪です。",
    config=types.GenerateContentConfig(cached_content=cache.name),
)
 
usage = response.usage_metadata
print(f"通常入力: {usage.prompt_token_count}")
print(f"キャッシュ読込: {usage.cached_content_token_count}")

私のレビュー分類では、数千文字の分類ルールをキャッシュへ移しただけで、リクエストごとの実入力トークンが目に見えて下がりました。

2. 渡すコンテキストを削る

会話履歴をそのまま積み続けると、何往復もするうちに入力トークンが雪だるま式に増えます。古い発言から落として上限内に収める、という単純な整理が効きます。

def prune_history(messages, max_tokens=4000):
    """新しい発言を優先して残し、トークン上限内に収める。"""
    kept, total = [], 0
    for msg in reversed(messages):
        approx = len(msg["content"]) // 2  # 日本語の粗い概算
        if total + approx > max_tokens:
            break
        kept.insert(0, msg)
        total += approx
    return kept

3. 出力トークンに上限をかける

入力に気を取られがちですが、単価が高いのは出力側です。max_output_tokens を用途に合わせて絞るだけで、暴走した長文生成による想定外の請求を防げます。

ただし、絞りすぎにも落とし穴がありました。思考機能を持つ 2.5 系では、内部の思考に使われたトークンも出力側に数えられます。分類の返答は短いからと上限を極端に小さくした私は、本文が空で返ってくる原因を半日ほど探すことになりました。上限が思考の分まで使い切られていた、と気づいたのは usage_metadata の中身を並べて見たあとでした。いまは本番に出す前に、実際の出力と思考のトークン数を測り、その最大値に余裕を足した値を上限にしています。

ストリーミングで無駄な再試行を減らす

長い応答を待っているとタイムアウトしやすく、再送するたびに入力トークンを払い直すことになります。ストリーミングなら生成途中から結果が届くため、体感速度が上がるだけでなく、重複リクエストによる無駄な課金も減らせます。最終チャンクには usage_metadata が載るので、実際の消費量もそのまま記録できます。

from google import genai
 
client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
 
stream = client.models.generate_content_stream(
    model="gemini-2.5-flash",
    contents="このレビュー群を要約して、改善要望を3点にまとめてください。",
)
 
usage = None
for chunk in stream:
    if chunk.text:
        print(chunk.text, end="", flush=True)
    if chunk.usage_metadata:
        usage = chunk.usage_metadata
 
if usage:
    print(f"\n入力 {usage.prompt_token_count} / 出力 {usage.candidates_token_count}")

なお count_tokens の呼び出し自体は無料なので、本番のリクエスト前に必ず一度通して、入力側の見積もりをログに残しておくと、後からコストの異常値を追いやすくなります。

見積もりと実績のずれを記録しておく

送信前の count_tokens は、あくまで入力側の予想です。請求の根拠になるのは、応答に付いてくる usage_metadata のほうです。両方を同じ行に残しておくと、自分の見積もりの癖が数日で見えてきます。

import json
import time
 
def call_with_ledger(client, model, contents, config=None, log_path="token_ledger.jsonl"):
    estimated = client.models.count_tokens(model=model, contents=contents).total_tokens
    res = client.models.generate_content(model=model, contents=contents, config=config)
    u = res.usage_metadata
    row = {
        "ts": int(time.time()),
        "model": model,
        "estimated_in": estimated,
        "billed_in": u.prompt_token_count,
        "cached_in": u.cached_content_token_count or 0,
        "thoughts": getattr(u, "thoughts_token_count", 0) or 0,
        "out": u.candidates_token_count,
    }
    with open(log_path, "a", encoding="utf-8") as f:
        f.write(json.dumps(row, ensure_ascii=False) + "\n")
    return res

ずれが大きいときは、システム指示やキャッシュなど、見積もりの時点で渡していないものがないかを疑います。思考のトークンは thoughts の列に分かれて残りますので、出力の上限を決める材料にもなります。毎回 count_tokens を挟むと往復が一つ増えますから、常時ではなく抜き取りで回すだけでも足ります。

見積もりは送る前に、実績は返ってきた直後に、同じ行へ残します。 費用の話は、この一行が揃ってから始めるようにしています。

次の一歩

まずは手元でいちばん回数の多い処理を一つ選び、count_tokens でその実入力トークンを測ってみてください。多くの場合、毎回貼り付けている固定文やオーバースペックな画像解像度が、削れる余地としてすぐ見つかります。さらにリアルタイム性を高めたいときは、ストリーミングとチャットの実装パターンや、画像・動画を扱うマルチモーダル API ガイドも合わせて読むと、コストと体験の両面で打ち手が増えます。

シェア

お読みいただきありがとうございます

Gemini Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

◈ API / SDK2026-09-08
値上げの日をまたぐ費用の見積もりを、はじめから二段で書く
Gemini Flash の導入価格は2026年12月31日で終わり、2027年1月1日から標準価格に切り替わります。世代を据え置いても避けられないこの日を、はじめての費用見積もりでどう扱うか。動くコードとともに書き残します。
◈ API / SDK2026-10-14
config に「Extra inputs are not permitted」が出たら、キーの綴りを一つずつ疑います
google-genai SDK で config を渡した途端に pydantic の ValidationError(extra_forbidden)が出る原因は、ほぼ綴りの一字違いです。手元で再現した出力と、呼び出し前に怪しいキーを洗う関数、text が None になる場合の見分け方を書き残します。
◈ API / SDK2026-10-08
停止日のない非推奨をどう扱うか — 画像モデルの移行先を、3つの条件で選び直す
10月6日に gemini-nano-banana-2.1 が GA になり、gemini-3.1-flash-image は停止日の書かれないまま非推奨になりました。解像度・参照画像・検索の3条件で移行先を選ぶ表と、確認用の短いスクリプトをまとめます。