Skip to content

OpenAI APIでトークンをカウントする方法

問題説明

OpenAIのテキスト生成モデル(GPT-3.5 Turbo、GPT-4など)にはコンテキスト長(例:2049トークン)の制限があります。APIリクエスト時にはmax_tokensパラメータで生成トークン数を指定しますが、次の課題があります:

  • プロンプトに含まれるトークン数を事前に把握できない
  • max_tokens = 最大コンテキスト長 - プロンプトトークン数の計算が事前にできない
  • 長さが異なるテキストを動的に生成する際に制御が困難

この問題を解決するためには、APIリクエスト前に正確にトークン数をカウントする手法が必要です。

基本的な解決策:tiktokenを活用する

OpenAI公式のtiktokenライブラリを使用すると、Python環境で効率的にトークンカウントが可能です。

bash
pip install --upgrade tiktoken

エンコーディングの選択

モデルごとに適切なエンコーディングを選択します(2024年5月現在):

エンコーディング対応モデル例
o200k_baseGPT-4o (gpt-4o)
cl100k_baseGPT-4 (gpt-4), GPT-3.5 Turbo (gpt-3.5-turbo), 埋め込みモデル (text-embedding-3-small等)

トークンカウント基本実装

python
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
python
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の設定例:

python
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ではrolenameもトークン消費するため、単純な文字列カウントでは不正確になります。

公式推奨実装

OpenAIクックブックに基づいた最新の実装方法:

python
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

使用例

python
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
Javajtokkit
PHPGPT-3-Encoder-PHP

よくある質問

Q. API応答のトークン使用量とtiktokenの結果が異なるのはなぜ?

A. 以下の要因により1-2トークンの差が生じる可能性があります:

  • API内部でプロンプトが再フォーマットされる場合
  • 特殊トークンの処理方法の違い
  • モデルバージョンの差異

ベストプラクティス

クリティカルな用途では、常に10%程度の安全マージンを確保してください。例えば2048トークン制限の場合、1843トークンを上限として利用します。

Q. 古いモデル(例:text-davinci-003)もサポートしていますか?

A. p50k_baseエンコーディングが使用可能ですが、2024年現在は新規利用が非推奨です。現行モデルへの移行をお勧めします。

ベストプラクティスまとめ

  1. モデルに対応したエンコーディングを選択 - 常に公式ドキュメントで最新情報を確認
  2. チャットAPIでは専用関数を使用 - メタデータを含む正確なカウントが必要
  3. コンテキスト長の余裕を確保 - 安全マージン10%を目安に
  4. ライブラリを適宜更新 - モデル変更時はトークナイザーの互換性を確認

現在の推奨アプローチはtiktokenライブラリを使用したプログラム的カウントです。動的プロンプトを扱うアプリケーションでは、必ずリクエスト前にトークンバリデーションを行ってください。