このページの目次
トークンとサンプリング
モデルは文字を読み取るのではなく、トークン単位でデコードします。入力側のサブワード分割がコストの基準を決め、出力側のサンプリング戦略が創造性と決定論を決定します——そして2026年、Claudeとローカルモデルの間でこの両端は分岐しています。
概要
モデルは文字を読み取らず、直接文章を出力もしません。入力側では、テキストは トークン に分割されます。出力側では、モデルは一度に「次のトークンが語彙全体で持つ確率分布」のみを生成し、サンプリング戦略 によって1つが選択され、入力に戻されて自己回帰的に1つずつ生成されます。この両端は普段目に見えませんが、実際の開発で頻繁に直面する3つの事象を決定します:コストが正確に計算できるか(課金単位はトークン)、「創造性」を適切に調整できるか(サンプリング戦略)、そして同じプロンプトでも結果が2回で異なる理由(非決定性)。
さらに重要なのは、この両端に関する「常識」が2026年に分岐したことです。オープンソース/ローカルモデル は依然として temperature/top_p/top_k を使ってサンプリングを調整します(ローカルで動作する Qwen など);一方、Claude のマネージド API は Opus 4.7 からこれらのパラメータを完全に削除 しました——これらのパラメータを送信すると即座に 400 エラーになります。同じ概念でも2つの世界があり、この記事では両端のメカニズムとこの分岐を徹底的に解説します。
入力側:テキストがトークンに変換される仕組み
サブワード分割と BPE
現代の LLM は、文字単位でも単語単位でも分割せず、サブワード で分割します。最も一般的なアルゴリズムは BPE(Byte Pair Encoding) です:トレーニング時には文字から始まり、「最も頻繁に出現する隣接するトークンのペア」を新しいトークンとしてマージし、語彙サイズが設定サイズ(通常は数万〜十几万)に達するまでこれを繰り返します。その結果、高頻度の単語は1つのトークンになり、低頻度の単語は複数のサブワードに分解されます。
現代の実装では、バイトレベル BPE がよく使われます:これは Unicode 文字ではなくバイト に対して BPE を実行します。利点はOOV(未登録語)が存在しないことです——どんな入力(珍しい文字、絵文字、バイナリ列)でもバイトでフォールバックできるため、絶対に分割できないことがありません。代償として、ASCII 以外(中国語、日本語など)の1文字は多くの場合、複数のバイトおよび複数のトークンを占めます。
直感に反するが重要なポイント
- トークン ≠ 単語 ≠ 文字。 英語では約 1トークン ≈ 4文字です。中国語では1文字が通常 1–2+ トークンを占め、コード内の句読点やインデントもトークンを消費します。 文字数で長さを推定すると、体系的に低く見積もってしまいます。
- チャットテンプレートもトークンを消費します。 複数ターン対話では、
roleマーカー、メッセージ区切り文字、ツール定義のスキーマなどがすべて入力トークンに含まれます——本文だけが課金対象ではありません。 - モデル間のトークンは互換性がなく、バージョンによって変動します。 Claude のトークナイザー ≠ OpenAI のトークナイザーです。Claude の見積もりに
tiktokenを使わないでください(15–20% 少なく見積もり、コードや中国語ではさらに顕著です)。同じメーカーでも、モデル世代が変わると変化します:Opus 4.7 のトークナイザーは、同じテキストを前世代の 1.0–1.35 倍のトークン数に分割する可能性があります。モデルを変更する際は基準を再設定する必要があり、古い倍率を適用しないでください。 - 正確に計測するには API を呼び出し、サードパーティの近似器を使わないでください:
# 単一セグメントのカウント
= .
# コストの見積もり(公式価格に基づく、変動あり): input_tokens × 単価
# 2つのバージョンの差分を比較: それぞれカウントして引き算——エンドポイントはステートレスなので、自身で差分を取る
count_tokens はステートレスです。「いくつのトークンが変更されたか」を計算するには、それぞれをカウントして引き算します。
出力側:トークン単位でのサンプリング
モデルが各ステップで出力するのは単語ではなく、語彙全体に対するスコアベクトル(logits) です。これらは softmax によって確率分布に変換され、戦略に従ってサンプリングされ、入力に戻されて再帰的に処理されます——これが自己回帰(autoregressive)です。
flowchart LR
T["テキスト"] --> TK["トークナイザー → トークン"]
TK --> M["モデル (Transformer)"]
M --> L["logits<br/>(語彙内の各トークンに対するスコア)"]
L --> SM["softmax(logits / T)<br/>→ 確率分布"]
SM --> S["サンプリング戦略<br/>top_p / top_k / greedy"]
S --> N["次のトークン"]
N -->|入力に戻し、自己回帰| M
サンプリングのノブ(サポートされているモデルの場合)
| 戦略 | メカニズム | 効果 |
|---|---|---|
| greedy (argmax) | 各ステップで確率が最も高いトークンを取得 | 最も決定論的ですが、繰り返しや劣化に陥りやすい |
temperature T | softmax 前に logits を T で除算 | T>1 は分布を平坦化→よりランダム;T<1 は尖らせる→より集中;T=0 は greedy に退化 |
| top_p (nucleus) | 「累積確率が p に達する最小のトークンセット」のみでサンプリング | 動的に裾を切り捨て、分布の形状に応じて適応 |
| top_k | 確率が最も高い k 個のトークンのみでサンプリング | 固定された切り捨て |
| repetition / presence penalty | 既に出現したトークンの重みを低下 | 繰り返しを抑制 |
| stop sequence | 指定された文字列に一致すると停止 | 出力の境界を制御 |
実務では temperature + top_p の組み合わせ が最も一般的です:温度がランダム性を制御し、nucleus が荒唐無稽な裾を切り落とします。top_k は比較的粗いです。
なぜチャット LLM はビームサーチを使わないのか
古典的な機械翻訳では ビームサーチ(複数の候補パスを同時に維持し、全体として最適なものを選択)が使われます。チャット/オープン生成ではほぼ使われません:これは高確率だが退屈で反復的なテキストを生成する傾向があり(「ニューラルテキストの劣化」)、多様性と自然度を犠牲にします。サンプリング(top_p/温度)は、むしろ人間らしく、情報量豊富なテキストを生成します——これが2020年の nucleus sampling 論文の核心的な結論です。
なぜ T=0 でもバイト単位の再現が保証されないのか
多くの人が「温度 0 = 再現可能」と思っています。できません。 その理由はサンプリングではなく、ハードウェアとスケジューリングにあります:
- 浮動小数点の非結合性: GPU 上の大量の並列加算における累算順序は固定されておらず、浮動小数点では
(a+b)+c ≠ a+(b+c)が成立し、極微小な差異が argmax の臨界点で選択を反転させることがあります。 - バッチ構成: リクエストがどのバッチに組み込まれるか、カーネルのスケジューリング方法が数値に影響します。
- MoE ルーティング: MoE モデル のエキスパート選択は数値により敏感です。
「決定論的」であることは、特定のサンプリングパラメータが保証するものではなく、エンジニアリング上の目標(固定プロンプト、低ランダム性、微小なドリフトを許容)です。
分岐:Claude はサンプリングを削除し、ローカルモデルは依然として使用している
Claude Opus 4.7 / 4.8 / Fable 5 世代に至り、temperature、top_p、top_k が削除されました——送信すると即座に 400 エラーになります。これは退化ではなく、設計思想の変化です:
- 強力な推論モデルにおいて、サンプリング温度を使って「創造性/決定論」を調整しても、そのリターンは限定的で制御不可能です。
- Anthropic は代わりにより高レベルな2つのツールを提供しています:
- プロンプティング——決定論を望む場合は指示を固定し、発散を望む場合はプロンプト内で多様性を明確に要求します(例:フロントエンド設計シナリオでモデルに「まず4つの異なる方向性を提示させてから実装する」よう指示、詳細は移行ドキュメントの design セクションを参照);
- effort(
output_config.effort)——どの程度深く考え、どのくらいのトークンを消費するかを制御します(推論と思考 を参照)。
移行のポイント:旧コードの temperature=0.7 は新モデルで削除し、意図をプロンプト + effort に変換します——temperature=0(決定論を求める)→ effort:"low" + 指示の固定;temperature=高(発散を求める)→ プロンプト内で「複数の異なる方向性を提示する」と明確に記述。この移行レシピは プロンプトエンジニアリングと構造化出力 で展開されます。
しかし他方で、サンプリングは依然として存続しています。 ローカル/オープンソースモデル(llama.cpp、vLLM)はこれらのパラメータを依然として受け付けます——ローカル LLM デプロイ でも設定されています。さらに、モデルカードには推奨値が記載されています:Qwen-AgentWorld の公式推奨は temperature 0.6 / top_p 0.95 / top_k 20 です。つまり、「サンプリングの削除」は Claude マネージド API の思想であり、業界全体の標準ではありません——どの世界にいるかによって、どのルールを使うかを決めます。
ベストプラクティス
- 正確に計測するには
count_tokensを呼び出し、サードパーティの近似器を使わないでください。tiktokenで Claude を見積もると 15–20% 少なく見積もり、中国語/コードではさらに顕著です;チャットテンプレートやツールスキーマもトークンを消費します。 - モデルを変更する際はトークンの基準を再設定してください。 トークナイザーはバージョンによって変動するため、古い倍率を適用しないでください;2つのバージョンの差異を比較するには、それぞれカウントして引き算します。
- どの世界にいるかによって、どのルールを使うかを決めます。 ローカル/オープンソースモデルでは
temperature/top_p/top_kを通常通り調整(モデルカードの推奨値に従う);Claude マネージド API はサンプリングを削除しており、プロンプト + effort を使用します。 - ローカルモデルはモデルカードの推奨サンプリング値を設定してください。 例えば AgentWorld の推奨値は 0.6 / 0.95 / 20 です。デフォルト値で発散度を賭けないでください。
T=0でバイト単位の再現を期待しないでください。 浮動小数点の累算、バッチ処理、MoE ルーティングが変動します;厳密な再現を必要とする場合は結果をキャッシュしてください。
トレードオフと失敗パターン
- 文字数でトークンを推定: 中国語/コードで深刻な過小評価 →
count_tokensを使用し、チャットテンプレート/ツールスキーマを含める。 - モデル間でトークン数や古い温度を適用: トークナイザーとサンプリングの両方が変化する → モデル変更時は基準を再設定し、移行時にサンプリングパラメータを削除。
T=0での再現を期待: バイト単位の一致は不可能 → 固定プロンプト + 低 effort で微小なドリフトを許容;厳密な再現を必要とする場合は結果をキャッシュ。- ローカルモデルで推奨サンプリング値を設定しない: デフォルト温度では発散しすぎたり、鈍感すぎたりする可能性がある → モデルカード(例:AgentWorld の 0.6/0.95/20)に従う。
参考
- Anthropic 公式ドキュメント: トークンカウント、Models API、移行ガイド(サンプリングパラメータの削除)(platform.claude.com)
- 論文: 「Neural Machine Translation of Rare Words with Subword Units」(BPE、Sennrich 2016)、「The Curious Case of Neural Text Degeneration」(nucleus sampling、Holtzman 2020)
- モデルカード: Qwen-AgentWorld-35B-A3B(推奨サンプリング値)
Keywords: tokenization, subword, BPE, byte-level BPE, vocabulary, OOV, chat template, token ≠ word, count_tokens, tiktoken, tokenizer drift, logits, softmax, autoregressive, greedy, temperature, top_p, nucleus sampling, top_k, repetition penalty, stop sequence, beam search, text degeneration, 決定論, floating-point non-associativity, サンプリングパラメータの削除, effort