きっかけ
「Sonnet 5 でトークナイザが変わったらしい。トークン数が増えるぞ」
そんな話を聞いて、身構えました。というのも、Amazon Bedrock 経由のチャットボットを構築していて、ちょうど Sonnet 4.6 から 5 への切り替えを検討していたところだったんです。
しかも、前回痛い目を見たのは、4.5 から 4.6 に上げたとき、出力トークンがドカッと増えてコストが跳ね上がったんですね。あのときは切り替えてから気づきました。(その原因も今回計測しました)
というわけで、今度は先に測ってみることにしました。
結果を先に言うと、日本語については本当に1トークンも変わりませんでした。ただし英語は別の話で、しかも出力側には予想していなかった罠がありました。
まず結論
入力トークン(同じ文章が何トークンに数えられるか)
- 日本語は 1.000 倍。文字通り1トークンも変わりません(散文・カタカナ多め・漢字多め、どれも完全一致)
- 英語は 1.28〜1.46 倍に増えます。Python コードも 1.28 倍
- Sonnet 4.5 と 4.6 は完全に同一でした。試した全テキストで1トークンの差もなし
- おまけの発見として、日英対訳で見た「日本語のトークン数ペナルティ」が 1.92倍 → 1.32〜1.46倍に縮みました。日本語が良くなったのではなく、英語が悪くなった結果です
出力トークン(モデルがどれだけ喋るか)
- 4.5 → 4.6 の激増は再現しました。全7タスクで増加、最大 1.62倍
- 4.6 → 5 はタスクによって増減の向きが逆転します。推論させると短くなり、説明させると長くなる
- そして一番驚いたのが、「出力が3割短くなったのに、トークン数は2%しか減らない」ケースがあったこと
料金は 3モデルとも 3 / 15 $ per MTok で同じなので、トークン数の増減がそのままコストの増減になります。
日本語チャットでの結論: 4.6 → 5 のコスト変動は −7%〜+12% 程度。4.5 → 4.6 のときのような1.4〜1.6倍の激変は起きなさそうです!
測定方法
素朴に測ると間違った答えが出ます。
input_tokens をそのまま比べてはいけない
API が返してくる input_tokens は、自分が送った文章だけの数字ではないみたいです。実際には、
- システムプロンプト
- ツール定義(function calling のスキーマ)
- メッセージの構造そのもの(role の区切りなど、目に見えない制御トークン)
これらが全部合算されています。そしてこれらは、測りたい文章の長さに関係なく一定です。以下これを「固定オーバーヘッド」と呼びます。
どのくらい乗っているか、実際に測ってみました。システムプロンプトをReply with exactly: OK、ユーザーメッセージをhiだけにした状態がこちらです。
| モデル | input_tokens |
|---|---|
| Sonnet 4.6 | 128 |
| Sonnet 4.5 | 157 |
| Sonnet 5 | 172 |
文章の部分は合わせて10トークンくらいのはずなので、残りの 120〜160 トークンは全部オーバーヘッドです。しかもモデル間で 44 トークンもズレている。
これがどうなるのか具体的に見てみます。仮に 400 トークンの日本語テキストを測ったとしましょう。
| 4.6 | 5 | 報告値の比 | |
|---|---|---|---|
| オーバーヘッド | 128 | 172 | |
| テキスト本体 | 400 | 400 | 1.000 |
| 報告される値 | 528 | 572 | 1.083 |
テキストは1トークンも変わっていないのに、「8%増えた」という結論が出てしまいます。
しかも短い文章ほど誤差は大きくなります。100トークンなら 228 対 272 で 1.19倍。……これ、まさに「1.2倍になった」という噂の数字そのものなんですよね。もしかすると噂の一部はこれかもしれません(?)
引き算で消してしまう
対策はシンプルで、同じテキスト T を1回・2回・3回繰り返したものを送って、増分を取るだけです。
T の本当のトークン数 = input_tokens(TT) - input_tokens(T)
固定オーバーヘッドは両方に等しく乗っているので、引き算するときれいに消えます。オーバーヘッドの中身が何なのかを特定する必要すらありません。 文章の長さに依存しないものは、全部消えてくれます。
「ちゃんと消えたか」を確認する方法
この方法には、うれしいことに検算が内蔵されています。
1x→2x の増分と、2x→3x の増分は、一致していなければおかしいんです。もしズレていたら、どこかに長さ依存の何かが混ざっているということになります。
実際にやってみたところ、測定できた全テキストで両者がピタリと一致しました。たとえば英語技術文の Sonnet 5 だとこうです。
1x: 806 トークン
2x: 1443 トークン (増分 637)
3x: 2080 トークン (増分 637)
というわけで、これから出す入力トークンの数字は「だいたいこのくらい」という推定値ではなく、何度測っても同じ数字が出ます。
そのほか気をつけたこと
-
キャッシュ分も足しました。
input_tokens + cache_creation_input_tokens + cache_read_input_tokensの合計を総入力トークン数としています - 日本語と英語は同じ内容の対訳ペアを用意しました。「日本語のほうが長い文章だっただけ」という交絡を避けるためです
-
thinking はオフにしました(
MAX_THINKING_TOKENS=0)。チャットボットに合わせるためですが、レスポンスに thinking ブロックが本当に無いことも目視で確認しています -
出力トークンは確率的なので、各条件 n=8 で平均と標準偏差を出しました。
stop_reasonが全件end_turn(= max_tokens で打ち切られていない)ことも確認済みです
なお計測はAPI で行っています。Bedrock ではない点は最後の注意点をご覧ください。
結果1: 入力トークン
まずは入力から。
| テキスト | 文字数 | Sonnet 4.5 | Sonnet 4.6 | Sonnet 5 | 5 / 4.6 |
|---|---|---|---|---|---|
| 英語・技術文 | 2091 | 437 | 437 | 637 | 1.458 |
| 英語・散文 | 1277 | 282 | 282 | 370 | 1.312 |
| Python コード | 1951 | 562 | 562 | 719 | 1.279 |
| 日本語・技術文 | 911 | 840 | 840 | 841 | 1.001 |
| 日本語・散文 | 546 | 542 | 542 | 542 | 1.000 |
| 日本語・カタカナ多め | 472 | 404 | 404 | 404 | 1.000 |
| 日本語・漢字多め | 379 | 361 | 361 | 361 | 1.000 |
(英語・技術文と日本語・技術文、英語・散文と日本語・散文は、それぞれ同じ内容の対訳です)
日本語、まったくの無風でした。 1.001 になっている技術文も 840 対 841 で1トークンの差しかありません。残り3つは完全一致です。カタカナが多かろうが漢字が多かろうが変わりませんでした。
一方で英語は 1.28〜1.46倍。噂は英語に関しては本当だった、ということになります。
あと当たり前ですがSonnet 4.5 と 4.6 が全テキストで完全一致だったこと。この2つは同じトークナイザですね。
なぜ日本語だけ変わらないのか
「1トークンあたり何文字か」を見ると、答えが見えてきます。
| テキスト | Sonnet 4.6 | Sonnet 5 |
|---|---|---|
| 英語・技術文 | 4.78 文字/トークン | 3.28 |
| 英語・散文 | 4.53 | 3.45 |
| Python コード | 3.47 | 2.71 |
| 日本語・技術文 | 1.08 | 1.08 |
| 日本語・散文 | 1.01 | 1.01 |
日本語はもともと「1文字=ほぼ1トークン」で、すでに文字単位まで分解されきっていたんですね。これ以上悪くなりようがない。
逆に英語は 4.5〜4.8 文字/トークンという効率的な状態から、3.3〜3.5 に落ちています。伸びしろがあったぶん、失うものもあったということかもしれません。
おまけ: 日本語ペナルティが縮みました
同じ内容の対訳ペアで、日本語が英語の何倍トークンを食うかを見てみます。
| Sonnet 4.6 | Sonnet 5 | |
|---|---|---|
| 技術文(日本語 / 英語) | 1.92倍 | 1.32倍 |
| 散文(日本語 / 英語) | 1.92倍 | 1.46倍 |
4.6 では日本語は英語の 1.92倍かかっていました(2つの対訳ペアで見事に一致したのが気持ちいいですね)。それが 5 では 1.32〜1.46倍まで縮んでいます。
……とはいえ、日本語が効率化されたわけではありません。日本語のトークン数は1つも変わっておらず、英語側が悪化しただけです。
結果2: 英語の何が膨らんだのか
英語だけ増えたのはなぜなのか気になったので、1つずつ条件を変えて調べてみました。
| 条件 | Sonnet 4.6 | Sonnet 5 | 倍率 |
|---|---|---|---|
| 頻出英単語400語・小文字 | 401 | 401 | 1.000 |
| 同じ単語を Capitalize(先頭1文字を大文字) | 405 | 647 | 1.598 |
| 同じ単語を UPPERCASE(すべて大文字) | 639 | 1237 | 1.936 |
| 頻出単語+カンマ区切り | 800 | 800 | 1.000 |
| 頻出単語+ピリオド区切り | 800 | 800 | 1.000 |
| 数字列 | 368 | 368 | 1.000 |
| 記号のみ | 1020 | 1180 | 1.157 |
| 英文(折り返しあり) | 282 | 370 | 1.312 |
| 英文(同じ文の折り返しを除去) | 270 | 358 | 1.326 |
| 英文(同じ文を小文字化) | 270 | 356 | 1.319 |
| Python コード(インデントあり) | 562 | 719 | 1.279 |
| Python コード(インデント除去) | 521 | 678 | 1.301 |
わかったことを並べると:
- 改行・インデント・空白は無関係でした。同じ文章の折り返しを取っても倍率はほぼ動きません(1.312 → 1.326)
- 句読点も数字も影響なし。どちらも 1.000 です
- 頻出英単語を並べただけのテキストは 1.000。つまり英語が一律に悪くなったわけではないみたいです
-
大文字がとにかく効きます。頻出単語でも Capitalize で 1.60倍、UPPERCASE だと 1.94倍。UPPERCASE は 1.47文字/トークンなので、ほぼ1文字1トークンまで落ちています
ここで「じゃあ大文字が犯人か」と言いたくなるんですが、実際の英文ではそこまで効きません。実文書を丸ごと小文字化しても倍率は 1.312 → 1.319 とほとんど動きませんでした。英文中で大文字になっている単語なんて数%しかないので、当然といえば当然です。
つまり実文書の 1.3倍を説明しているのは大文字ではない、ということになります。頻出語リストが 1.000 なのに実文書が 1.32 になるので、頻度の低い単語ほど不利になっているのではないかと睨んでいるのですが、そこは詰めきれませんでした。
というのも、中頻度語・低頻度語のリストで検証しようとしたら、単語リストの反復がセーフティ分類器に引っかかってリクエストが通りませんでした(Sonnet 5 can't help with this)。なんでや。
結果3: 出力トークン
さて、ここからは「同じ文章が何トークンになるか」ではなく「モデルがどれだけ喋るか」の話です。4.5 → 4.6 で痛い目を見たのはこっちでした。
システムプロンプトなし、thinking 無効、各条件 n=8 で測っています。
このとき、トークン数だけでなく文字数も記録したのがポイントでした。出力トークン数はトークナイザの影響も受けてしまうので、「本当に短くなった」のか「同じ長さが違う数え方をされただけ」なのかを分けて見る必要があるからです。文字数なら言語に依存しない冗長さの指標になります。
多段階の推論をさせるタスク
| タスク | 4.5 | 4.6 | 5 | 5/4.6 トークン | 5/4.6 文字数 |
|---|---|---|---|---|---|
| 算数(多段階の文章題) | 630±58 | 690±62 | 602±46 | 0.87x | 0.77x |
| 論理パズル(並び順を全列挙) | 820±128 | 996±102 | 794±89 | 0.80x | 0.73x |
| 障害切り分け(401 の原因分析) | 1625±234 | 2103±204 | 2059±194 | 0.98x | 0.71x |
| 合計 | 0.91x | 0.73x |
Sonnet 5 は推論タスクだと、実際に3割ほど短く答えます。 文字数で 0.71〜0.77倍と、かなり安定してこの傾向が出ました。無駄に思考過程を書き下さなくなった、という感じでしょうか。
ところがトークン数はそこまで減らない
ここが今回いちばん面白かったところです。
上の表をよく見ると、文字数比(0.71〜0.77)とトークン比(0.80〜0.98)が一致していません。1トークンあたりの文字数を見ると理由がわかります。
| タスク | 4.6 | 5 |
|---|---|---|
| 算数 | 1.40 文字/トークン | 1.24 |
| 論理パズル | 1.07 | 0.98 |
| 障害切り分け | 1.79 | 1.31 |
障害切り分けタスクが象徴的で、出力が29%も短くなったのに、トークン数は2%しか減っていません(0.98倍)。
なぜかというと、この回答には 401、Cookie、SameSite、それにコード片といった英語・技術用語がたくさん含まれるからだと思われます。結果1で見た英語のトークン効率の悪化が、せっかくの短文化をまるごと食い潰してしまっているわけですね。
日本語で出力させていても、英語の技術用語やコードが混ざる分この影響があります。 逆に、純粋な日本語の説明文であれば短くなった分がそのままコスト減になります。
オープンに説明・列挙させるタスク
| タスク | 4.5 | 4.6 | 5 | 5/4.6 トークン | 5/4.6 文字数 |
|---|---|---|---|---|---|
| 概念の説明(DBインデックス) | 614±69 | 992±187 | 1058±127 | 1.07x | 0.99x |
| 観点の列挙(リモートワーク導入) | 572±46 | 817±74 | 932±104 | 1.14x | 1.09x |
| 短い技術質問(TCPとUDPの違い) | 457±49 | 540±48 | 732±45 | 1.36x | 1.18x |
| 合計 | 1.16x | 1.07x |
推論タスクとは逆に、こちらは増えます。しかもここでも文字数比(1.07倍)よりトークン比(1.16倍)のほうが大きい。文章が長くなった分に、トークナイザによる目減りが上乗せされている格好です。
とくに短い技術質問が 1.36倍と一番悪いのですが、これは回答に TCP、UDP、ACK といった英大文字の略語が多いせいだと思われます。結果2の「大文字が 1.6〜1.9倍になる」がそのまま出力コストに顔を出してきました。英略語が飛び交う技術系チャットは、この点で不利ということになります。
コード生成
| タスク | 4.5 | 4.6 | 5 | 5/4.6 トークン | 5/4.6 文字数 |
|---|---|---|---|---|---|
| コード生成(マージ関数) | 835±109 | 1040±66 | 732±59 | 0.70x | 0.68x |
減少幅は全タスク中で最大でした。3割減です。
4.5 → 4.6 の激増も、しっかり再現
| タスク | 4.5 → 4.6 の出力トークン |
|---|---|
| 算数 | 1.10x |
| 短い技術質問 | 1.18x |
| 論理パズル | 1.21x |
| コード生成 | 1.25x |
| 障害切り分け | 1.29x |
| 観点の列挙 | 1.43x |
| 概念の説明 | 1.62x |
全7タスクで増加していて、とくにオープンな生成タスクで顕著でした。体感どおりです。
そして重要なのは、入力側で 4.5 と 4.6 のトークン数が1トークンも違わなかったこと。つまりこの増加はトークナイザのせいではなく、モデルが純粋に長く喋るようになった結果だと切り分けられます。犯人がはっきりしてスッキリしました。
結局コストは?
日本語チャットでシステムプロンプトも日本語、という前提で整理します。
入力側は完全に無風です。 日本語のシステムプロンプトも、会話履歴も、ユーザーの発話も 1.000倍。入力コストは1円も変わりません。
入力側で影響が出るのは「英語で書かれた固定部分」だけです。英語のシステムプロンプト、英語の few-shot 例、英語の RAG 文書などを積んでいる場合、そこが 1.3〜1.5倍になります。API はステートレスなのでこれらは毎ターン再送されるぶん、効き方は大きくなります(プロンプトキャッシュを使っていれば緩和されます)。
出力側はタスク構成しだいです。1ターンあたり日本語入力1500トークン、出力800トークンという想定で試算してみました。
| 入力 | 出力 | 合計 | 対 4.6 | |
|---|---|---|---|---|
| Sonnet 4.6 | $0.0045 | $0.0120 | $0.0165 | — |
| Sonnet 5(説明・列挙が多い 1.16x) | $0.0045 | $0.0139 | $0.0184 | +12% |
| Sonnet 5(推論が多い 0.91x) | $0.0045 | $0.0109 | $0.0154 | −7% |
というわけで、日本語チャットにおける 4.6 → 5 のコスト変動は −7%〜+12% くらい。 4.5 → 4.6 のときのような1.4〜1.6倍の激変は起きなさそうです。ひとまず安心。
どちらに振れるかはタスク構成で決まります。ユーザーが「考えさせる」質問をするチャットなら安くなり、「説明させる」「列挙させる」チャットなら高くなる、という感じです。
用途別にまとめると:
- 日本語チャット — 入力は影響ゼロ。合計で −7%〜+12% の範囲
- 推論・分析が中心 — 安くなりそう(出力トークン 0.91倍)
- コード生成が中心 — かなり安くなりそう(0.70倍)
- 英略語が頻出する技術系チャット — 出力側で不利。大文字が一番強く効くので
- 英語のドキュメントやコードを大量に入力する用途 — ここが一番影響が大きいです。入力コストが 1.3〜1.5倍に
- コンテキストウィンドウの実効容量 — 英語資料を詰め込む用途では、同じウィンドウサイズでも入る量が3割減ると思っておいたほうがよさそうです
注意点・この検証の限界
最後に、注意点を正直に書いておきます。
- Bedrock ではなくAPI で測っています。 同じモデルなら同じトークナイザのはずですが、そこは確認していません。また Bedrock の料金体系は異なる場合があるので、コスト換算はご自身の料金表でお願いします(多分同じになるはずです)
- トークナイザの中身を見たわけではありません。 API が報告するトークン数を測っただけで、語彙やマージ規則を確認したわけではないので、「なぜそうなるか」の説明は観測からの推測を含みます
- 入力トークンの数字は厳密ですが、出力トークンは確率的です。 出力側は n=8 の平均と標準偏差を併記しました。標準偏差が大きい条件(概念の説明の 4.6 は ±187 あります)では、倍率の差を過信しないほうがよいです
- プロンプトが変われば出力の傾向も変わります。 とくに「簡潔に答えて」のような長さ制約をシステムプロンプトに入れている場合、ここでの数字はそのまま当てはまりません
- 英語が膨らむ原因は特定しきれていません。 大文字が強く効くのは確認できましたが、実文書の 1.3倍の主因は別のところにありそうです
- モデルは今後アップデートされうるので、数値は計測時点のものです
同じようにsonnetモデルのアップデートを検討している方の参考になれば幸いです。