Google Cloud のプロジェクトに Gemini API のキーを複数発行して、部署やベンダーごとに配っている環境は珍しくない。
そういう運用をしていると、遅かれ早かれ「どのキーがいくら使ったのか」を聞かれる。
結論から書くと、課金データからキー別の金額を出すことはできない。
ただしキー別の利用実績は取得でき、それを使った按分なら実用に足る精度で成立する。
この記事では、その境目を実測でどこまで詰められたかを書く。
目次
- 課金データにキーの識別子はあるか
- サービスアカウントを挟むという発想
- 検証は比率を仕込んで作る
- Cloud Monitoring の credential_id
- 取れるのは回数とデータ量だけ
- 按分は成立するか
- キー ID とキー名をどう対応づけるか
- まとめ
課金データにキーの識別子はあるか
まず確認したのは、BigQuery への詳細(リソースレベル)課金エクスポートである。
このエクスポートには system_labels という項目があり、リソースに自動で付くラベルがここに入る。
生成 AI に「サービスアカウント単位で集計できる」と言われた人が最初に見に行くのもここだろう。
見に行く前に、自分が見ているテーブルが詳細エクスポートのものかを確認しておきたい。
標準エクスポートには system_labels も resource も存在しないので、標準のテーブルを見て「ラベルが無い」と判断してしまうと、単に見る場所を間違えただけということになる。
| エクスポート種別 | テーブル名 |
|---|---|
| 標準(Standard usage cost) | gcp_billing_export_v1_ |
| 詳細(Detailed usage cost) | gcp_billing_export_resource_v1_ |
| 料金(Pricing) | cloud_pricing_export |
テーブル名に resource_v1 が入っていれば詳細エクスポートである。
system_labels や resource.name を参照したクエリがエラーにならずに通ったことでも確認できる。
結論として、Gemini API の課金行にはキーもサービスアカウントも現れない。
ラベル系の 4 項目をすべて確認したが、いずれも空だった。
| 項目 | 実測 |
|---|---|
system_labels |
全行 null |
labels(user_labels) |
goog-generativelanguage-model = モデル名のみ |
tags |
全行 null |
resource.name / resource.global_name |
全行 null |

図 1: 詳細課金エクスポートの照会結果。service_account 列は 2 行とも null になる
注目すべきは最後の行である。
リソースレベルのエクスポートを使っているのに、リソースを指す識別子そのものが入っていない。
Gemini API の呼び出しはプロジェクトに対して課金されるだけで、紐づく課金対象リソースが存在しないからだ。
この構造が分かると、「キーやサービスアカウントにラベルを付ければいいのでは」という発想も同時に否定できる。
ラベルが課金行に乗るのは、それが課金対象リソースか、その上位階層(プロジェクト、フォルダ、組織)に付いている場合に限られる。
API キーもサービスアカウントも認証の主体であって課金対象リソースではないので、ラベルを付けても乗せる先の行がない。
サービスアカウントを挟むという発想
Gemini API のキーは、2026 年に入ってから作成時にサービスアカウントへのバインドが必要になった。
コンソールのキー編集画面にも、Agent Platform(Vertex)と Gemini API を使うキーはサービスアカウントにバインドしなければならないと明記されている。
そこで「キー単位が無理でもサービスアカウント単位なら分離できるのではないか」という話が出てくる。
これは二重に成立しない。
一つは前節のとおりで、課金行にサービスアカウントの識別子が入らない。
compute.googleapis.com/service_account というラベルキーは存在するが、これは GCE の VM がどのサービスアカウントで動いているかを示すもので、VM を伴わない API 呼び出しには付きようがない。
もう一つは運用側の理由である。
同一プロジェクト内であれば、一つのサービスアカウントに複数のキーをバインドできる。
サービスアカウントとキーは 1 対 N なので、仮にサービスアカウント単位で金額が割れたとしても、その中に複数キーが同居していればキー別の内訳は得られない。
つまりこの方式は、成立したとしても目的に届かない。
検証は比率を仕込んで作る
ここからが実測である。
同一プロジェクト内に API キーを 2 本作り、それぞれ別のサービスアカウントにバインドして、gemini-3.6-flash を呼んだ。
このとき、呼び出し回数に 30 回と 10 回の差をつけた。
比率を仕込むのは、後で何らかの分割が観測されたときに、それが狙った軸によるものかを判定するためである。
分割が起きただけでは、キーで割れたのか別の理由で割れたのか区別できない。
実際、この仕込みが効いた。
40 回分は Gemini API として 4 行に計上され、入力トークンと出力トークンの 2 種類がそれぞれ 2 行に割れていた。
一見するとキーで割れたように見える。
しかし行を並べて全列を比較すると、ペア内で違う列は export_time だけだった。
課金エクスポートが 2 回のバッチに分けて書き込んだ結果である。
決め手になったのは入力トークン数だった。
40 回の入力トークン合計は 280 で、1 回あたりちょうど 7 になる。
同じプロンプトを投げていたので当然だが、この定数性のおかげで行を呼び出し回数へ換算できる。
換算すると 175 対 105、すなわち 25 回対 15 回だった。
仕込んだ 30 対 10 とは一致しない。
この分割はキー由来ではないと算術で断定できた。
なお費用は 40 回で 0.120958 USD 発生している。
金額がゼロに丸められていて判定できない、という状態ではない。
課金レコードは確かに生成されており、そのうえでキーの軸が存在しないという結果である。
Cloud Monitoring の credential_id
課金データが駄目なら、API 側の指標はどうか。
Cloud Monitoring の監視リソース consumed_api には credential_id というラベルがある。
公式ドキュメントの定義は「The client credential ID, such as an API key ID or the OAuth client ID」で、API キー ID がそのまま入ると読める。
これを PromQL で引いた。
Metrics Explorer のツールバーから PromQL を選び、次のクエリを実行する。
# promql
sum by (credential_id) (
increase(
serviceruntime_googleapis_com:api_request_count{
monitored_resource="consumed_api",
project_id="PROJECT_ID",
service="generativelanguage.googleapis.com"
}[1h]
)
)
結果は 2 系列に分かれ、値は 30 と 10 だった。
increase は窓の端点で外挿するため多少ずれることを覚悟していたが、整数でそのまま出た。
同一プロジェクト内の 2 本のキーが、キー単位で完全に分離できている。

図 2: キー別の呼び出し回数。仕込んだ 30 対 10 が外挿誤差なく分離される
書き方で二点補足しておく。
Cloud Monitoring の PromQL では、メトリクス名はドットをアンダースコアに、最初のスラッシュをコロンに置き換える。
serviceruntime.googleapis.com/api/request_count が serviceruntime_googleapis_com:api_request_count になるのはこの規則による。
もう一点は monitored_resource の指定で、これは省略できない。
api/request_count は api、consumed_api、produced_api の 3 種類の監視リソースに紐づいており、指定しないと複数のリソース型に紐づいている旨のエラーになる。
取れるのは回数とデータ量だけ
キー別に割れたと言っても、取れたのは呼び出し回数である。
Gemini の課金はトークン量に対して発生するので、回数がそのまま金額になるわけではない。
キー別にトークン数を取れないかとメトリクスの一覧を当たったが、ここで頭打ちになる。
| メトリクス | 監視リソース | credential_id |
値 |
|---|---|---|---|
serviceruntime.googleapis.com/api/request_count |
consumed_api |
あり | 呼び出し回数 |
serviceruntime.googleapis.com/api/response_sizes |
consumed_api |
あり | レスポンスのバイト数 |
serviceruntime.googleapis.com/api/request_sizes |
consumed_api |
あり | リクエストのバイト数 |
generativelanguage.googleapis.com/generate_content_usage_output_token_count |
.../Location |
なし | 出力トークン数 |
Gemini 固有のトークン系メトリクスは監視リソースが違い、credential_id を持たない。
ラベルはモデル名と出力モダリティと思考の有無だけである。
入力トークン数のメトリクスに至っては提供されていない。
メトリクス一覧を全ページ検索しても credential_id が出てくるのは serviceruntime の節だけだった。
キー別に割れるのは汎用の API メトリクスに限られる、というのがこの API の構造である。
按分は成立するか
金額そのものが取れないなら、按分でどこまで近づけるかという話になる。
手がかりは費用の構成比にあった。
40 回の内訳は出力トークンが 0.120539 USD、入力トークンが 0.000419 USD で、出力トークンが総額の 99.65% を占める。
出力トークン量はレスポンスのデータ量と相関するので、キー別のレスポンスバイト数が按分の分母になりうる。
先ほどのクエリのメトリクス名を api_response_sizes_sum に差し替えて引く。
ディストリビューション型のメトリクスは _count、_sum、_bucket を付けて Prometheus のヒストグラムのように扱えるので、合計バイト数は _sum で取れる。
| キー | 呼び出し回数 | レスポンス総バイト | 1 回あたり |
|---|---|---|---|
| キー A | 30 | 67,286 | 2,242.9 |
| キー B | 10 | 19,879 | 1,987.9 |

図 3: キー別のレスポンスバイト数。この比が按分の分母になる
ここで精度を確かめておきたい。
レスポンスには JSON の外枠という固定的なデータ量が含まれ、これは呼び出し回数に比例する。
外枠の分は、回数の多いキーへ過大に配賦される方向に効く。
全体では 87,165 バイトに対して出力トークンが 16,072 なので、1 トークンあたり 5.423 バイトになる。
純粋なトークン換算はおおむね 4 バイト前後なので、差分が外枠にあたる。
bytes = α×tokens + β×calls と置いて β を振り、キー A の配賦率がどう動くかを見た。
| 按分方法 | キー A の配賦率 |
|---|---|
| バイト数比をそのまま使う | 77.19% |
| β = 200 バイト/回で補正 | 77.42% |
| β = 400 バイト/回で補正 | 77.69% |
| β = 572 バイト/回で補正(α = 4.0 を仮定した上限) | 77.97% |
| (参考)呼び出し回数比 | 75.00% |
振れ幅は 0.78 ポイントに収まった。
費用配賦の用途としては十分だろう。
回数比による按分がバイト数比から 2.2 ポイントずれることも分かるので、按分するならバイト数を使うほうがよい。
ただしこの精度は利用形態に依存する。
今回の標本は 1 回あたりの出力量がキー間で 13% しか違わなかった。
多数の短い呼び出しをするキーと、少数の長い生成をするキーが混ざれば、外枠の偏りが拡大して誤差は大きくなる。
またこの検証は非ストリーミングの呼び出しで行っている。
ストリーミングでは通信の制御データが加わるため、バイト数とトークン数の換算率は取り直す必要がある。
キー ID とキー名をどう対応づけるか
運用に落とすときに最後に引っかかるのがここだった。
credential_id は apikey: に続けてキー ID が入る形式で、キー名は含まれない。
どのキーの実績なのかを判別するには対応表がいる。
ところがコンソールを探しても、キー ID はなかなか出てこない。
認証情報の一覧画面の列は「名前」「Bound account」「作成日」「制限」「操作」で、キー ID の列はない。
キーの詳細画面を開いても、本文には名前と作成日とバインドされたアカウントが並ぶだけである。
キー ID が現れるのはブラウザのアドレスバーだけだった。
https://console.cloud.google.com/apis/credentials/key/{KEY_ID}?project={PROJECT_ID}

図 4: キーの編集画面。キー ID はアドレスバーにしか現れない
この {KEY_ID} が credential_id の apikey: に続く値と一致する。
確認手順としては、認証情報からキー名をクリックして URL を見る、という手作業になる。
キーが数本なら問題ないが、増えてくると厳しい。
キーを発行する運用の中に対応表への追記を組み込んでおかないと、後から棚卸ししようとしたときにキー ID しか残っていない実績データと向き合うことになる。
用途の分からないキーが溜まっている環境ほど、この整備は先にやっておいたほうがいい。
まとめ
Gemini API の課金をキー単位で追えるかという問いに対する答えは、追う対象によって変わる。
金額そのものは追えない。
課金データにキーやサービスアカウントの識別子が存在せず、これは詳細エクスポートを使っても変わらない。
サービスアカウントを挟む方式も、識別子が出ない点と 1 対 N である点の両方で成立しない。
利用実績は追える。
Cloud Monitoring の credential_id でキー別の呼び出し回数とレスポンスバイト数が取得でき、同一プロジェクト内の複数キーも分離できる。
按分なら実用範囲に入る。
費用のほぼ全量が出力トークンなので、レスポンスバイト数比で配賦すれば、外枠の見積もり幅による揺れは 1 ポイント未満に収まった。
厳密な実額が必要なら、アプリケーション側で応答の usageMetadata を記録するか、キーごとにプロジェクトを分けるかの二択になる。
最後に検証の作り方について一つ。
今回は呼び出し回数に 30 対 10 の比率を仕込んでおいたことで、課金データ側に現れた 2 行の分割が目的の軸によるものではないと算術で切り分けられた。
分離できるかを確かめる検証では、観測された分割が何由来なのかを後から判定できる仕掛けを先に入れておくと、解釈で迷わずに済む。