OpenAI APIでトークンをカウントする方法
問題説明
OpenAIのテキスト生成モデル(GPT-3.5 Turbo、GPT-4など)にはコンテキスト長(例:2049トークン)の制限があります。APIリクエスト時にはmax_tokens
パラメータで生成トークン数を指定しますが、次の課題があります:
- プロンプトに含まれるトークン数を事前に把握できない
max_tokens = 最大コンテキスト長 - プロンプトトークン数
の計算が事前にできない- 長さが異なるテキストを動的に生成する際に制御が困難
この問題を解決するためには、APIリクエスト前に正確にトークン数をカウントする手法が必要です。
基本的な解決策:tiktokenを活用する
OpenAI公式のtiktoken
ライブラリを使用すると、Python環境で効率的にトークンカウントが可能です。
pip install --upgrade tiktoken
エンコーディングの選択
モデルごとに適切なエンコーディングを選択します(2024年5月現在):
エンコーディング | 対応モデル例 |
---|---|
o200k_base | GPT-4o (gpt-4o ) |
cl100k_base | GPT-4 (gpt-4 ), GPT-3.5 Turbo (gpt-3.5-turbo ), 埋め込みモデル (text-embedding-3-small 等) |
トークンカウント基本実装
import tiktoken
def count_tokens(text: str, encoding_name: str) -> int:
"""文字列のトークン数をカウント"""
encoding = tiktoken.get_encoding(encoding_name)
return len(encoding.encode(text))
# 使用例
print(count_tokens("こんにちは、世界!", "cl100k_base")) # 出力: 5
import tiktoken
def count_tokens(text: str, model_name: str) -> int:
"""モデル名を指定してトークン数をカウント"""
encoding = tiktoken.encoding_for_model(model_name)
return len(encoding.encode(text))
# 使用例
print(count_tokens("自然言語処理のテスト", "gpt-4o")) # 出力: 7
max_tokensの自動計算
コンテキスト長を考慮したmax_tokens
の設定例:
def calculate_max_tokens(prompt: str, model: str) -> int:
"""プロンプトトークンを考慮したmax_tokens値を計算"""
# モデルのコンテキスト長を取得
CONTEXT_LENGTHS = {
"gpt-3.5-turbo": 4096,
"gpt-4": 8192,
"gpt-4o": 128000
}
prompt_tokens = count_tokens(prompt, model)
return CONTEXT_LENGTHS.get(model, 4096) - prompt_tokens - 100 # 安全マージンを確保
チャットAPI向けのトークンカウント
チャット形式(メッセージリスト)のリクエストでは、メタデータを含む特別なカウントが必要です。
注意点
チャット補完APIではrole
やname
もトークン消費するため、単純な文字列カウントでは不正確になります。
公式推奨実装
OpenAIクックブックに基づいた最新の実装方法:
import tiktoken
def count_chat_tokens(messages: list, model: str) -> int:
"""チャットメッセージの総トークンをカウント"""
try:
encoding = tiktoken.encoding_for_model(model)
except KeyError:
encoding = tiktoken.get_encoding("cl100k_base")
# モデルごとの設定値
if model in {"gpt-3.5-turbo-0613", "gpt-4-0613", "gpt-4o"}:
tokens_per_message = 3
tokens_per_name = 1
else:
# 互換性(一部旧モデル用)
tokens_per_message = 4
tokens_per_name = -1
token_count = 0
for message in messages:
token_count += tokens_per_message
for key, value in message.items():
token_count += len(encoding.encode(value))
if key == "name":
token_count += tokens_per_name
token_count += 3 # アシスタントのプレフィックス
return token_count
使用例
messages = [
{"role": "system", "content": "あなたは日本語のアシスタントです"},
{"role": "user", "content": "トーキョーの天気は?"}
]
print(f"総トークン数: {count_chat_tokens(messages, 'gpt-4o')}")
主要プログラミング言語のライブラリ
Python以外の言語では以下のライブラリが利用可能です:
言語 | ライブラリ例 |
---|---|
Node.js | @dqbd/tiktoken, gpt4-tokenizer |
.NET/C# | SharpToken, TryAGI.Tiktoken |
Java | jtokkit |
PHP | GPT-3-Encoder-PHP |
よくある質問
Q. API応答のトークン使用量とtiktokenの結果が異なるのはなぜ?
A. 以下の要因により1-2トークンの差が生じる可能性があります:
- API内部でプロンプトが再フォーマットされる場合
- 特殊トークンの処理方法の違い
- モデルバージョンの差異
ベストプラクティス
クリティカルな用途では、常に10%程度の安全マージンを確保してください。例えば2048トークン制限の場合、1843トークンを上限として利用します。
Q. 古いモデル(例:text-davinci-003)もサポートしていますか?
A. p50k_base
エンコーディングが使用可能ですが、2024年現在は新規利用が非推奨です。現行モデルへの移行をお勧めします。
ベストプラクティスまとめ
- モデルに対応したエンコーディングを選択 - 常に公式ドキュメントで最新情報を確認
- チャットAPIでは専用関数を使用 - メタデータを含む正確なカウントが必要
- コンテキスト長の余裕を確保 - 安全マージン10%を目安に
- ライブラリを適宜更新 - モデル変更時はトークナイザーの互換性を確認
現在の推奨アプローチはtiktoken
ライブラリを使用したプログラム的カウントです。動的プロンプトを扱うアプリケーションでは、必ずリクエスト前にトークンバリデーションを行ってください。