ヒーリング音源アプリの素材を棚卸ししていた夜、手元に溜まった長い音声ファイルの中身を一覧にしたくなりました。聞き落としが出ると作り直しになりますので、迷わず resolution を high にして投げました。
返ってきた usage を見て、手が止まりました。low で試したときと、入力トークンがぴたりと同じだったのです。
設定の書き方を間違えたのだろうと、キーもモデルも変えて何度か往復しました。おかしかったのは私の設定ではなく、この値が何を決めているかについての私の思い込みのほうでした。
解像度は画質ではなく、渡す枠を決めています
media_resolution(Interactions API では入力ごとに付ける resolution)は、画像や動画フレーム 1 つあたりに最大で何トークン割り当てるかを決める設定です。写真を綺麗にする設定でも、モデルの賢さを上げる設定でもありません。
ここを取り違えていると、「品質を落としたくないから全部 high」という素朴な判断が、効き目のない入力にまで料金だけを積み上げます。
いま思えば、high という語感そのものに引きずられていたのかもしれません。上げれば丁寧に聞いてくれるはずだ、という期待を、パラメータの説明を読まないまま設定に乗せていたのだと気づいたのは、同じ数字を三度見返したあとでした。
解像度は画質の設定ではなく、モデルに渡す枠の設定です。 この一行を先に置いてから表を読むと、納得のいかなかった挙動がほどけました。
上げて効く入力と、上げても動かない入力
Media resolution のドキュメントに、Gemini 3 系の目安が入力の種類別に載っています。
| 設定 | 画像 | 動画(1フレーム) | 音声(1秒) | |
|---|---|---|---|---|
unspecified(既定) | 1120 | 70 | 25 | 560 |
low | 280 | 70 | 25 | 280 + 本文テキスト |
medium | 560 | 70 | 25 | 560 + 本文テキスト |
high | 1120 | 280 | 25 | 1120 + 本文テキスト |
ultra_high | 2240 | — | — | — |
横に並べると、私が踏んだ落とし穴がそのまま見えます。音声は 4 段階すべてで 1 秒あたり同じです。段階を上げても下げても、入力トークンは動きません。
動画も素直ではありません。low と medium はどちらも 1 フレーム 70 トークンで、文脈を節約するために同じ扱いにしてある旨が明記されています。medium を選ぶ行為は、動画に関しては low と同じ支払いで、同じ結果です。上げる意味が出るのは、フレームの中の細かい文字を読ませたいときの high だけです。
PDF は逆側の注意書きが付いています。文書の理解は medium で頭打ちになりやすく、high に上げても通常の書類では読み取りがよくなることは稀、とされています。
公式の数字が 1 か所に揃っていない場面があります
ここで一度、素直に困ったことも書き残します。同じ ai.google.dev の中で、音声と動画のトークン換算が 2 通り載っています。
上の表では音声が 1 秒 25 トークンですが、Interactions API 版のトークン解説では音声が 1 秒あたり 32 トークン、動画が 1 秒あたり 263 トークンと書かれています(いずれも 2026 年 9 月 19 日に確認しました)。後者は Beta 表記のページで、前者はフレーム単位、後者は秒単位という粒度の違いもあります。
どちらが間違いだと決めつけるより、自分の使うモデルで実際にどう数えられるかを見たほうが早い、というのが私の結論でした。見積もりをお客様に出す場面では、なおさらです。
数字は読むものではなく、自分のキーで数えるものです。
自分のキーで数え直す
段階を変えて同じファイルを投げ、usage.total_input_tokens を並べるだけで判定できます。出力を短く固定しておけば、確認の費用はほとんどかかりません。
import os
from google import genai
client = genai.Client(api_key=os.environ["YOUR_API_KEY_ENV"])
MODEL = "gemini-3.8-flash"
uploaded = client.files.upload(file="samples/room-tone-60s.wav")
def input_tokens(resolution: str) -> int | None:
"""同じ入力を段階だけ変えて投げ、入力トークン数を返します。"""
try:
interaction = client.interactions.create(
model=MODEL,
input=[
{"type": "text", "text": "Answer with one word."},
{
"type": "audio",
"uri": uploaded.uri,
"mime_type": uploaded.mime_type,
"resolution": resolution,
},
],
)
except Exception as err:
print(f"{resolution}: 失敗しました ({type(err).__name__}: {err})")
return None
return interaction.usage.total_input_tokens
counts = {level: input_tokens(level) for level in ("low", "medium", "high")}
for level, tokens in counts.items():
print(f"{level:>6}: {tokens}")
distinct = {t for t in counts.values() if t is not None}
print("段階が効いています" if len(distinct) > 1 else "段階は効いていません")3 行の数値が揃ってしまえば、その入力では段階を触る意味がありません。値が分かれたなら、どこまで下げると答えの質が崩れるかを次に測ります。比較の対象は必ず同じファイル、同じプロンプト、同じモデルに揃えてください。片方だけ条件が動くと、段階の効果と別の要因が混ざります。
なお count_tokens による事前見積もりと実際の課金トークンがずれる話は、count_tokens の推定と実課金がズレる5つの原因で切り分けを整理しています。ここで見ているのは応答に載る usage の実績値のほうです。
1 回のリクエストの中で段階を混ぜる
Gemini 3 系では、リクエスト全体ではなく入力 1 つずつに resolution を付けられます。細かい数字を読ませたい図と、状況を添えるだけの写真を、同じ呼び出しの中で別扱いにできるのです。
chart = client.files.upload(file="reports/sales-chart.png")
photo = client.files.upload(file="reports/site-photo.jpg")
interaction = client.interactions.create(
model="gemini-3.8-flash",
input=[
{"type": "text", "text": "図の数値と、写真に写っている状況を突き合わせてください。"},
# 小さな数字を読み落とすと作り直しになる1枚だけ high
{"type": "image", "uri": chart.uri,
"mime_type": chart.mime_type, "resolution": "high"},
# 文脈を添えるだけの1枚は low
{"type": "image", "uri": photo.uri,
"mime_type": photo.mime_type, "resolution": "low"},
],
)
print(interaction.usage.total_input_tokens)high と low の差は画像 1 枚あたり 4 倍です。1 枚だけ精度が要る構図で全部を high に揃えていると、その 4 倍が枚数分そのまま乗ります。この混在指定は Gemini 3 系だけの機能ですので、旧世代へ落とすコードでは無視される前提で書いておくと安全です。
画像については、もう一つ頭の片隅に置いている論点があります。画像理解のドキュメントには、両辺 384 ピクセル以下なら 258 トークン、それより大きければ 768×768 のタイルに分けて 1 枚ごとに 258 トークン、という換算も併記されています。つまり「寸法で決まる」規則と「段階の上限で決まる」規則が同じ場所に並んでいます。縮小してから渡す価値があるのかどうかは、同じ画像を数通りの寸法で投げて total_input_tokens を見比べれば、その場で答えが出ます。
いま私が決めている割り当て
個人開発で回している処理には、こう線を引いています。読み落とすと作り直しが発生する入力、つまり図表や文字の写り込んだ画像だけを high に上げます。状況を添えるだけの画像は low で置きます。PDF は medium から始めて、読み取りが崩れたときにだけ上げます。音声は段階を触らず、長さそのものを削ります。
出力側の削り方は別の軸です。推論に使うトークンを抑える話は、thinking_budget を制御してコストを守るのほうが具体的です。入力と出力を別々に押さえておくと、請求が跳ねたときに原因を早く切り分けられます。
まずは、いちばん枚数の多い入力を 1 種類だけ選んで、low と high の total_input_tokens を並べてみてください。自分の数字が 1 行出るだけで、表の読み方が変わります。ここまでお読みいただき、ありがとうございました。