Agentic OS 技術スタックを下から読む 第1回:推論のコストは、黒板で逆算できる
Agentic OS を下から読むなら、最初に見るべきものはモデルの賢さではない。推論の値段と速度である。
Agentic OS を下から読むなら、最初に見るべきものはモデルの賢さではない。推論の値段と速度である。
エージェントの上には、記憶、計画、道具の呼び出し、評価、複数ステップの実行管理が乗る。けれど、どれだけ上の設計を立派にしても、最後はすべてトークンとしてモデルに入り、トークンとしてモデルから出てくる。
普通のチャットより、エージェントはこの制約を強く受ける。過去の作業を長く持つ。道具の結果を文脈に戻す。途中で何度も考え直す。つまり、短い質問に一度答える用途よりも、長い文脈と長い生成を抱えやすい。
だから推論の物理は、上の設計を縛る。どれだけよい記憶システムを作っても、毎回すべてを文脈に詰めれば高くなる。どれだけ精密な計画を立てても、モデルを何百回も呼べば遅くなる。ここを見ないまま上だけを論じると、設計が現実の床から浮いてしまう。
この回で扱うのは、その床である。推論の値段はどこから来るのか。なぜ、細かい実装を知らなくても、黒板の上でおおよその見積もりができるのか。
ルーフラインという見方
GPU は計算が非常に速い。行列計算を大量に並べて処理するための機械だからである。
しかし、計算器が速くなったからといって、メモリからデータを読み出す速度も同じだけ速くなるわけではない。重みやキャッシュはメモリに置かれている。計算するには、まずそれを読まなければならない。
ここで大事なのは、推論の時間を大きく二つに分けて見ることである。
ひとつは計算にかかる時間。もうひとつはメモリから必要なデータを読む時間である。実際の時間は、おおざっぱにはこの二つのうち大きい方で決まる。計算が先に終わっても、メモリ読み出しを待っていれば速くならない。逆に、メモリが間に合っていても、計算が詰まっていればそこが上限になる。
この見方を持つだけで、推論の風景はかなり変わる。モデルを動かすコストは、単に「何回演算したか」だけでは決まらない。多くの生成場面では、計算器そのものより、重みやキャッシュをどれだけ読まされるかが効いてくる。
モデルは頭で考えているように見えるが、機械の側から見ると、大きな重みの塊を何度も読み、過去の文脈のキャッシュを何度もなめながら、次の 1 トークンを出している。
1 トークンの値段を三つに分ける
1 トークンを出す費用は、おおよそ三つに分けられる。
第一に、実際に使う重みに対する計算がある。モデルが次のトークンを出すには、入力を何層ものネットワークに通す。そのとき、実際に活性化して使われる部分が計算量を決める。ここでは「活性パラメータ」と呼んでおく。要するに、その一回の推論で本当に計算に参加する重みの量である。
第二に、重みそのものの読み出しがある。計算に使うには、重みをメモリから読む必要がある。ここで効くのは、実際の計算量とは少し違う。モデルの構造によっては、全体としては巨大でも、毎回使う部分はその一部だけ、という形がある。混合専門家型のモデルがその例である。総量は大きいが、各トークンで動く専門家は限られる。この場合、計算に効く量と、重みをどう読まされるかの量がずれる。ここでは深入りしないが、このずれは後の層を読むときに重要になる。
第三に、KV キャッシュの読み出しがある。これは長い文脈で特に効いてくる。モデルは次のトークンを出すとき、過去の文脈を参照する。その参照を毎回最初から作り直すのではなく、過去トークンごとのキーと値を保存しておく。この保存された束が KV キャッシュである。
この三つを並べると、推論コストの形が見えてくる。
計算は、実際に動く部分に応じて増える。重み読み出しは、モデルの大きさと読み方に応じて増える。KV キャッシュは、バッチの大きさ、文脈長、そして 1 トークンあたりに必要なキャッシュのバイト数に応じて増える。
かなり粗い。しかし、粗いからこそ使える。推論の値段は神秘ではなく、この三つの足し算として見始められる。
バッチが値段を決める
ここでバッチが出てくる。
バッチとは、複数のリクエストをまとめて同時に処理することである。たとえば 1 人のためにモデルの重みを読むのではなく、100 人分をまとめて同じタイミングで処理する。すると、重みを読む費用は 100 人で割れる。
重みの読み出しは大きい。巨大なモデルでは、次の 1 トークンを出すたびに、多くの重みを読む必要がある。これを 1 リクエストごとに単独でやると高い。けれど、同じ重みを使って多くのリクエストを一緒に進めれば、1 人あたりの負担は小さくなる。
電車を思い浮かべるとよい。一定間隔で発車する電車がある。客が 1 人来るたびに電車を出せば、1 人あたりの運行コストは非常に高い。けれど、発車時刻までに来た客をまとめて乗せれば、同じ運行コストを多くの客で割れる。
推論でも同じことが起きる。速く返すモードでは、待てる時間が短い。十分に客を集める前に電車を出すことになる。遅くてもよいモードでは、少し待ってからまとめて処理できる。だから安くできる。
ただし、すべてが割り勘できるわけではない。
重みの読み出しは割り勘しやすい。一方で、計算そのものは各リクエストの分だけ必要になる。KV キャッシュもリクエストごとに固有である。ある人の過去文脈は、別の人の過去文脈として使えない。
ここに境界がある。割り勘できる費用と、リクエストごとに必ず払う費用の境界である。
この境界が、推論サービスの値段を大きく左右する。バッチを十分にまとめられないと、1 トークンあたりの経済性は桁で悪くなりうる。条件によっては、おおよそ最大で千倍近い差が出ても不思議ではない。これは正確な定数の話ではない。構造として、それくらい大きな差が出る余地があるということだ。
だから、推論の値段を見るときは、モデル名だけを見ても足りない。そのトークンが、どれだけうまく他のリクエストと同じ電車に乗れたかを見る必要がある。
KV キャッシュが長文脈の核心になる
長い文脈のコストを考えるとき、KV キャッシュは避けて通れない。
モデルは、次のトークンを出すたびに過去の文脈を見る。過去に出てきたトークンそれぞれについて、注意機構で参照するためのキーと値を持っている。文脈が長くなるほど、この束は大きくなる。
ここで重要なのは、KV キャッシュが薄めにくい費用だということだ。
重みの読み出しは、バッチで割れる。多くのリクエストが同じモデルの同じ重みを使うからである。けれど KV キャッシュは違う。リクエストごとに中身が違う。ある会話の過去文脈は、その会話だけのものだ。別のユーザーの文脈と共有できない。
さらに、長い文脈ではこのキャッシュを読み続けることになる。次の 1 トークンを出すために、過去の大量のキーと値を参照する。文脈が 1 万トークン、10 万トークン、20 万トークンと伸びるほど、メモリ帯域と容量への圧力が増える。
長文脈の限界を語るとき、注意の計算量が文脈長の二乗になる、という説明がよく出てくる。これは仕組みとして間違いではない。だが、生成時の実感に近い制約は、むしろ KV キャッシュのメモリ側にある。過去文脈を保存し、それを読み、GPU 上の限られた高速メモリに載せ続けることが難しくなる。
だから、コンテキスト長が 10 万から 20 万あたりで重くなり、頭打ちに見えるのは自然である。そこには単なるソフトウェア上の上限ではなく、HBM と呼ばれる GPU 側の高速メモリの帯域と容量の壁がある。計算器は速くできても、このメモリを簡単に大きく速くすることはできない。
エージェント設計で長い記憶をそのまま文脈に入れたくなる場面は多い。だが、長文脈は無料ではない。長く持つほど、KV キャッシュという形で毎トークンの生成に効いてくる。
料金表は原価の影を見るための道具になる
API の料金表を見ると、入力トークンより出力トークンの方が高いことが多い。これは偶然ではない。
入力をまとめて読む段階では、モデルは既存のトークン列を一気に処理する。この段階はプリフィルと呼ばれる。多くのトークンをまとめて流せるので、計算器を使いやすい。つまり、計算律速になりやすい。
一方、出力を生成する段階では、1 トークンずつ進む。次のトークンを出し、その結果を受けてまた次を出す。並べて一気に先のトークンを作ることはできない。ここでは重みや KV キャッシュを繰り返し読みながら、少しずつ進む。だからメモリ帯域律速になりやすい。
この違いが、入力と出力の価格差として外に出る。
もちろん、料金表は原価表そのものではない。そこには需給、利益、競争、製品戦略が混ざる。だが、供給側が原価から大きく外れた価格を長く続けるのは難しい。特に推論は競争が激しい。似た品質のモデルを、より安く、より速く出せる相手がいれば、ユーザーはそちらへ流れる。
だから料金表は、内部の制約が外に透けたものとして読める。出力が高いなら、生成側に重い制約がある。長文脈に追加料金があるなら、KV キャッシュやメモリ容量が効いている。速いモードが高いなら、十分なバッチを待てないことが効いている。
価格は単なる商業上の数字ではない。そこには、計算、メモリ、バッチ、キャッシュの影が落ちている。
次回へ
ここまでで見たかったことは一つだけである。
推論コストはブラックボックスではない。おおよそ、メモリ帯域、バッチ、KV キャッシュから逆算できる。正確な数字は実装やハードウェアで変わる。けれど、どこに費用が出るのか、なぜ長文脈が高いのか、なぜ出力が入力より高いのか、なぜ速いモードが高いのかは、黒板の上でかなり説明できる。
ただし、コストの構造が分かることと、GPU を実際に遊ばせず回しきることは別である。
次回は「GPU を遊ばせない」。同じハードのまま生成を速くするために、リクエストをどう流し込み、どう待たせ、どうまとめるのか。連続バッチ処理の話に入る。
← 一覧へ