
【新機能】Gemini API や Vertex AI で利用費の上限を設定できる機能が公開されました
はじめに
こんにちは、すらぼです。
7/28 にGoogle Cloud 上の AI サービスや Cloud Run に対して、月ごとの利用費にキャップを設けられる「利用額上限」機能が追加されました!
クラウド上で AI サービスを活用する方も増える中で、意図しない利用費が発生してしまう経験がある方は少なくないと思います。僕自身も待ち望んでいた機能なので、実際に触ってみました。
今回は特に利用シーンの多い Gemini API で検証してみようと思います。
利用費の上限機能とは
利用費の上限機能は、特定のサービスに対して月ごとの上限額を設定し、上限を超過した場合にサービスを一時的に停止する機能です。
執筆時点での対象サービスは以下の4つです。
- Cloud Run
- Cloud Run Functions
- Gemini API
- Vertex AI (Gemini Enterprise Agent Platform)
この中でも特に利用費が読みにくい Gemini API, Vertex AI (Gemini Enterprise Agent Platform)に対して上限を設けることで、想定外の利用が発生した場合でも影響を抑えることができるのが嬉しいポイントですね。
なお、以下の制限がある点には注意してください。
- 利用費のカウントは「月ごと」のみ(日ごと、四半期ごとのキャップ設定は不可)
- トリガーから停止までにタイムラグがあり、設定した上限額を超える可能性がある
設定方法
では、設定方法を確認してきます。
まず請求先アカウント画面の「予算とアラート」から「Create budget」を作成します。

「利用額上限の適用」を選択します。画面の右側には、対象サービスの利用費の推移が表示されています。

次に、キャップを設けるプロジェクトとサービスを選択します。
対象とするプロジェクトとサービスは、現時点では「1つのプロジェクト」「1つのサービス」しか選択ができないようです。(執筆時点では「全て」を選択するとエラーになり次に進めませんでした。)


今回は「検証用プロジェクト」と「Gemini API」を選択して「次へ」をクリックします

最後に金額を設定します。今回は検証目的なので、小さい金額で試してみます。

こちらで、設定が完了しました。

金額設定の注意点
なお、上限金額は2つの注意書きを踏まえた金額設定が必要です。
この上限に達すると、指定されたサービスは一時停止します。適用は即時ではないため、上限はハードリミットより少し低く設定してください。超過分は請求されます。
注: 予測は実際の費用を使用して計算されます。ただし、迅速なレポート生成のため、利用額上限は推定費用の総額によってトリガーされます。
整理すると、以下のようになります。
- 迅速化のために推定費用の超過でトリガーされる(実際に超える前にトリガーされる可能性がある)
- それでもトリガー → 停止 までは即時ではない(タイムラグがある)ため、実際のハードリミットよりは低く設定する必要がある
検証: 上限を超えたらどうなるか
設定した上限を超えた際の挙動を確認するため、スクリプトで Gemini API を繰り返し呼び出してみました。
検証の条件は以下の通りです。
- 対象モデル: Gemini 3.1 Pro(
gemini-3.1-pro-preview) - リクエスト内容: 約2,000語のエッセイ生成(固定プロンプト)
- リクエスト間隔: 1分に1回程度(レスポンス待ち含む)
- 利用費上限の設定額: 200円
検証に使用したスクリプト
import { GoogleGenAI } from "@google/genai";
import { appendFileSync, writeFileSync } from "node:fs";
import { parseArgs } from "node:util";
const LONG_PROMPT =
"Please write a detailed 2000-word essay about the history of " +
"artificial intelligence, covering key milestones from the 1950s " +
"to the present day. Include discussion of neural networks, " +
"expert systems, machine learning, and large language models.";
const { values: args } = parseArgs({
options: {
model: { type: "string", default: "gemini-3.1-pro-preview" },
interval: { type: "string", default: "10" },
"max-requests": { type: "string", default: "500" },
"max-errors": { type: "string", default: "10" },
output: { type: "string", default: "spend_cap_results.jsonl" },
},
});
const model = args.model;
const interval = Number(args.interval);
const maxRequests = Number(args["max-requests"]);
const maxErrors = Number(args["max-errors"]);
const outputPath = args.output;
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
const sleep = (sec) => new Promise((r) => setTimeout(r, sec * 1000));
async function callGemini() {
const timestamp = new Date().toISOString();
try {
const response = await ai.models.generateContent({
model,
contents: LONG_PROMPT,
});
const usage = response.usageMetadata;
const inputTokens = usage.promptTokenCount;
const outputTokens = usage.candidatesTokenCount;
const thinkingTokens = usage.thoughtsTokenCount ?? 0;
return {
timestamp,
status: "success",
input_tokens: inputTokens,
output_tokens: outputTokens,
thinking_tokens: thinkingTokens,
total_tokens: inputTokens + outputTokens + thinkingTokens,
};
} catch (e) {
return {
timestamp,
status: "error",
error_type: e.constructor.name,
error_message: String(e.message ?? e),
};
}
}
console.log(`Model: ${model}`);
console.log(`Interval: ${interval}s`);
console.log(`Output: ${outputPath}`);
console.log(`Max requests: ${maxRequests}`);
console.log("---");
let consecutiveErrors = 0;
let totalTokens = 0;
let successCount = 0;
let errorCount = 0;
for (let i = 1; i <= maxRequests; i++) {
const result = await callGemini();
result.request_number = i;
appendFileSync(outputPath, JSON.stringify(result) + "\n");
if (result.status === "success") {
consecutiveErrors = 0;
successCount++;
totalTokens += result.total_tokens;
console.log(
`[${i}] OK | tokens: ${result.total_tokens.toLocaleString()} | cumulative: ${totalTokens.toLocaleString()}`
);
} else {
consecutiveErrors++;
errorCount++;
console.log(
`[${i}] ERROR | ${result.error_type}: ${result.error_message.slice(0, 120)}`
);
}
if (consecutiveErrors >= maxErrors) {
console.log(`\n${maxErrors} consecutive errors. Stopping.`);
break;
}
if (i < maxRequests) {
await sleep(interval);
}
}
console.log("\n--- Summary ---");
console.log(`Total requests: ${successCount + errorCount}`);
console.log(`Success: ${successCount}`);
console.log(`Errors: ${errorCount}`);
console.log(`Total tokens: ${totalTokens.toLocaleString()}`);
エラーの挙動
実際にスクリプトで API を叩き続けてみると、一定回数を叩いた後に 403 エラーが返るようになりました。
どうやら PERMISSION_DENIED のエラーが返ってくるようです。
{
"error": {
"code": 403,
"message": "Spend cap breached for project: projects/xxxxxxxxx for service: generativelanguage.googleapis.com. Correlation id: -8044973067305202300",
"status": "PERMISSION_DENIED"
}
}
この状態で、先ほどの「予算とアラート」画面を確認すると、先ほど設定した billing-cap で制限がかかっていることがわかります。

実際に利用費上限によって、API利用に制限がかかっていることが確認できました。
タイムラグと超過額
次に、上限の超過からエラーが返り始めるまでにどの程度のタイムラグがあるかを確認します。
以下がリクエストの実行結果です。
| # | 時刻(JST) | ステータス | output tokens | thinking tokens |
|---|---|---|---|---|
| 1 | 15:59:12 | OK | 2,641 | 1,597 |
| 2 | 16:00:00 | OK | 2,771 | 1,702 |
| ... | (中略) | OK | ... | ... |
| 18 | 16:13:47 | OK | 2,985 | 1,616 |
| 19 | 16:14:39 | OK | 2,921 | 1,630 |
| 20 | 16:15:20 | 403 | - | - |
| 21 | 16:15:25 | 403 | - | - |
| 22 | 16:15:30 | 403 | - | - |
トークンの消費状況から、実際に200円のボーダーを超えたのは 16:07 と想定されます。
しかし、実際に制限がかったのは 16:15 と、 約8分のタイムラグ がありました。
結果として、 200円のキャップに対して 286円の利用費が発生 しました。1分に1回程度のリクエスト頻度でもこの程度の超過は発生するため、注意書きの通り ハードリミットよりも低めに設定する 必要があります。
上限の解除
上限を一時的に解除したい場合は、先ほどのアラート画面から「利用費の上限を解除」ボタンを押すことで、一時的に制限を解除できます。

解除を実施すると、以下のような表示に切り替わります。

解除すると、数分以内にまた利用が可能になりました。
しかし、 上限を解除することでキャップが存在しない状態になってしまう 点には注意してください。キャップの上限値を変更するか、別のキャップを設けるようにしてください。
終わりに
以上、利用費の上限を設定する方法を試してみました。
設定した金額を超える可能性がある点については注意が必要ですが、意図しない高額請求を防げるというのは非常にありがたい機能です。今後の AI 利用を推進する中で、必須の設定の1つになっていくかもしれませんね。
この記事がどなたかの助けになれば幸いです。以上、すらぼでした。
参考リンク





