分離型推論、第 1 回:いつ、どこへルーティングするか
GPU が高稼働なのにユーザーが遅さを感じるなら、問題は容量ではなく、同じハードウェアでプリフィルとデコードを混在させていることにあります。

コーディングアシスタントが、関数を生成している途中で途切れます。GPU 使用率は 92%。容量を増やしても改善しません。
一つの GPU が、根本的に異なる二つの仕事をしようとしています。プリフィル、つまりプロンプトの読み込みは Tensor コアを使い切ります。デコード、つまりトークンを一つずつ生成する処理はメモリに制約され、コアの大半は遊休状態です。同じカード上で動かすと、新しいプロンプトが来るたびに、生成中のデコードが止まります。ユーザーにはトークンの出力間隔の揺れとして見えますが、ダッシュボードには成功と表示されます。
一般的な答えは分離です。一方の GPU プールでプリフィル、別のプールでデコードを行い、その間で KV キャッシュを転送します。多くの記事はそこで終わります。しかし重要なのはその先です。いつ分離の手間をかける価値があるか、どう適切な GPU にリクエストを届けるか、どうデコードを止めずにキャッシュを届けるか、そしてなぜネットワークスタックが期待に応えられなくなるのかです。
全 3 回の第 1 回となる本記事は、最初の二つを扱います。 分離に価値がある場面と、適切な GPU へリクエストを届ける方法です。第 2 回ではキャッシュの受け渡し、第 3 回ではデータプレーンを取り上げます。
分離が手間に見合うのはいつか
効果が逆転する点は、モデルのサイズと並列化のトポロジーによります。DistServe は、単一の A100 上の 13B モデルでは、入力が約 512 トークンを超えるとプリフィルの計算能力が制約になると報告しています。Splitwise は、BLOOM-176B では 1,500 トークンのプロンプトのプリフィルに、出力わずか 6 トークンのデコードと同じ時間がかかることを示しています。一般的な RAG やエージェントのリクエストは、既に大部分がプリフィルのワークロードです。Sarathi-Serve は、中程度の規模ならプリフィルをチャンク化し、同じ GPU 上でデコードと交互に実行することで対処します。それを超えると、チャンク自体がデコードに大きな揺れを生み、物理的な分離が有利になります。
LLM 推論には、重要なレイテンシ指標が二つあります。最初のトークンまでの時間(TTFT)と、出力トークンあたりの時間(TPOT)です。プリフィルをチャンク化した一体型のサービングは、最初のトークンが速く届けば TPOT の揺れを許容できる場合に機能します。しかし、リアルタイム音声、コードの自動補完、会話型エージェントでは、TPOT の制約が厳格です。トークン間に 200ms の間隔があれば、ユーザーはすぐに気づきます。TPOT が厳しい場合、プリフィルのバーストをデコードのストリームから物理的に分離することで、干渉を根本から取り除けます。
導入を決める前に、転送の追加コストを計算してください。FP16 の Llama-70B では、KV キャッシュはトークンあたり約 320 KB です。10,000 トークンのプロンプトは 3.2 GB の KV キャッシュを生み、生成開始前に転送しなければなりません。100 Gbps では TTFT に約 250ms が加わります。分離が有利なのは、この 250ms が、干渉によって既に生じているテールレイテンシより短い場合です。長いコンテキストを扱う RAG なら、ほぼ確実にそうなります。
チャット型のワークロードでは、プリフィルとデコードを独立に拡張できる点も、分離を後押しします。ピーク時のトラフィックは偏ります。長いストリーミング回答のためデコード容量が大幅に増える一方、追加の質問が短く、プレフィックスの再利用が多ければ、新しいプリフィルはほとんど増えないことがあります。一体型クラスターは両段階を一緒に拡張する必要がありますが、分離型なら独立に拡張できます。Microsoft の Splitwise 論文では、対称的な一体型構成に対して、ハードウェアコストを 20% 下げつつスループットを 1.4 倍にできたと報告しています。デコード中心のワークロードでは、同じ電力予算で 2.35 倍です。クラスター全体では大きな金額になります。
リクエストを適切な GPU へ届ける方法
プリフィルとデコードを別のプールに置くと、リクエストごとに二つのスケジューリング判断が必要です。どのプリフィルノードがプロンプトを処理し、どのデコードノードが引き継ぐかです。適切に行うには、一体型サービング以上の仕組みが必要です。
標準的な設計は二段階の階層構造で、Splitwise が最も明確に説明しています。クラスターレベルのスケジューラーがプリフィルとデコードのプールにリクエストを振り分け、各 GPU のマシンレベルのスケジューラーが、既に担当しているリクエストの継続的バッチ処理とメモリページングを扱います。分けるのは、二つの判断の時間スケールが違うためです。全体のルーティングには数十ミリ秒の判断時間を使えますが、ローカルのバッチ処理はマイクロ秒単位で動き、ネットワークの往復を待てません。統合すると、バッチ処理には遅すぎるか、適切にルーティングするには視野が狭すぎるスケジューラーになります。
興味深いのは、クラスターレベルのスケジューラーがどうノードを選ぶかです。ラウンドロビンや最小負荷への割り当てといった単純なルーティングは、各ノードの HBM に何があるかを無視します。複数ターンの会話、システムプロンプトが大きいワークフロー、少数例をテンプレートに含むエージェントでは、新しいプロンプトのトークンの多くが、既にどこかのノードで処理されています。キャッシュを認識するルーターは、それを見てプレフィックスを持つノードに送ります。再計算がなくなり、TTFT が大幅に下がります。
NVIDIA の Dynamo ルーターは、簡潔なコスト関数でこれを実装しています。
Cost = (Overlap Score Weight × Prefill Blocks) + Decode Blocks
Prefill Blocks は、対象ワーカーで新たに計算する必要があるトークン数を、ブロックサイズで割った値です。プロンプトの 90% が既にキャッシュにあれば、この値はゼロに近づき、スコアは大きく下がります。Decode Blocks は、そのワーカーが現在どれほど生成を行っているかを示す負荷のシグナルで、キャッシュが温まった一つのノードへの集中を防ぎます。Overlap Score Weight が調整項目です。高くするとキャッシュの局所性と TTFT を優先し、低くすると負荷を均等化して、時折のキャッシュミスと引き換えにトークン間のレイテンシを安定させます。TTFT に厳しいコーディングアシスタントなら高く、TTFT の許容幅が広いバッチ要約パイプラインなら低く設定します。
このルーティングの重要性は、想像以上です。本番環境では、キャッシュを認識するルーティングにより、KV キャッシュのヒット率が最大 87.4%に達したと報告されています。単純な方式では事実上ゼロです。クラスターが行う GPU 計算を、桁違いに削減できます。
キャッシュを認識するルーティングだけが有効な設計ではありません。DistServe は、別の選択をします。実行時のルーターを、FCFS、プリフィルは最短キュー、デコードは最小負荷という単純なものに保ち、導入前に実行する配置アルゴリズムへ知的な処理を集約します。ワークロードの分布、SLO、クラスターのトポロジーを入力し、シミュレーションによって最適な並列化戦略とインスタンス数を求めます。実際の SLO 達成率は、閉形式でモデル化するには複雑すぎるワークロード分布に依存するためです。ShareGPT 型のトラフィックで OPT-175B を動かした際は、人手では見つけにくいと論文が述べる並列構成に到達しました。ネットワークも考慮します。ノード間の帯域幅が限られるとき、DistServe は同じステージのプリフィルとデコードのセグメントを一つのノードに同居させ、KV 転送を遅い Ethernet ではなく NVLink に載せます。適切なルーティング戦略は一律ではなく、プロンプトのばらつき、プレフィックスの再利用、相互接続の品質によって変わります。
ルーティングは、どの GPU がリクエストを扱うかを決めますが、KV キャッシュを実際にどう移すかまでは決めません。いつ送信を始めるか、ホップ間ではどこに置くか、リクエストをまたいでどう再利用するか。受け渡し自体が独立した問題です。これらはオーケストレーションの問いであり、実際の性能の大部分を決める場所でもあります。
次回、第 2 回:デコードを止めずに KV キャッシュを移動する