※この記事は、個人技術ブログ CodeArchPedia.com の技術メモ(要約)です。
現場でOpenAI APIを多用していると、チャット履歴が長くなった際や、大規模なテキスト処理を行った際に、予期せぬコスト超過やContext Windowエラーに遭遇することがある。特にプロダクション環境で安定運用を目指すなら、リクエスト前にトークン数を正確に見積もる仕組みが必須になる。以前は簡単な文字数ベースの自作関数を使っていたが、それではモデルが解釈するトークン数と乖離が大きすぎた。
何が起きたか(課題)
OpenAI APIを利用する上でのコストと安定性の課題は明確だった。
- 意図しないトークン超過による高額請求のリスク。
- GPT-4などでは特に、システムメッセージや会話構造による隠れたオーバーヘッドが発生し、簡易な文字数カウントではエラーを予見できない。
- 最大トークン制限を超過した場合、リクエスト全体が400エラーとなり、処理が中断してしまう。
どう解決したか(概要)
解決の鍵は、OpenAI公式のtiktokenライブラリを導入し、モデルが実際に使用するトークン数を完全に再現すること。特にチャット形式のメッセージリストを扱う際には、モデル固有のオーバーヘッドを考慮に入れる必要がある。
まず、テキスト単体であればencoding_for_modelでエンコーディングを取得し、.encode()でトークン数をカウントする。この基本をマスターした上で、実践的な課題であるチャットメッセージのカウントに対応した。モデルバージョン(例: gpt-4oやgpt-3.5-turbo-0613)ごとに異なるオーバーヘッド(tokens_per_messageやtokens_per_name)を考慮したヘルパー関数を作成し、メッセージリスト全体(role, content)を正確に計算できるようにした。
さらに、制限超過を防ぐため、トークン数が閾値を超えそうになったら、最も古いメッセージ(通常は最初のユーザー/アシスタントのやり取り)を削除するダイナミック・トリミング戦略を実装した。これにより、常に最新の会話を維持しつつ、上限内に収める制御を実現した。
テキスト単体のカウント例
import tiktoken
encoding = tiktoken.encoding_for_model("gpt-3.5-turbo")
token_count = len(encoding.encode(text))
チャット形式のメッセージカウントの概要
モデルバージョンを指定し、メッセージ構造体(role, content)をループ処理し、モデル固有の定数(tokens_per_messageなど)を適用して合計を算出する。
効果(Before/After)
| 項目 | 対策前(簡易カウント) | 対策後(tiktoken利用) |
|---|---|---|
| トークン予測精度 | 約70%〜85%程度 | 99%以上の精度を達成 |
| エラー発生率 | 月に数回(予期せぬオーバーフロー) | ゼロに抑制 |
| コスト管理 | 不安が伴う | 予算内に収まる安定運用 |
正確なカウント基盤を構築したことで、リクエスト前に安全マージンを設定でき、意図しないコスト増大やリクエスト失敗を劇的に減らすことができた。特に日本語の長いプロンプトを扱う際に、この精度の差は顕著に出る。
🚀 詳細な設定とコードはこちら
具体的なWAFのルール設定や、より詳細なログ解析データは元のブログで公開しています。