GASでClaude APIのトークン数を
送信前に数えて見積もる方法
Claude APIの料金はトークン単位で決まります。送信して初めて消費量が分かるのでは、想定外の高額請求が怖くて大量処理に踏み切れません。count_tokensエンドポイントを使えば、メッセージを送る前に入力トークン数を正確に数えられます。料金の事前見積もりからコンテキスト上限のチェックまで、動くコードで解説します。
Table of Contents
なぜ送信前にトークン数を数えるのか
Claude APIはトークン(単語や文字を細かく区切った処理単位)ごとに課金されます。呼び出したあとにレスポンスのusageを見れば実際の消費量は分かりますが、それは「もう課金されたあと」です。数百行にAIを回すような処理では、走らせる前に「だいたいいくらかかるか」「上限に収まるか」を把握したいはずです。
そこで使うのがcount_tokensエンドポイントです。回答を生成せず、入力トークン数だけを正確に数えて返します。呼び出し自体は無料なので、送信前チェックに気軽に使えます。
料金を事前に見積もれる
文字数からの推測ではなく、実測トークン数で概算コストを出せる
上限オーバーを防げる
コンテキストの上限を超えるリクエストを送る前に検知できる
呼び出しは無料
回答を生成しないため、数えるだけなら入力トークンの料金はかからない
大量処理の前に確認できる
スプレッドシート全行の合計コストを、走らせる前に見積もれる
count_tokensエンドポイントの基本
使うURLは通常のメッセージ送信(/v1/messages)ではなく、/v1/messages/count_tokensです。送るリクエストの中身(modelとmessages)をそのまま渡すと、{ "input_tokens": 数値 }という形で入力トークン数だけが返ってきます。
返ってくるのは入力トークン数のみです。出力(回答)のトークン数は実際に生成するまで分かりません。トークンの数え方はモデルごとに異なるため、本番で使う予定のモデル名を必ず指定してください。
GASからトークン数を数える関数を作る
GASではUrlFetchApp.fetchでcount_tokensを呼び出します。APIキーはPropertiesServiceに保存しておき、コードに直接書かないのが基本です。ヘッダーのanthropic-versionはメッセージ送信のときと同じ値を使います。
// count_tokens は「送信前に入力トークン数を数える」専用エンドポイント。
// messages(回答生成)とは別で、呼び出し自体は無料。
// レスポンスは { "input_tokens": 1234 } の形。
//
// POST https://api.anthropic.com/v1/messages/count_tokens
function countClaudeTokens(userText) {
const apiKey = PropertiesService.getScriptProperties()
.getProperty("CLAUDE_API_KEY");
const res = UrlFetchApp.fetch(
"https://api.anthropic.com/v1/messages/count_tokens",
{
method: "post",
contentType: "application/json",
headers: {
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
},
payload: JSON.stringify({
model: "claude-haiku-4-5", // 本番で使う予定のモデルを指定
messages: [{ role: "user", content: userText }],
}),
muteHttpExceptions: true,
}
);
if (res.getResponseCode() !== 200) {
throw new Error("count_tokens error: " + res.getContentText());
}
const body = JSON.parse(res.getContentText());
return body.input_tokens; // 入力トークン数(正確な実測値)
}
// 使い方
function demo() {
const n = countClaudeTokens("この文章のトークン数を教えて");
Logger.log("入力トークン数: " + n);
}返り値のinput_tokensが、その文章を送ったときに消費される入力トークン数です。文字数から推測する必要はなく、モデルが実際に数えるのと同じ値が得られます。
system・toolsも含めて正確に数える
実際の呼び出しでは、ユーザーの文章だけでなくsystem(役割や指示を固定するシステムプロンプト)やtools(AIに実行させる関数の定義)も入力トークンに加算されます。正確に数えるには、本番で送るリクエストと同じ構成をcount_tokensにも渡します。
// system(システムプロンプト)や tools を使うなら、
// messages と同じ内容を count_tokens にも渡す。
// 送るリクエストと同じ構成にしないと数がずれる。
function countTokensFull(systemPrompt, messages, tools) {
const apiKey = PropertiesService.getScriptProperties()
.getProperty("CLAUDE_API_KEY");
const payload = {
model: "claude-haiku-4-5",
messages: messages, // 会話履歴も含めて丸ごと渡す
};
if (systemPrompt) payload.system = systemPrompt; // あれば追加
if (tools) payload.tools = tools; // ツール定義も加算対象
const res = UrlFetchApp.fetch(
"https://api.anthropic.com/v1/messages/count_tokens",
{
method: "post",
contentType: "application/json",
headers: {
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
},
payload: JSON.stringify(payload),
muteHttpExceptions: true,
}
);
if (res.getResponseCode() !== 200) {
throw new Error("count_tokens error: " + res.getContentText());
}
return JSON.parse(res.getContentText()).input_tokens;
}システムプロンプトやツール定義は毎回送るぶん、意外とトークンを消費します。数えてみて多いと感じたら、プロンプトキャッシュで固定部分を使い回すとコストを抑えられます。まず数えることが、削減の第一歩です。
トークン数から料金を事前見積もりする
入力トークン数が分かれば、料金を概算できます。料金は入力トークン × 入力単価 + 出力トークン × 出力単価です。ここで注意したいのは、入力は正確に数えられても、出力は生成するまで確定しないこと。そこで出力は「max_tokensの上限まで使った場合」など想定値で計算します。
// 入力トークン数は正確に数えられるが、出力トークン数は
// 生成してみるまで分からない。そこで出力は「想定値」で見積もる。
//
// 料金 = 入力トークン × 入力単価 + (想定)出力トークン × 出力単価
// 単価は「100万トークンあたり◯ドル」。改定されるため公式で最新値を確認。
const PRICE_PER_MTOK = {
// model名: { input: 入力単価, output: 出力単価 } ※サンプル値
"claude-haiku-4-5": { input: 1.0, output: 5.0 },
"default": { input: 3.0, output: 15.0 },
};
const USD_TO_JPY = 160; // 円換算レート(任意)
// 送信前に「入力は実測・出力は想定」で概算料金を出す
function estimateBeforeSend(userText, model, assumedOutputTokens) {
const inputTokens = countClaudeTokens(userText); // 実測
const price = PRICE_PER_MTOK[model] || PRICE_PER_MTOK["default"];
const inputUsd = (inputTokens / 1000000) * price.input;
const outputUsd = (assumedOutputTokens / 1000000) * price.output;
const usd = inputUsd + outputUsd;
Logger.log(
"入力(実測): " + inputTokens + "tok / " +
"出力(想定): " + assumedOutputTokens + "tok"
);
Logger.log("概算: $" + usd.toFixed(5) + " / 約" + Math.round(usd * USD_TO_JPY) + "円");
return usd;
}
function demoCost() {
// 出力は max_tokens の上限(例: 512)を想定して見積もる
estimateBeforeSend("長い議事録をここに...", "claude-haiku-4-5", 512);
}単価はサンプル値です。料金は改定されることがあるため、必ずAnthropicの公式料金ページで最新の値を確認してテーブルに設定してください。ここで出る金額はあくまで「概算」で、実際の出力量によって上下します。入力は実測、出力は想定、と切り分けて考えるのがコツです。
コンテキスト上限オーバーを未然に防ぐ
モデルには一度に入力できる量の上限(コンテキストウィンドウ)があります。長い議事録や大量の行をまとめて送ると、この上限を超えてエラーで弾かれることがあります。送信前にcount_tokensで数えておけば、収まるかどうかを事前に判定できます。
// 長文や大量の行をまとめて送る前に、コンテキスト上限に
// 収まるかチェックする。超えるリクエストはエラーで弾かれるため、
// 送信前に気づけると安全。
const MODEL_CONTEXT_LIMIT = {
// 各モデルの入力の上限(コンテキストウィンドウ)※公式で最新値を確認
"claude-haiku-4-5": 200000,
"default": 200000,
};
// 上限に収まるか、余裕をみて判定する
function fitsInContext(userText, model) {
const inputTokens = countClaudeTokens(userText);
const limit = MODEL_CONTEXT_LIMIT[model] || MODEL_CONTEXT_LIMIT["default"];
// 出力ぶんの余白も残す(例: 上限の90%までを入力の目安にする)
const safeLimit = Math.floor(limit * 0.9);
const ok = inputTokens <= safeLimit;
Logger.log(
"入力: " + inputTokens + "tok / 目安上限: " + safeLimit + "tok / " +
(ok ? "OK" : "超過(分割が必要)")
);
return ok;
}
function demoLimit() {
const bigText = "とても長い本文...";
if (!fitsInContext(bigText, "claude-haiku-4-5")) {
// 上限を超えるなら分割して送るなどの対策へ
throw new Error("入力が長すぎます。分割してください。");
}
// 収まっていれば本番の messages 呼び出しへ進む
}ポイントは、上限ぎりぎりではなく余白を残すことです。入力が上限に近いと、回答を生成する出力ぶんの余地がなくなります。上限の8〜9割を目安にしておくと安全です。超えそうなときは、テキストを分割して複数回に分けて送る設計に切り替えます。
大量データを本番実行前に一括見積もりする
一番効果が大きいのが、スプレッドシートの全行にAIを回す前の一括見積もりです。走らせる前に「合計で何トークン・いくらかかりそうか」を出しておけば、想定外の請求を避けられます。A列に対象テキストが並んでいる前提のコードです。
// スプレッドシートの全行を「本番実行する前に」一括見積もり。
// 走らせる前に「合計いくらかかりそうか」を把握できる。
// A列に対象テキストが入っている前提。
function estimateSheetBeforeRun() {
const sheet = SpreadsheetApp.getActive().getSheetByName("対象");
const values = sheet.getRange(2, 1, sheet.getLastRow() - 1, 1).getValues();
const model = "claude-haiku-4-5";
const price = PRICE_PER_MTOK[model] || PRICE_PER_MTOK["default"];
const assumedOutputTokens = 300; // 1件あたりの想定出力トークン
let totalInput = 0;
let totalUsd = 0;
let count = 0;
for (const row of values) {
const text = String(row[0] || "").trim();
if (!text) continue;
const inputTokens = countClaudeTokens(text); // 1件ずつ実測
const usd =
(inputTokens / 1000000) * price.input +
(assumedOutputTokens / 1000000) * price.output;
totalInput += inputTokens;
totalUsd += usd;
count++;
Utilities.sleep(200); // レート制限に配慮して少し待つ
}
Logger.log(
count + "件 / 入力合計: " + totalInput + "tok / " +
"概算: $" + totalUsd.toFixed(4) + " / 約" + Math.round(totalUsd * USD_TO_JPY) + "円"
);
return { count: count, totalInput: totalInput, totalUsd: totalUsd };
}1件ずつcount_tokensを呼ぶとリクエスト回数が増えるため、Utilities.sleepで少し間隔を空けています。件数が非常に多いときは、全行を数えずに代表的な数十件だけ数えて1件あたりの平均を出し、件数を掛けて概算する方法でも十分です。見積もりで納得したら、実行後の実測トークン記録と組み合わせると、事前予測と実績を突き合わせられます。
まとめ
Claude APIのcount_tokensを使えば、メッセージを送る前に入力トークン数を正確に数えられます。呼び出しは無料なので、料金の事前見積もり、コンテキスト上限のチェック、大量処理前の合計コスト把握に気軽に使えます。押さえるべきは、入力は実測できるが出力は想定値で見積もること、本番と同じモデル・同じ構成で数えること、そして単価は公式で最新値を確認することです。送信前に一手間かけるだけで、AI自動化を安心して本番に載せられます。
よくある質問
トークンを数えるためのcount_tokensエンドポイント自体の利用は無料です。実際にメッセージを生成するmessagesエンドポイントとは別で、モデルに回答を生成させるわけではないため、入力トークンの料金は発生しません。ただしリクエスト回数のレート制限はあるため、数百件を一気に数えるときは送信間隔を空けるか、代表的な数件だけ数えて平均を出す使い方が安全です。
文字数とトークン数は単純に比例しないため、推測では誤差が大きくなります。トークンは単語や文字の断片を表す処理単位で、日本語は1文字が複数トークンになることもあり、記号やコードが混ざるとさらにずれます。count_tokensはモデルが実際に数えるのと同じ方式でカウントするので、料金や上限の判断に使える正確な値が得られます。
いいえ。count_tokensで分かるのは入力トークン数だけです。出力トークン数は実際に回答が生成されるまで確定しません。料金を事前に見積もるときは、入力は正確な実測値を使い、出力は「max_tokensの上限まで使った場合」など想定値で計算するのが現実的です。入力と出力を分けて考えるのがポイントです。
変わります。トークンの数え方はモデルによって異なるため、同じ文章でもモデルが違えばトークン数が変わることがあります。count_tokensのリクエストには実際に使う予定のモデル名を指定してください。見積もりに使ったモデルと本番で送るモデルを一致させないと、数えた値と実際の消費量がずれます。
モデルの入力の上限(コンテキストウィンドウ)を超えるリクエストはエラーで弾かれます。長い議事録や大量の行をまとめて送る処理では、送信前にcount_tokensで入力トークン数を数え、上限に収まるか確認しておくと、エラーになってから気づく事態を防げます。上限に近いときは分割して送るなどの対策を取れます。
AI×GASの業務自動化を
相談する。
Claude APIを使った自動化は、コストの事前見積もりと予算管理まで含めて設計すると安心して本番運用できます。要件整理から運用設計までご相談いただけます。