LLM APIの料金、なぜ高い?トークン課金の仕組みと予算で止める実装
AI APIの請求が読めない人へ。入出力トークン課金の計算、モデル使い分け、プロンプトキャッシュ、予算アラートで止める方法を、コピペで動くコードと一緒に整理しました。
月初に届いたAPIの請求を見て、コーヒーを吹きそうになりました。先月の3倍。何も派手なことはしていない、いつものスクリプトを回しただけのはずなのに。
ログを掘って原因が分かったとき、ちょっと脱力しました。犯人は「もっと詳しく説明して」と毎回頼んでいた、自分のプロンプトでした。出力が長いほど料金が跳ねる、という当たり前の事実を、僕は数字で殴られるまで本当には理解していなかったんです。
LLMのAPI料金がブラックボックスに見えるのは、頭が悪いからじゃありません。「読んだ量」と「書いた量」と「使い回した量」で値段が決まるという、ふだんの感覚にない課金体系だからです。タクシー料金のつもりで宅配便を使っている、と言えば近いかもしれません。
今日は、その仕組みを分解します。見積もりの式、モデルの使い分け、プロンプトキャッシュ、そして予算で自動的に止める実装まで。料金そのものは頻繁に変わるので、数字は「最新は公式で確認」を前提に読んでください。Claude Code本体のトークン節約術は別記事(/blog/claude-code-token-optimization/)に切り分けたので、ここではAPIの請求そのものに集中します。
この記事の要点
- LLM APIの料金は「入力トークン + 出力トークン + キャッシュ書き込み + キャッシュ読み取り」の足し算。出力単価は入力の5倍前後で、ここが請求を膨らませる主犯。
- 安くする順番は (1) 入力を絞る → (2) モデルを下げる → (3) プロンプトキャッシュを当てる → (4) 出力の長さを縛る。難しい最適化より、この4つが効く。
- 送る前にトークンを数え、実行後に
usageを記録し、1日の上限を超えそうなら止める。これをコードに組み込めば、月初の事故は起きない。 - 料金表もモデル名も変わる。記事の数字は基準値として、最終判断は必ず公式の料金ページで。
まず、課金の正体を1つの式に落とす
最初に、ぼんやりした不安を式に変えます。LLM APIの1回の請求は、だいたいこれで説明がつきます。
概算コスト = 入力トークン × 入力単価
+ キャッシュ書き込みトークン × 書き込み単価
+ キャッシュ読み取りトークン × 読み取り単価
+ 出力トークン × 出力単価
トークンというのは、AIが読み書きする文字の単位です。日本語だと1文字で1〜2トークン、英語だと単語1個でだいたい1トークン、くらいのざっくり感覚で困りません。「料金 = 文字数の足し算」と思っておけば、入り口は十分です。
数字を入れてみます。2026-06-07時点のAnthropicの料金表だと、たとえばこうです(単価は100万トークン=MTokあたり)。
| モデル | 入力 | 出力 | 5分キャッシュ書込 | キャッシュ読取 |
|---|---|---|---|---|
| Claude Opus 4.8 | $5 | $25 | $6.25 | $0.50 |
| Claude Sonnet 4.6 | $3 | $15 | $3.75 | $0.30 |
| Claude Haiku 4.5 | $1 | $5 | $1.25 | $0.10 |
この表で、まっさきに目に焼き付けてほしいのは出力が入力の5倍だという一点です。OpenAIなど他社でも、出力が入力より高い構造はだいたい共通しています。つまり「長く詳しく書いて」と頼むたびに、いちばん高い蛇口をひねっている。僕が請求3倍をやらかしたのは、まさにこれでした。
逆に、いちばん安いのがキャッシュ読み取り。入力単価の10分の1です。同じ前置きを何度も送るなら、ここを当てにいく価値があります(後で実装します)。
安くする4つの順番
コストを下げる打ち手はたくさんありますが、効く順に並べると迷いません。上から順に試すだけです。
- 入力を絞る。 いちばん効きます。10個のファイルを丸ごと貼るのをやめて、関係する3個に絞る。失敗ログは全文じゃなく最後の80行だけ渡す。これだけで入力トークンが半分以下になることはザラです。
- モデルを下げる。 翻訳・要約・整形みたいな素直な作業に、最上位モデルは要りません。Haikuで足りる仕事をOpusに投げるのは、近所のコンビニにタクシーで行くようなものです。
- プロンプトキャッシュを当てる。 文体ルールや長い前提文など「毎回同じ前半」をキャッシュすると、2回目以降の入力が激安になります。
- 出力を縛る。 「重大度順に最大5件」「200字以内」のように出口を指定する。
max_tokensはあくまで保険で、本命はプロンプト側で短く頼むことです。
順番が大事です。先に細かいキャッシュ調整をしても、巨大な入力を毎回送っていたら焼け石に水。まず入力、次にモデル、それからキャッシュと出力、の順で潰します。
モデルの使い分けで、品質を落とさず安くする
「安いモデルにすると質が落ちるのでは」とよく聞かれます。答えは「仕事による」です。タスクを3層に仕分けると、無駄が見えます。
| 層 | こういう仕事 | 向くモデル |
|---|---|---|
| 軽作業 | 翻訳、要約、フォーマット変換、定型分類 | Haiku |
| 主力 | 一般的なコード生成、レビュー、調査 | Sonnet |
| 難所 | 設計判断、難しい障害調査、複雑な推論 | Opus |
コツは、標準をSonnetにして、上下に振ることです。最初からOpus固定にすると、軽い翻訳1件にまで最上位料金を払い続けます。逆に全部Haikuにすると、難しい判断で手戻りが増えて、結局やり直しのトークンで高くつく。
大量の同型リクエスト(何百件の翻訳など、すぐ結果が要らないもの)は、Batch APIを使うと入出力ともに50%引きになります。急がない一括処理なら、これを使わない手はありません。
プロンプトキャッシュで「毎回の前置き」をタダ同然にする
キャッシュは、効くと劇的です。仕組みはシンプルで、前半が前回とまったく同じプロンプトを送ると、その部分を再処理せず安く読み込んでくれます。
僕の記事制作だと、文体ルールやチェック項目を書いた長い前提文を毎回送っています。これをキャッシュ対象にして、本文だけ差し替える。すると2回目以降、その前提文ぶんの入力が読み取り単価(入力の10分の1)になります。
落とし穴は1つだけ。前半に「毎回変わるもの」を混ぜると外れます。 system promptに現在時刻、UUID、毎回並びが変わるファイル一覧を入れると、それだけでキャッシュが当たりません。「変わらない前置き → 変わる本文」の順に並べるのが鉄則です。
SDKではcache_controlを付けるだけで使えます。次のコードに組み込んであるので、そちらで確認してください。
送信前に見積もる:APIを叩かない概算スクリプト
ここから手を動かします。まずは課金される前に、月額をざっくり出す電卓を作ります。Node.jsだけで動き、APIキーも要りません。
// cost-estimator.mjs
// 1日あたりのトークン量(MTok)を入れて月額をざっくり出す電卓
const RATES = {
// [入力, 出力, キャッシュ読取] 単位はドル/100万トークン
opus48: { input: 5, output: 25, cacheRead: 0.5 },
sonnet46: { input: 3, output: 15, cacheRead: 0.3 },
haiku45: { input: 1, output: 5, cacheRead: 0.1 },
};
// 例: node cost-estimator.mjs sonnet46 22 0.25 0.06 0.20
const [model = "sonnet46", days = "22", input = "0.25", output = "0.06", cacheRead = "0.20"] =
process.argv.slice(2);
const rate = RATES[model];
if (!rate) throw new Error(`知らないモデル: ${model}(${Object.keys(RATES).join(", ")} から選ぶ)`);
// 1日あたりのドル = 各トークン量 × 単価
const dailyUsd =
Number(input) * rate.input +
Number(output) * rate.output +
Number(cacheRead) * rate.cacheRead;
console.log({
model,
営業日: Number(days),
日額ドル: Number(dailyUsd.toFixed(4)),
月額ドル: Number((dailyUsd * Number(days)).toFixed(2)),
});
実行してみます。
node cost-estimator.mjs sonnet46 22 0.25 0.06 0.20
node cost-estimator.mjs haiku45 22 0.25 0.06 0.20
この条件だとSonnet 4.6で1日約$1.71、22営業日で約$37.6。同じ量をHaikuに寄せると約$13に下がります。実際にはツール定義や再試行、キャッシュ書き込みが上乗せされるので、見積もりには2〜3割の余白を足しておくと安心です。
肝心なのは、数字が「読める」ようになることです。請求書に怯えるかわりに、「Haikuに寄せれば月25ドル浮く」と先に言える。これだけで意思決定がぜんぜん変わります。
実行時に予算で止める:超えそうなら投げない
次が本命です。実際にAPIを呼ぶ前にトークンを数え、今日の上限を超えそうなら、そもそも送らない。送った後はレシート(usage)をファイルに残します。Claudeで書きますが、考え方はどのLLM APIでも同じです。
npm init -y
npm i @anthropic-ai/sdk
// budgeted-message.mjs
// 送る前に量り、上限を超えそうなら止め、送った後にレシートを残す
import Anthropic from "@anthropic-ai/sdk";
import fs from "node:fs";
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const model = process.env.CLAUDE_MODEL ?? "claude-sonnet-4-6";
const maxTokens = Number(process.env.MAX_TOKENS ?? 700);
const dailyBudgetUsd = Number(process.env.DAILY_BUDGET_USD ?? 5);
// 単価表(ドル/100万トークン)。最新は公式の料金ページで確認すること
const RATES = {
"claude-opus-4-8": { input: 5, output: 25, cacheWrite5m: 6.25, cacheRead: 0.5 },
"claude-sonnet-4-6": { input: 3, output: 15, cacheWrite5m: 3.75, cacheRead: 0.3 },
"claude-haiku-4-5": { input: 1, output: 5, cacheWrite5m: 1.25, cacheRead: 0.1 },
};
// usageオブジェクトから実コスト(ドル)を計算
function usdFromUsage(usage, rate) {
return (
(usage.input_tokens ?? 0) * rate.input +
(usage.output_tokens ?? 0) * rate.output +
(usage.cache_creation_input_tokens ?? 0) * rate.cacheWrite5m +
(usage.cache_read_input_tokens ?? 0) * rate.cacheRead
) / 1_000_000;
}
// 今日ぶんの累計コストをログから合算
function todayTotalUsd(path) {
if (!fs.existsSync(path)) return 0;
const today = new Date().toISOString().slice(0, 10);
return fs.readFileSync(path, "utf8")
.trim()
.split("\n")
.filter(Boolean)
.map((line) => JSON.parse(line))
.filter((row) => row.date === today)
.reduce((sum, row) => sum + row.usd, 0);
}
const messages = [
{ role: "user", content: "このTypeScript関数のバグ候補を3つだけ挙げてください。" },
];
const rate = RATES[model];
if (!rate) throw new Error(`単価表にないモデル: ${model}`);
// 1) 送る前に入力トークンを数える
const counted = await anthropic.messages.countTokens({ model, messages });
// 2) 最悪ケース(入力 + 出力上限まで)のコストを見積もる
const worstCaseUsd = (counted.input_tokens * rate.input + maxTokens * rate.output) / 1_000_000;
const logPath = "usage.jsonl";
// 3) 今日の累計 + 今回の最悪ケースが上限を超えるなら、送らずに止める
if (todayTotalUsd(logPath) + worstCaseUsd > dailyBudgetUsd) {
throw new Error(`予算ストップ: 本日の見込みが $${dailyBudgetUsd} を超えます`);
}
const response = await anthropic.messages.create({
model,
max_tokens: maxTokens,
// 前半を使い回せる場合はキャッシュを有効化
cache_control: { type: "ephemeral" },
system: "あなたは簡潔なシニアコードレビュアーです。実行可能な指摘だけ返してください。",
messages,
});
// 4) 送った後、実コストをレシートとして追記
const usd = usdFromUsage(response.usage, rate);
fs.appendFileSync(logPath, JSON.stringify({
date: new Date().toISOString().slice(0, 10),
model,
usd: Number(usd.toFixed(6)),
usage: response.usage,
}) + "\n");
console.log({ id: response.id, usd: Number(usd.toFixed(6)), usage: response.usage });
ANTHROPIC_API_KEY=sk-ant-... DAILY_BUDGET_USD=5 node budgeted-message.mjs
やっていることは3つだけです。送る前に大きさを量る・上限を超えそうなら投げない・送った後にレシートを残す。 たったこれだけで、月初に請求書を見て青ざめる事故が消えます。usage.jsonlが日々のレシート帳になるので、後から「どのモデルでいくら使ったか」も追えます。
使用量を監視して、予算アラートを置く
個人なら上のJSONLログで十分ですが、チームだと「気づいたら誰かが大量に使っていた」を防ぎたい。そこで予算を3段階に分けて、しきい値で警告・停止します。
| レベル | 目安 | ルール |
|---|---|---|
| 1タスク | $0.20まで | 超えたら入力を削るかモデルを下げる |
| 1日 | $5まで | ログで累計、80%で警告 |
| 1か月 | $100まで | 公式コンソールで確認、超過前に停止 |
最小ルールは「80%で警告・100%で停止・翌日リセット」。これだけ決めておけば、初心者でも運用が破綻しません。
組織アカウントなら、AnthropicのUsage and Cost API(Admin API)でモデル別・期間別の利用をまとめて引けます。これは個人アカウントでは使えず、sk-ant-admin...で始まる管理キーが必要です。
curl "https://api.anthropic.com/v1/organizations/usage_report/messages?\
starting_at=2026-06-01T00:00:00Z&\
ending_at=2026-06-08T00:00:00Z&\
group_by[]=model&\
bucket_width=1d" \
--header "anthropic-version: 2023-06-01" \
--header "x-api-key: $ANTHROPIC_ADMIN_KEY"
毎朝これで見るのは3つで足ります。Opus比率(軽作業まで最上位を使っていないか)、出力トークン(返答が毎回長文になっていないか)、キャッシュ読み取り(ゼロに近いならキャッシュが外れている)。この3点を5分眺めるだけで、無駄の9割は見つかります。チームで権限と予算を毎朝点検する具体的な手順は/blog/claude-code-permission-budget-loop/にまとめました。AWS経由で動かして請求を一本化したいなら/blog/claude-code-amazon-bedrock-guide/も参考になります。
僕がやらかしたコスト事故3つ
正直に書きます。請求3倍は氷山の一角でした。
ひとつ目は、出力を縛らなかったこと。冒頭の事故そのものです。「詳しく」と頼むクセが、いちばん高い出力トークンを毎回フル回転させていました。出口を「最大5件」「200字以内」と決めただけで、月額が体感3割減りました。
ふたつ目は、キャッシュが当たっていると思い込んでいたこと。system promptに実行時刻を埋め込んでいて、前半が毎回変わる。当然キャッシュは1回も当たっていませんでした。usageのcache_read_input_tokensがずっとゼロで、ようやく気づいたんです。レシートを見る習慣がなければ、永遠に取りこぼしていました。
みっつ目は、安すぎる非公式APIに手を出しかけたこと。料金が正規の半額みたいなサービスがあって、一瞬ぐらつきました。でもモデルが本物か、ログを再利用されないか、認証情報は安全か、どれも説明できない。結局やめました。安さの裏が説明できないものは、事故の前借りです。
よくある質問
Q. トークン数って、事前に正確に分かりますか?
入力側はSDKのToken Count APIでかなり正確に数えられます。出力側は実際に生成されるまで確定しないので、max_tokensで上限を置いて最悪ケースを見積もるのが現実的です。
Q. プロンプトキャッシュは必ず安くなりますか? 前半が前回と同じで、かつ一定時間内に再利用されたときだけです。1回書き込んで1回も読まれないと、書き込みぶん(5分キャッシュで入力の1.25倍)がむしろ割高になります。同じ前置きを繰り返すワークフローでこそ効きます。
Q. どのモデルから始めればいいですか? 標準をSonnet級にして、軽作業はHaiku級へ、難所だけOpus級へ振るのがおすすめです。最初から最上位固定にすると、軽い処理にまで最上位料金を払い続けます。
Q. 安い非公式API(プロキシ)はアリですか? おすすめしません。モデルの差し替え、ログの再利用、認証情報の漏えいリスクを説明できないことが多いです。料金が正規の半額みたいなサービスは、安さの理由を確認できない時点で見送るのが安全です。
Q. 料金表の数字、この記事のまま信じていいですか? 基準としては使えますが、最終判断は必ず公式で。モデルも価格も更新されます。この記事は2026-06-07時点のAnthropic公式料金を基準にしています。
実際に試した結果
請求3倍の月から、僕がやったのは難しい最適化ではありませんでした。やったのは3つだけ。出口を短く縛る・標準モデルをSonnetに下げる・JSONLにレシートを残して80%で警告する。 これで翌月の請求は元の水準に戻り、しかも作業の質は落ちませんでした。
いちばん効いたのは、実は「ログを残す」だったと思います。金額が見えるようになると、「この処理、Haikuでよくない?」と自分でツッコめる。請求書に怯える側から、数字で判断する側に回れる。コスト管理は我慢の話じゃなくて、見えるようにする話なんだと、今は思っています。
まずcost-estimator.mjsを回して自分の月額を一度可視化してみてください。それだけで、次の一手が驚くほどはっきりします。チーム導入やテンプレートが必要なら教材一覧も覗いてみてください。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Codeに1ファイルだけ直させる指示文のつくり方
「もっと良くして」で40行も変えられた失敗から学んだ、触る範囲・検証・戻し方をセットにしたClaude Code用の依頼文テンプレートを紹介します。
Claude Code の権限拒否から復旧する: 止まった理由を次の安全手順に変える
Claude Code のコマンドが拒否されたとき、焦って許可を広げずに、拒否理由、代替手順、証拠コマンド、再試行条件へ分解する方法。
Claude Codeにビルド→スモークテスト→自動修正を回させる足場の作り方
最小スモークテストの選び方、失敗ログを食わせて直させるループ、回数上限と確認ゲートで暴走を止める方法を、コピペで動くコード付きで紹介します。