トークンの仕組み
この記事では、AIのトークンとはそもそも何なのか、どのような仕組みで動くのかを掘り下げる。
これまで筆者は、AIツールをうまく使う方法や、どのツールがなぜ流行しているのかを主に扱ってきた。ところがトークン節約術をまとめる中で、改めて気づいたことがある。コストの減らし方を語るには、まず「トークンとは何か、どのように課金されるのか」を知る必要があるのに、その土台をきちんと説明したことがなかったのだ。(節約術を書いているうちに、トークンの仕組みだけで一本の記事になる分量になった。)
そこで本稿では、節約術に入る前の基礎を整理する。トークンが単語でも文字でもないなら正確には何なのか(BPE)、どのような姿でモデルに入るのか(embedding)、なぜ入力より出力の方が高いのか(prefill/decode)、prompt cachingが単価を下げる理由はTransformer(ニューラルネットワークの設計)のどこにあるのか(KV cache)、そしてコンテキストが長くなるほどなぜ高くなるのか(注意機構の二乗コスト)を順に見ていく。実践的な節約方法を知りたい場合は、本稿の次にトークン節約術を読んでほしい。
トークンは単語でも文字でもない
まず最も基本的な事実から確認しよう。トークンは単語でも文字でもない。 モデルが学習データに頻出する文字列を圧縮して作った、語彙の単位である。
私たちが「この文は何語あるか」と数える直感と、モデルがテキストを分割する方法は異なる。モデルは頻繁に一緒に現れる文字の組み合わせを一つの単位としてまとめ、入力されたテキストをその語彙に沿って細かく分ける。そのため、同じ一単語でも一つのトークンになるものもあれば、複数に分かれるものもある。
この語彙を作るアルゴリズムが、ほぼすべての現代LLMに共通する基盤であるBPEだ。
BPEアルゴリズム
BPE(Byte Pair Encoding、バイト対符号化)は、隣接して頻出する記号のペアを繰り返し新しい一つの記号へ統合し、語彙を増やしていくアルゴリズムである。
興味深いのは、もともと自然言語処理のために生まれたものではない点だ。BPEは1994年、Philip Gageによってデータ圧縮手法として初めて提案された。データ内で最も頻出するバイト対を未使用の1バイトで置き換え、その置換規則を別の表に保存する圧縮方式だった。
これをニューラル機械翻訳の語彙問題へ持ち込んだのが、エディンバラ大学のSennrichらの研究チームである。2015年に公開され、ACL 2016で発表された「Neural Machine Translation of Rare Words with Subword Units」で、固定語彙では希少語や未知語を扱えないという限界をBPEで解決した。単語全体を覚える代わりに、より小さなサブワードの組み合わせで表せば、語彙にない単語も既知の断片から符号化できるという発想だ。
動作の流れは意外に単純である。
- 最初は一文字ずつを一つのトークンとする。
- コーパス内で最も頻繁に隣接するトークンのペアを探す。
- そのペアを新しい一つのトークンに統合し、コーパス全体で該当ペアを新トークンに置き換える。
- 語彙が目標サイズに達するまで2〜3を繰り返す。
初めは一文字が一トークンだが、やがて「th」「the」「tion」のような頻出する組み合わせが一つのトークンへまとまっていく。よく使われるパターンほど大きな塊になるわけだ。

GPT系は、さらに一歩進んだバイトレベルBPEを使う。テキストを文字ではなくUTF-8のバイト列へ変換してからBPEを適用する方式だ。これにより、基本語彙を256種類(バイトの種類数)から小さく始めながら、UTF-8で表現できるあらゆるテキストを未知トークンなしで符号化できる。絵文字でも漢字でも特殊記号でも、少なくともバイト単位では必ず表現できることが保証される。
同じテキストでもトークン数は違う
この仕組みのため、同じテキストでもtokenizer(人が書いたテキストを、モデルが扱えるトークン単位に分割するツール)によってトークン数は大きく変わる。語彙がどのように学習されたかにより、同じ文が細かくも、大きな塊にも分割されるからだ。

OpenAIがGPT-4oとともに公開した資料を見ると、この差がよく分かる。GPT-4o系の新tokenizerであるo200k_baseは、GPT-4系のcl100k_baseより同じテキストを少ないトークンで表現する。英語では約1.1倍効率的という程度だが、英語以外では差が広がる。公開された短い例文では、中国語と日本語で約1.4倍、韓国語で約1.7倍、ヒンディー語では最大約2.9倍トークンが減った。(韓国語話者にとって、tokenizerの世代差が英語話者より大きく感じられるのは興味深い。)
さらに広く見ると、言語そのものによる格差もある。cl100k_baseで複数言語を比較したYennie Junの分析では、同じ意味の文でも英語はほぼ常に最少トークンで、固有の文字体系を持つ言語ほど長くtokenizeされる傾向がある。ヒンディー語やベンガル語は英語の5倍、ビルマ語は10倍を超えることもある。韓国語や中国語も英語より長くtokenizeされるが、それらの極端な言語ほどではない。
ここから実務上重要な示唆が得られる。AnthropicもOpus 4.7から新しいtokenizerを導入し、公式料金資料に「同じテキストでも従来モデルより最大35%多いトークンとして課金される場合がある」と明記した。単価が同じでも、トークン数が増えれば請求額もそのまま増える。 モデル比較は単価だけでなく、単価×予想トークン数で見る必要がある。
では、分割されたトークンがモデルへ入るとき、文字や単語のまま入るわけではない。トークンはどのような形でモデルに入力されるのだろうか。
トークンがモデルに入るまで
ニューラルネットワークはテキストを直接扱えない。モデルが計算できるのは最終的に数値、より正確にはベクトル(複数の数値を並べた配列)だけだ。そのため、トークンはモデルに入る前にいくつかの段階を経て数値へ変換される。
順に整理すると次のようになる。
- テキスト → トークン:BPE tokenizerがテキストをトークン片に分ける。
- トークン → トークンID:各トークンは語彙内の位置を示す整数IDへ対応付けられる。たとえば
" the"が語彙の1,234番目なら、そのトークンのIDは1234となる。 - トークンID → embeddingベクトル:このIDでembedding行列の該当行を取り出す。embedding行列は
vocabulary size × model dimension (d_model)という大きさの巨大な表で、各トークンIDが一行、つまり一つのベクトルに対応する。このベクトルをトークンの「意味」を表す座標と考えればよい。 - 位置情報を加える:自己注意機構は、それ自体ではトークンの順序を知らない。つまり「私は君が好き」と「君が私は好き」を同じものとして見る。そこで各トークンベクトルへ位置情報を注入し、並び順を教える。
言葉だけでは抽象的なので、この4段階を直接試せる操作ツールを用意した。入力文を変えたりトークンをクリックしたりすると、IDからembeddingベクトルとなり、位置情報が加わって最終入力ベクトルになるまでの流れを追える。(表示する次元数は減らしているが、実際のGPT-4のベクトルは12,288次元であることを念頭に置いて見てほしい。)
ここでモデル次元(d_model)とは、一つのトークンを表現するベクトルの長さである。元祖Transformer論文では512だったが、現在のLLMははるかに大きい。(Llama 2の7Bモデルでも4,096次元ある。)モデル次元が大きいほどトークンの微妙な意味の違いを豊かに表せる一方、計算量とメモリも増える。

位置情報を注入する方法も世代によって変わった。元祖Transformerは正弦・余弦関数で作った位置ベクトルをembeddingへそのまま加えたが、現在の公開LLMで事実上の標準となったRoPE(Rotary Position Embedding、回転位置embedding)は、Query/Keyベクトルを回転させ、注意機構の計算時に相対位置を注入する。(方式は違っても「Transformerに順序感覚を持たせる」という目的は同じだ。)
まとめると、テキスト → トークン → トークンID → embeddingベクトル(+位置情報)→ Transformer入力という流れである。請求書にある「トークン数」とは、この流れの二番目、つまりテキストがいくつのトークンに分割されたかを数えたものだ。
ここまでで、トークンがどう作られ、どんな姿でモデルに入るかが分かった。ではモデル内部で処理されるとき、入力と出力のコストはなぜこれほど違い、同じ入力を繰り返し送るコストはどう減らせるのだろうか。
入力が安く、出力が高い理由
トークンを扱った人なら一度は疑問に思うはずだ。料金表を見ると、出力トークンは入力トークンの数倍も高い。 Anthropicでは、全モデルで出力単価が入力単価のちょうど5倍である。(Opusは入力$5/出力$25、Haikuは入力$1/出力$5。)同じ一トークンなのに、入るときと出るときでなぜ価格が違うのか。
答えは、モデルが入力と出力のトークンをまったく異なる方法で処理するからだ。LLM inferenceは二段階に分かれる。
- prefill(入力処理):プロンプトとして入った全トークンをまとめて並列に処理する。1,000トークンでも10,000トークンでも、GPUが一度に走査して各トークンのK/V(Key/Value)を計算する。演算量は多いが、並列処理できるためトークン当たりの効率がよい。
- decode(出力生成):応答トークンを一度に一つずつ順番に作る。一つ生成したら入力へ追加し、次のトークンを生成する。応答が終わるまでこれを繰り返す。
この非対称性がコスト差を生む。Databricksの推論性能分析によれば、prefillは演算律速の段階で、decodeはメモリ帯域律速の段階だ。decodeでは一トークンを作るたび、モデルの全重みをGPUメモリから再び読み込む必要があるのに、一回で得られるのは一トークンだけである。GPUの膨大な演算能力の大半が遊んでいることになる。(Databricksの表現を借りれば、GPUを動かす料金を払いながら、使える演算能力を使えていない状態だ。)
つまり、入力トークンは並列prefillでまとめて効率よく処理される一方、出力トークンは一つずつ非効率に絞り出さなければならない。 料金には需要や利益率など商業的要因も含まれるだろうが、技術的にはdecode段階の非効率が背景にある。したがって「出力を短くする」という節約原則は、単なる助言ではなく、最も高価な段階を減らすことなのだ。
では、この非効率なdecodeを少しでも改善する方法はないのか。そこで登場するのがKV cacheである。
キャッシュが単価を下げる仕組み
prompt cachingは静的な入力を一度キャッシュへ保存し、次の呼び出しでは大幅に安い料金で読み出す仕組みだ。Anthropic公式資料では、キャッシュ読み出しは基本入力単価の0.1倍、つまりちょうど10%である。キャッシュ書き込みは5分TTL(Time To Live、キャッシュの有効期間)で1.25倍、1時間TTLで2倍になる。最初の呼び出しで少し多く払い、二回目以降は90%安くなる構造だ。
だが、なぜ90%も安くできるのか。そして「接頭部が完全に一致しなければならない」という条件はなぜそれほど厳しいのか。Transformerの内部を見れば、どちらの答えも明確になる。
KV cache
モデルは入力トークンを処理するとき、各トークンに対応するQuery/Key/Value(Q/K/V)ベクトルを作る。自己注意機構はQueryとKeyの内積で注意スコアを計算し、そのスコアを重みとしてValueの加重和を作って出力する。一つのトークンがほかのトークンを「どの程度参照するか」を決める計算だと考えればよい。
先ほど見たdecode段階は、まさにここで問題になる。新しいトークンを一つ作るたび、それ以前の全トークンのK/Vが必要だが、毎回最初から計算すると同じK/Vを際限なく重複計算することになる。

KV cacheは、この重複をなくすために導入された。一度計算したK/Vを保存し、新しいトークンを生成するときは先行トークンのK/Vを再計算せず、キャッシュから読み出して再利用する。これにより、一つの系列内でトークンを一つ追加生成するコストは、各段階で全体を再計算するO(n²)から、キャッシュを読むだけのO(n)へ下がる。(厳密には一段階当たりのコストだが、要点は「計算済みのものは再計算しない」という単純な発想である。)decodeがメモリ律速なのも、各段階でこのKV cacheをメモリから読み直す必要があるためだ。
呼び出し間での再利用
KV cacheがもともと一つの応答生成中のdecodeを高速化する仕組みなら、prompt cachingはこのメモリ構造を一回の呼び出し内だけでなく、呼び出しと呼び出しの間でも再利用するという発想だ。
静的な接頭部(システムプロンプト、ツール定義、コード断片など、毎回ほぼ同じ冒頭部分)のK/Vを5分または1時間のTTL中GPUメモリに保持する。次の呼び出しが同じ接頭部で始まれば、その部分のK/V計算を丸ごと飛ばし、キャッシュから直接読み出して使う。正確には入力トークンの単価が魔法のように下がるのではなく、そのトークンを計算するGPUの仕事そのものが消える。 90%の値下げは、省かれた計算を料金に反映した結果なのだ。
この仕組みを理解すれば、「接頭部が完全一致しなければならない」という条件が厳しい理由も自然に分かる。キャッシュヒットは接頭部を累積的にハッシュ化した値が一致するかで判定されるが、自己注意機構には因果性があるため、前のトークンが一つでも変われば後続する全トークンのK/Vも変わる。プロンプトの先頭に時刻情報を一行置くだけでも、呼び出すたび値が変わって接頭部のハッシュが一致せず、それ以降のキャッシュ全体が無効になる。
Anthropicのキャッシュはtools → system → messagesの階層順に読み込まれる。したがって先頭側のツール定義が一つ変わるだけでも、その後のキャッシュ全体が無効になる。結論は単純だ。静的なものを前に、毎回変わる動的なものを後ろに置けばキャッシュが生きる。
キャッシュにはあまり知られていない制約もある。キャッシュ可能な最小トークン数はモデルごと、同じ系列内でもバージョンごとに異なる。それより短いプロンプトはキャッシュを有効にしても、通知なく保存されない。(この最小トークン数と提供元ごとのキャッシュ方針はコスト設計に直結するため、トークン節約術の記事で料金表とともに詳しく扱った。)
コンテキストウィンドウがトークン上限を生む理由
最後に、トークンを語るうえで欠かせない概念がコンテキストウィンドウである。モデルが一度に受け取れるトークン数の上限を指す。なぜこの上限があるのかを理解すれば、「コンテキストが長いほど高くなる」というよくある警告の正体も明らかになる。
鍵は自己注意機構の計算構造にある。注意機構では、すべてのトークンがほかのすべてのトークンを一度ずつ参照する。トークンがn個ならトークンの組はn × n、つまり自己注意機構の計算量とメモリは系列長nの二乗に比例して増える。 トークンが2倍になれば注意機構のコストは4倍になる。(モデル全体がO(n²)なのではなく、注意機構の段階がそうである点は明記しておきたい。)

この二乗増加がどれほど急かは、Hugging Faceの推計がよく示している。最適化なしの標準的な注意機構では、注意スコア行列を保存するだけでも、入力1,000トークンなら約50MBで済むが、16,000トークンでは約19GB、100,000トークンではほぼ1TB必要になる。
さらに、先ほどのKV cacheもトークン数に比例してメモリを消費する。コンテキストが長くなるほど保持すべきK/Vが線形に積み上がる。つまりコンテキストウィンドウの上限とは、「これ以上長くなるとメモリと計算が耐えられない」という物理的な限界にモデルが引いた線なのだ。
だから長い会話をそのまま引き継ぐことは、単に入力トークン数を増やすだけの問題ではない。注意機構のコストは二乗で増え、トークン数が上限に近づくほどモデルが情報を正確に扱う能力も落ちる。(この精度低下は、節約術の記事で扱ったコンテキスト劣化と直結する。コンテキストを軽く保つことがコストと正答率の両方に効く理由がここにある。)
まとめ
ここまでを整理すると、トークンの仕組みはいくつかの単純な事実に集約できる。トークンはBPEが頻出パターンをまとめて作った語彙の単位であり、トークンIDを経てembeddingベクトルへ変換され、モデルに入る。入力は並列prefillでまとめて処理できるが、出力は一トークンずつ絞り出すため高く、その非効率を和らげるのがK/Vを再利用するKV cacheだ。キャッシュが単価を下げるのは魔法ではなく、Transformerが計算済みのK/Vを再計算しないからであり、接頭部が完全一致しなければならない厳しい条件もこの構造から直接導かれる。そしてコンテキストが長いほど高くなるのは、注意機構のコストがトークン数の二乗で増えるためだ。
この基礎を知れば、コストの話はずっと明快になる。出力がなぜ高いのか、キャッシュを壊さないためプロンプトをどう配置すべきか、なぜコンテキストを軽く保つべきか、同じ答えならなぜ安いモデルへ移るべきかといった節約戦略は、すべてこの原理の上に立っているからだ。仕組みを知りたくてここまで読んだ方には、続けてトークン節約術を読み、これらの原理が実際のコストをどう削減するか確かめてほしい。
참고 자료
📚関連記事
AIトークン節約術
2026/6/11 · 51 min read
今回は、AIトークンを節約する方法について考えてみたい。 以前は性能やコストよりも、結果とプロセスに意識を向けていた。AIの成果物には穴が多く検証が欠かせなかったうえ、早く結果を出したい一心で、筆者を含む多くの人がトークン不足のたびに追加料金を払い、より上位のプランを使っていた。筆者も同じだった。(実のところ、最初の数か月はトークンにいくらかかっているかさえ気にしていなかった。) ところが、しばら...
AIエージェントツール
2026/5/29 · 58 min read
今回の記事では、AIコーディングエージェントを取り巻くツールエコシステムについて考えてみたい。 筆者はフロントエンド開発者として働きながら、日常的にClaudeを活用している。そうしているうちに、いつの間にかプロジェクトルートにCLAUDE.mdができ、その隣には誰かが作ったAGENTS.mdがあり、.cursorrulesも片隅に残り、どこかで読んだ記事に倣って.claude/skills/フォ...
AIフロントエンドエンジニア
2026/3/2 · 45 min read
今回の記事では、AI時代にエンジニアがどのように成長し、生き残れるのかについて、個人的な視点から考えてみたい。 筆者がジュニアだった頃、特に印象深く読んだ記事の一つに、ペ・フィドンさんの「フロントエンドエンジニアのキャリアロードマップ、ジュニアのための3つの専門性トラック」がある。フロントエンドエンジニアのキャリアを、Web特化(Software Engineer)/プロダクト特化(Product...