OpenAI APIのトークン数を送信前に計算する方法|token_counterツール・料金見積もり【2026年版】
ひとことで言うと
OpenAI APIを使う際、リクエスト送信前にトークン数を正確に計算することで、予期しない高額課金を防げます。Pythonの「tiketokenライブラリ」を使えば、実際のAPI計算と同じ方法でトークン数をカウント可能。料金予測ツールの実装パターンも紹介します。
なぜトークン数の事前計算が重要か
OpenAI APIの課金は「トークン(言葉を分割した最小単位のこと)」ごとに発生します。テキストを送信する前にトークン数を知ることで、以下のメリットが得られます。
- 💰 予算を守る:送信前に「この質問は〇円かかる」と把握できる
- 🛡️ バグによる超過課金を防ぐ:ループ処理の暴走など、予期しない大量リクエストの損失を検知できる
- 📊 コスト削減の工夫が見える:どこのテキストが「トークン無駄使い」か特定できる
多くの日本のスタートアップ・個人開発者が「気づいたら高額請求が来た」という経験をしています。送信前計算はそうした事故を防ぐ最初の防線です。
トークンとは?基本理解
トークンの数え方
トークンは1語=1トークンではありません。言語やモデルによって異なります。
| 例 | トークン数 |
|---|---|
| ”hello” | 1トークン |
| ”Hello, world!“ | 4トークン |
| ”こんにちは” | 3~4トークン(日本語は英語より多い傾向) |
| 絵文字😊 | 1~2トークン |
日本語は1字=1トークンに近い計算になることが多く、英語より効率が悪いことに注意します。
モデルごとにトークン数が違う
重要な落とし穴:同じテキストでも、モデルによってトークナイザー(トークンに分割するプログラムのこと)が異なることがあります。実装時は「どのモデルで計算するか」を明確に指定する必要があります。
tiketokenライブラリの使い方
インストール
pip install tiktoken
公式ドキュメントによると、tiketokenはOpenAIが提供する軽量・高速なPythonライブラリで、ローカルマシンで即座にトークン数をカウントできます。
基本的な使い方
1. モデルを指定してトークンをカウント
import tiktoken
# GPT-4o用のトークナイザーを取得
enc = tiktoken.encoding_for_model("gpt-4o")
# テキストをトークン化
text = "OpenAI APIの料金は思いの外高いことがあります。"
tokens = enc.encode(text)
print(f"トークン数: {len(tokens)}")
print(f"トークン内容: {tokens}")
実行結果の例:
トークン数: 22
トークン内容: [139, 9, 1230, 45, ...]
2. 複数のテキストを計算
import tiktoken
enc = tiktoken.encoding_for_model("gpt-4o")
messages = [
{"role": "user", "content": "こんにちは"},
{"role": "assistant", "content": "こんにちは。何かお手伝いできることはありますか?"}
]
# メッセージ全体のトークン数を計算
total_tokens = 0
for msg in messages:
tokens = enc.encode(msg["content"])
total_tokens += len(tokens)
print(f"[{msg['role']}]: {len(tokens)}トークン")
print(f"合計: {total_tokens}トークン")
3. API呼び出し時の「オーバーヘッド」を含める
実は、APIリクエストにはテキスト本体以外にメタデータ用のトークンが消費されます。公式にはメッセージ形式では以下の計算が目安です。
- システムメッセージ:3~4トークンの固定オーバーヘッド
- 各メッセージの区切り:3~4トークン追加
def count_message_tokens(messages, model="gpt-4o"):
"""API呼び出しで実際に消費されるトークン数を推定"""
enc = tiktoken.encoding_for_model(model)
total = 0
for msg in messages:
# メッセージの内容
total += len(enc.encode(msg["content"]))
# メッセージの区切り記号(3~4トークン)
total += 4
# 終了マーカー(1トークン)
total += 1
return total
# 使用例
messages = [
{"role": "system", "content": "あなたは技術ライターです"},
{"role": "user", "content": "OpenAI APIの料金を説明してください"}
]
estimated_tokens = count_message_tokens(messages)
print(f"推定トークン数(オーバーヘッド含む): {estimated_tokens}")
料金予測ツールの実装パターン
パターン1:シンプルな料金計算
GPT-4oの現在の料金(2026年8月時点の参考値):
- 入力:$0.005 / 1,000トークン
- 出力:$0.015 / 1,000トークン
import tiktoken
class APITokenCalculator:
"""OpenAI APIのトークン数・料金を計算するクラス"""
# 2026年8月時点の料金(ドルで定義)
PRICING = {
"gpt-4o": {
"input": 0.005, # $ per 1,000 tokens
"output": 0.015
}
}
def __init__(self, model="gpt-4o"):
self.model = model
self.enc = tiktoken.encoding_for_model(model)
def count_tokens(self, text):
"""テキストのトークン数を計算"""
return len(self.enc.encode(text))
def estimate_cost(self, input_text, estimated_output_tokens=100):
"""
入力テキストと予想出力トークン数から料金を推定
Args:
input_text (str): 送信するテキスト
estimated_output_tokens (int): 出力の予想トークン数
Returns:
dict: 料金情報
"""
input_tokens = self.count_tokens(input_text)
pricing = self.PRICING[self.model]
input_cost = (input_tokens / 1000) * pricing["input"]
output_cost = (estimated_output_tokens / 1000) * pricing["output"]
total_cost = input_cost + output_cost
return {
"input_tokens": input_tokens,
"estimated_output_tokens": estimated_output_tokens,
"input_cost_usd": round(input_cost, 6),
"output_cost_usd": round(output_cost, 6),
"total_cost_usd": round(total_cost, 6),
"total_cost_jpy": round(total_cost * 150, 0) # 例:1ドル=150円
}
# 使用例
calc = APITokenCalculator()
question = "OpenAI APIの料金体系について、初心者向けに詳しく説明してください。"
result = calc.estimate_cost(question, estimated_output_tokens=300)
print(f"入力トークン: {result['input_tokens']}")
print(f"推定出力トークン: {result['estimated_output_tokens']}")
print(f"合計料金: ${result['total_cost_usd']} (約{int(result['total_cost_jpy'])}円)")
パターン2:バッチリクエストの超過防止
複数のテキストを処理する際に合計トークン数が予算を超えないようにする実装です。
class TokenBudgetGuard:
"""トークン予算を守りながらバッチリクエストを処理"""
def __init__(self, model="gpt-4o", max_input_tokens=10000):
self.model = model
self.enc = tiktoken.encoding_for_model(model)
self.max_input_tokens = max_input_tokens
def split_texts_by_token_budget(self, texts, max_tokens_per_batch=5000):
"""
テキストのリストを、トークン予算内に収まるようにバッチ分割
Args:
texts (list): テキストリスト
max_tokens_per_batch (int): 1バッチあたりの最大トークン数
Yields:
list: トークン予算内のテキストバッチ
"""
batch = []
batch_tokens = 0
for text in texts:
text_tokens = len(self.enc.encode(text))
# このテキストを追加すると超過する場合
if batch_tokens + text_tokens > max_tokens_per_batch:
if batch:
yield batch
batch = [text]
batch_tokens = text_tokens
else:
batch.append(text)
batch_tokens += text_tokens
if batch:
yield batch
def estimate_batch_cost(self, texts, cost_per_1k_input=0.005):
"""バッチ処理全体のコストを推定"""
total_tokens = sum(len(self.enc.encode(t)) for t in texts)
cost = (total_tokens / 1000) * cost_per_1k_input
return {
"total_texts": len(texts),
"total_input_tokens": total_tokens,
"estimated_cost_usd": round(cost, 6)
}
# 使用例
guard = TokenBudgetGuard(max_input_tokens=50000)
documents = [
"ドキュメント1:OpenAI APIの基本...",
"ドキュメント2:トークン計算の方法...",
"ドキュメント3:料金管理のベストプラクティス...",
# ... さらに多くのドキュメント
]
# バッチに分割して処理
for i, batch in enumerate(guard.split_texts_by_token_budget(documents, max_tokens_per_batch=3000)):
print(f"バッチ {i+1}: {len(batch)}件のテキスト")
cost = guard.estimate_batch_cost(batch)
print(f" 推定トークン: {cost['total_input_tokens']}")
print(f" 推定コスト: ${cost['estimated_cost_usd']}")
パターン3:応答が途中で切れたときの補足計算
トークン上限に達して応答が途中で切れるケースでは、入力トークンだけでなく、すでに消費された出力トークンをカウントして補続リクエストを最適化する必要があります。
def estimate_continuation_cost(
previous_input_tokens,
previous_output_tokens,
continuation_input_tokens,
input_rate=0.005,
output_rate=0.015
):
"""
途中で切れた応答を続けるときの追加コスト計算
Args:
previous_input_tokens: 最初のリクエストの入力トークン
previous_output_tokens: 最初のリクエストで得た出力トークン
continuation_input_tokens: 補続リクエストの入力トークン
input_rate: 入力の単価($/1000token)
output_rate: 出力の単価($/1000token)
"""
# すでに支払った分
previous_cost = (
(previous_input_tokens / 1000) * input_rate +
(previous_output_tokens / 1000) * output_rate
)
# 補続リクエストのコスト(入力のみ、出力は不明)
continuation_cost = (continuation_input_tokens / 1000) * input_rate
return {
"previous_cost_usd": round(previous_cost, 6),
"continuation_cost_usd": round(continuation_cost, 6),
"total_so_far_usd": round(previous_cost + continuation_cost, 6),
"note": "出力コストは補続の応答を得た後に追加される"
}
# 使用例
result = estimate_continuation_cost(
previous_input_tokens=500,
previous_output_tokens=2000,
continuation_input_tokens=250
)
print(result)
実装のベストプラクティス
1. 開発環境で常にトークン計算を有効にする
import os
import tiktoken
# 環境変数で「テストモード」を制御
TEST_MODE = os.getenv("API_TEST_MODE") == "true"
def call_api_with_token_check(messages, model="gpt-4o"):
"""送信前トークン数をチェック"""
enc = tiktoken.encoding_for_model(model)
total_tokens = sum(len(enc.encode(m["content"])) for m in messages)
print(f"[LOG] 予想トークン数: {total_tokens}")
# テストモードなら実際のAPIを呼ばず、推定結果を返す
if TEST_MODE:
print("[LOG] テストモード: APIは呼ばずシミュレーション")
return {"role": "assistant", "content": "[テスト応答]"}
# 本番環境ではここで実際のAPI呼び出し
# response = openai.ChatCompletion.create(...)
2. ログに「予想 vs 実績」を記録
import json
from datetime import datetime
class APICallLogger:
"""API呼び出しのコストを記録"""
def __init__(self, log_file="api_calls.jsonl"):
self.log_file = log_file
def log_call(self, input_tokens, output_tokens, model="gpt-4o", cost_usd=None):
"""1回のAPI呼び出しを記録"""
record = {
"timestamp": datetime.now().isoformat(),
"model": model,
"input_tokens": input_tokens,
"output_tokens": output_tokens,
"cost_usd": cost_usd
}
with open(self.log_file, "a") as f:
f.write(json.dumps(record) + "\n")
def analyze_usage(self):
"""集計結果を表示"""
total_input = 0
total_output = 0
with open(self.log_file, "r") as f:
for line in f:
record = json.loads(line)
total_input += record["input_tokens"]
total_output += record["output_tokens"]
total_cost = (total_input / 1000) * 0.005 + (total_output / 1000) * 0.015
print(f"累計入力トークン: {total_input}")
print(f"累計出力トークン: {total_output}")
print(f"推定累計コスト: ${round(total_cost, 2)}")
3. 予期しない大量リクエストを検知
def safe_batch_api_call(requests, max_cost_usd=10.0):
"""
複数のリクエストを処理する際、コストが予算を超えないようにチェック
Args:
requests (list): { "input": "...", "expected_output_tokens": 100 } のリスト
max_cost_usd (float): 最大許容コスト(ドル)
Returns:
dict: 実行可否と理由
"""
enc = tiktoken.encoding_for_model("gpt-4o")
total_cost = 0
for req in requests:
input_tokens = len(enc.encode(req["input"]))
output_tokens = req.get("expected_output_tokens", 100)
cost = (input_tokens / 1000) * 0.005 + (output_tokens / 1000) * 0.015
total_cost += cost
if total_cost > max_cost_usd:
return {
"can_execute": False,
"reason": f"予算超過: ${round(total_cost, 2)} > ${max_cost_usd}",
"stop_at_request": requests.index(req)
}
return {
"can_execute": True,
"total_cost_usd": round(total_cost, 2),
"requests_count": len(requests)
}
よくあるトークン計算の落とし穴
| 間違い | 問題点 | 対策 |
|---|---|---|
| 文字数でトークン数を推定 | 日本語は1字≠1トークン(実際は多い) | 必ずtiketokenで計算 |
| 同じトークナイザーを再利用しない | モデルごとに異なるため非効率 | グローバル変数・クラス属性で共有 |
| 出力トークンを無視 | 実際のコストより安く見積もる | 過去のログから平均出力トークン数を把握 |
| メッセージのオーバーヘッドを忘れる | 実際より安く見積もる | 4トークン/メッセージを加算 |
| max_tokensをAPIに設定しない | 無限ループで高額課金のリスク | max_tokensパラメータを常に指定 |
| モデルによるトークナイザーの違いを無視 | 同じテキストでもトークン数が異なる | 実際に利用するAPIモデルに合わせて指定 |
実践的なトークン計算チェックリスト
ChatGPT APIを本番環境で利用する前に、以下のチェックリストで確認しましょう。
- ✓ tiketokenをインストールし、送信前にトークン数をカウントする仕組みを導入したか
- ✓ 実装環境と同じモデルのトークナイザーで計算テストを実施したか
- ✓ メッセージのオーバーヘッドトークンを計算に含めているか
- ✓ 大量リクエスト前に試験的に小規模リクエストでトークン数を検証したか
- ✓ 月ごとの予想コストを計算し、予算内に収まっているか確認したか
- ✓ ログ・監視を設置し、予算オーバーの警告を自動化したか
- ✓ テストモードで本番前にシミュレーションを実施したか
参考:Claude APIの公式トークンカウント機能
Claude APIは別ライブラリ不要で、SDKに組み込みのトークンカウント機能があります。
import anthropic
client = anthropic.Anthropic()
def estimate_cost_before_sending(prompt: str, model: str = "claude-sonnet-4-5") -> dict:
"""送信前にトークン数とコストを見積もる"""
count_result = client.messages.count_tokens(
model=model,
messages=[{"role": "user", "content": prompt}]
)
input_tokens = count_result.input_tokens
pricing = {
"claude-haiku-4-5-20251001": {"in": 0.80, "out": 4.00},
"claude-sonnet-4-5": {"in": 3.00, "out": 15.00},
"claude-opus-5": {"in": 15.00, "out": 75.00},
}
estimated_input_cost = (input_tokens * pricing[model]["in"]) / 1_000_000
return {
"input_tokens": input_tokens,
"estimated_input_cost_usd": round(estimated_input_cost, 6),
"model": model
}
# 使用例:送信前にコストを確認
prompt = "以下の契約書を要約してください:" + "..." * 500 # 長文の例
estimate = estimate_cost_before_sending(prompt)
print(f"入力トークン数: {estimate['input_tokens']}")
print(f"予想コスト(入力のみ): ${estimate['estimated_input_cost_usd']}")
if estimate["estimated_input_cost_usd"] > 0.10:
print("⚠️ 想定コストが高額です。送信前に内容を見直してください")
count_tokensはAPIリクエストと同じトークナイザーを使うため、tiktokenのような別ライブラリでの近似計算より正確な見積もりが得られます。
まとめと結論
ChatGPT APIのコスト管理は「運」ではなく「計算」です。tiketokenライブラリを活用することで、APIを実行する前に費用を正確に見積もり、予算超過を防ぐことができます。
以下の流れで実装すれば、ほぼすべての予期しない課金を防げます。
- tiketokenをインストール:
pip install tiktoken - 送信前に必ずトークン数をカウント:
tiktoken.encoding_for_model()を使う - 料金予測ツールを実装:上記の実装パターンから選ぶ
- ログ・監視を設置:予算オーバーの警告を自動化
- テストモードで検証:本番環境に入る前にシミュレーション
特にスタートアップ・個人開発者の場合、毎月の固定予算(例:500円)を決めて、その範囲内でAPIを使うのが現実的です。トークン計算はそうした「予算内での最大活用」を可能にする最強のツールです。手間を惜しまず、今からでも実装することをお勧めします。
あわせて読みたい
- 【2026年版】Claude 3.5 Sonnet料金比較|無料版vs API vs Claude.aiの最安利用法
- 【2026年版】ChatGPT料金プラン比較|無料版vs Plus・Pro・Team選び方
- Claude 3.5 Sonnetの200Kトークンとは?実務活用の5つの使い方