ストーリー
トークンの仕組みと計算方法
トークンとは
LLMはテキストを「トークン」という単位に分割して処理します。トークンは単語や部分文字列に相当し、言語によって分割方法が異なります。
| 言語 | 1トークンの目安 | 例 |
|---|---|---|
| 英語 | 約4文字(0.75単語) | “Hello” = 1トークン |
| 日本語 | 約1-3文字 | ”東京” = 1-2トークン |
| コード | 変数名・記号単位 | console.log = 2-3トークン |
トークン数の計算
# OpenAI tiktokenによるトークン計算の例
import tiktoken
encoder = tiktoken.encoding_for_model("gpt-4o")
# 英語
english_text = "What is the capital of Japan?"
english_tokens = encoder.encode(english_text)
print(f"英語: {len(english_tokens)} tokens") # 約7トークン
# 日本語
japanese_text = "日本の首都はどこですか?"
japanese_tokens = encoder.encode(japanese_text)
print(f"日本語: {len(japanese_tokens)} tokens") # 約12トークン
# 日本語は英語の1.5-2倍のトークンを消費する
APIリクエストのトークン構成
1回のAPIリクエストのトークン構成:
┌─────────────────────────────────────┐
│ システムプロンプト 800 tokens │ ← 毎回固定で送信される
│ RAGコンテキスト 1,000 tokens │ ← 検索結果の量に依存
│ 会話履歴 500 tokens │ ← ターン数に比例して増加
│ ユーザー入力 200 tokens │ ← ユーザーの質問
├─────────────────────────────────────┤
│ 入力合計 2,500 tokens │
├─────────────────────────────────────┤
│ 出力(モデル応答) 500 tokens │ ← モデルが生成する部分
└─────────────────────────────────────┘
合計: 3,000 tokens/リクエスト
入力トークンの大部分はシステムプロンプトとRAGコンテキストだ。ユーザー入力は全体の10%以下。つまり削減余地はプロンプト設計にある。 — 田中VPoE
プロンプトエンジニアリングによるトークン削減
1. システムプロンプトの最適化
冗長なシステムプロンプトはコストを押し上げます。
| テクニック | 削減効果 | 説明 |
|---|---|---|
| 不要な指示の削除 | 10-20% | モデルがデフォルトで従う指示を省く |
| 箇条書きへの変換 | 15-25% | 長文の説明を箇条書きに圧縮 |
| 定型文の短縮 | 10-15% | 繰り返しの表現を簡潔にする |
| 英語での記述 | 30-40% | 日本語より英語の方がトークン効率が良い |
最適化前(1,200トークン):
あなたは弊社のカスタマーサポート担当のAIアシスタントです。
お客様からの質問に対して、以下のルールに従って回答してください。
まず、お客様の質問内容を正確に理解してください。
次に、提供されたコンテキスト情報から関連する情報を探してください。
回答は丁寧で分かりやすい日本語で行ってください。
技術的な専門用語は避け、一般的な言葉で説明してください。
もし回答に自信がない場合は、「確認いたします」と答えてください。
...(以下、詳細な指示が続く)
最適化後(500トークン):
Role: カスタマーサポートAI
Rules:
- コンテキストに基づき回答
- 丁寧な日本語、専門用語を避ける
- 不明な場合「確認いたします」と回答
- 回答は200字以内
Output: JSON {answer, confidence, source}
削減率: 約58%
2. Few-shotの最適化
| アプローチ | トークン数 | 品質への影響 |
|---|---|---|
| Few-shot 5例 | +2,000トークン | 高品質だがコスト大 |
| Few-shot 2例 | +800トークン | 多くの場合十分な品質 |
| Zero-shot + 明確な指示 | +0トークン | タスクによっては十分 |
| 動的Few-shot | +400-800トークン | 質問に最も近い例のみ選択 |
# 動的Few-shot: 質問に類似した例のみ選択する
def select_examples(query: str, examples: list, top_k: int = 2) -> list:
"""
ユーザーの質問に最も類似した例をtop_k件選択する。
全例を毎回送るのではなく、関連性の高い例のみ送ることで
トークン数を削減しつつ品質を維持する。
"""
query_embedding = embed(query)
similarities = [
(ex, cosine_similarity(query_embedding, embed(ex["question"])))
for ex in examples
]
similarities.sort(key=lambda x: x[1], reverse=True)
return [ex for ex, _ in similarities[:top_k]]
3. コンテキスト圧縮
RAGで取得したコンテキストを圧縮することで、入力トークンを大幅に削減できます。
| 手法 | 削減率 | 品質への影響 | 実装コスト |
|---|---|---|---|
| チャンクサイズ最適化 | 20-30% | 低い | 低い |
| 関連度スコアによるフィルタリング | 30-50% | 中程度 | 低い |
| LLMによるコンテキスト要約 | 50-70% | 要検証 | 中程度 |
| Extractive圧縮(重要文抽出) | 40-60% | 低い | 中程度 |
# 関連度スコアによるコンテキストフィルタリング
def filter_context(
retrieved_docs: list,
relevance_threshold: float = 0.7,
max_tokens: int = 1000
) -> str:
"""
関連度が閾値以上のドキュメントのみを
トークン上限内で返す。
"""
filtered = [
doc for doc in retrieved_docs
if doc.relevance_score >= relevance_threshold
]
context = ""
current_tokens = 0
for doc in filtered:
doc_tokens = count_tokens(doc.content)
if current_tokens + doc_tokens > max_tokens:
break
context += doc.content + "\n"
current_tokens += doc_tokens
return context
モデル選定戦略
タスク別の適切なモデルサイズ
すべてのタスクに最高性能モデルを使う必要はありません。タスクの複雑さに応じてモデルを選定します。
| タスクの複雑さ | タスク例 | 推奨モデルサイズ | コスト目安 |
|---|---|---|---|
| 低 | FAQ応答、定型文生成、分類 | 小(GPT-4o mini, Haiku) | $0.15-0.80/1M |
| 中 | 要約、翻訳、コードレビュー | 中(GPT-4o, Sonnet) | $2.50-3.00/1M |
| 高 | 複雑な推論、創造的な文章、戦略分析 | 大(GPT-4o, Opus) | $2.50-15.00/1M |
| 特殊 | 画像解析、音声処理 | 専用マルチモーダルモデル | タスク依存 |
モデル選定マトリクス
品質要求
低 中 高
┌────────┬────────┬────────┐
低 │ Flash │ Flash │ Mini │
コ │ ¥0.5/ │ ¥0.5/ │ ¥1/ │
ス 中 │ Mini │ Sonnet │ Sonnet │
ト │ ¥1/ │ ¥5/ │ ¥5/ │
許 高 │ Mini │ Sonnet │ Opus │
容 │ ¥1/ │ ¥5/ │ ¥20/ │
度 └────────┴────────┴────────┘
(¥は1,000リクエストあたりの概算)
モデルルーティング
ルーティングの仕組み
ユーザーの質問の複雑さに応じて、自動的に適切なモデルにルーティングする仕組みです。
ユーザーの質問
│
▼
┌──────────────┐
│ ルーター │ ← 質問の複雑さを判定
│ (小モデル) │
└──────┬───────┘
│
├── 簡単な質問(70%)──→ 小モデル(Haiku/Mini) → 低コスト
├── 普通の質問(20%)──→ 中モデル(Sonnet/4o) → 中コスト
└── 複雑な質問(10%)──→ 大モデル(Opus/4o) → 高コスト
コスト削減効果:
全件を大モデルで処理: 100% × $10 = $10/1Kリクエスト
ルーティング後: 70% × $1 + 20% × $5 + 10% × $10 = $2.7/1Kリクエスト
削減率: 73%
ルーターの実装パターン
| パターン | 仕組み | 精度 | コスト |
|---|---|---|---|
| キーワードベース | 特定キーワードでルーティング | 低い | ほぼゼロ |
| 分類モデル | 軽量な分類モデルで複雑さを判定 | 中程度 | 極めて低い |
| LLMルーター | 小モデルで質問の複雑さを判定 | 高い | 低い |
| ハイブリッド | キーワード + LLMの組み合わせ | 高い | 低い |
# LLMルーターの実装例
from enum import Enum
class ModelTier(Enum):
SMALL = "haiku" # 簡単な質問
MEDIUM = "sonnet" # 普通の質問
LARGE = "opus" # 複雑な質問
async def route_query(query: str) -> ModelTier:
"""
小モデル(Haiku)を使って質問の複雑さを判定し、
適切なモデルにルーティングする。
"""
routing_prompt = """
Classify the complexity of this question:
- SIMPLE: FAQ, factual lookup, yes/no questions
- MEDIUM: summarization, comparison, explanation
- COMPLEX: multi-step reasoning, creative tasks, analysis
Question: {query}
Classification (SIMPLE/MEDIUM/COMPLEX):
"""
# ルーティング自体は最小モデルで実行(コスト: ~$0.001/リクエスト)
result = await llm_call(
model="haiku",
prompt=routing_prompt.format(query=query)
)
tier_map = {
"SIMPLE": ModelTier.SMALL,
"MEDIUM": ModelTier.MEDIUM,
"COMPLEX": ModelTier.LARGE,
}
return tier_map.get(result.strip(), ModelTier.MEDIUM)
バッチ処理とストリーミングの使い分け
リアルタイム vs バッチの判断基準
| 観点 | リアルタイム(ストリーミング) | バッチ処理 |
|---|---|---|
| ユースケース | チャットボット、対話型UI | レポート生成、大量データ処理 |
| レイテンシ要求 | 即時応答が必要 | 数分〜数時間の遅延許容 |
| コスト | 通常料金 | 割引あり(OpenAI Batch APIは50%OFF) |
| スループット | 1リクエストずつ | 数千リクエストを一括 |
| エラーハンドリング | 即座にリトライ | バッチ単位でリトライ |
バッチAPIの活用
# OpenAI Batch APIの例
import json
# バッチリクエストの作成
batch_requests = []
for i, document in enumerate(documents):
batch_requests.append({
"custom_id": f"doc-{i}",
"method": "POST",
"url": "/v1/chat/completions",
"body": {
"model": "gpt-4o-mini",
"messages": [
{"role": "system", "content": "文書を要約してください。"},
{"role": "user", "content": document}
],
"max_tokens": 200
}
})
# JONLファイルとして保存
with open("batch_input.jsonl", "w") as f:
for req in batch_requests:
f.write(json.dumps(req) + "\n")
# バッチジョブの送信
# 通常料金の50%でバッチ処理が実行される
# 結果は24時間以内に返却
コスト最適化の判断フロー
リクエストの性質を判定:
│
├── リアルタイム応答が必要?
│ ├── Yes → ストリーミングAPI
│ │ └── モデルルーティングを適用
│ └── No → バッチ処理検討
│ ├── 24時間以内で良い?
│ │ ├── Yes → Batch API(50%割引)
│ │ └── No → 通常APIで処理
│ └── 定期実行?
│ ├── Yes → スケジュールバッチ
│ └── No → オンデマンドバッチ
まとめ
| ポイント | 内容 |
|---|---|
| トークン削減 | プロンプト最適化だけで30-50%のトークン削減が可能 |
| モデル選定 | タスクの複雑さに応じてモデルを使い分ける |
| モデルルーティング | 質問の複雑さで自動振り分けし、コストを最大73%削減 |
| バッチ処理 | リアルタイム不要な処理はBatch APIで50%コスト削減 |
チェックリスト
- トークンの仕組みと日本語でのトークン効率を理解した
- プロンプトエンジニアリングによるトークン削減手法を理解した
- タスク別のモデル選定戦略を理解した
- モデルルーティングの仕組みと実装パターンを理解した
- バッチ処理とストリーミングの使い分けを理解した
次のステップへ
次は「キャッシュ戦略とRAG最適化」です。同じ質問には同じ回答を返すキャッシュ戦略と、RAGの検索効率を最適化する手法を学びましょう。
推定読了時間: 30分