TL;DR(要点): 長いエージェント型コンテキストは、H200上でGLM-5.3を2つの限界に押し上げます。KVキャッシュのメモリとプレフィル速度です。我々は16基のH200(1つのプレフィルノードと1つのデコードノードに分割)でこの両方に対処しました:
- Prefill Context Parallelism(PCP) は各プロンプトをヘッドではなくトークン単位でGPUに分割します。これはテンソル並列よりもGLM-5.3のスパースアテンションにはるかに適しています。
- Decode Context Parallelism(DCP) はプレフィルエンジンのKVキャッシュをトークン単位でシャーディングするため、1Mのコンテキストがプレフィルノードに収まります。
- Hybrid HiSparse により、デコードはKVをホストメモリに保持できるため、1Mトークンのリクエストが収まります。
- AgentXでは、Hybrid HiSparseデコードと組み合わせたPCP8 × DCP8プレフィルにより、同じスループットのデータ並列デプロイのユーザーあたり速度の1.7~3.2倍が得られ、テストした構成の中で1Mトークンのコンテキストを提供できるのはこの構成だけです。
メモリが制約されたデプロイでの長いコンテキストの提供
エージェント型ワークロードはターンごとに増大する長いコンテキストを持ち、GPUメモリとプレフィルの両方に負荷をかけます。H200上では、GLM-5.3の重みが各GPUのメモリの大部分を占めるため、これらの長いコンテキストのKVキャッシュ用の空きはわずかです。また、すべてのターンがプレフィル対象のツール出力やファイル内容を増やすため、負荷がかかるとプレフィルエンジンがデプロイ全体のボトルネックになる可能性があります。
第1部 では、Hybrid HiSparseが長いコンテキストを単一の8× H200ノード上の集約デプロイに収める方法を示しました。プレフィル/デコード分離にはさらに多くの工夫が必要です。プレフィルノードでは、PCPを使ってプロンプトのトークン間で並列化することにより、長いプロンプトを高速化します。しかしMLAでは、これによりすべてのPCPランクがKVキャッシュの完全なコピーを保持することになるため、DCPと組み合わせてその重複を排除します。デコードノードでは、Hybrid HiSparseにより長いコンテキストでの高い同時実行数が可能になります。vLLMの新しいモジュラーコア(Model Runner V2)により、これらすべてを組み合わせることがはるかに容易になります。
なぜTPやDPではないのか?
8× H200ノード上でGLM-5.3のプレフィルを実行する標準的な2つの方法はDP8とTP8です:
- DP8 は各プロンプトを単一のGPUに割り当てるため、そのアテンションは他の7つのGPUを利用できません。これは長いプロンプトの最初のトークンまでの時間(TTFT)を制限し、プロンプトのKVキャッシュはそのGPUのメモリに収まらなければなりません。
- TP8 はアテンションヘッドをGPU間で分割します。MLAの潜在KVは64個すべてのヘッドで共有されるため、すべてのGPUが完全なキャッシュを格納し、8ヘッドに対応するためだけにそれを読み取ります。スパースMLAがアテンションする2,048個のトークンを選択するために、それ以前のすべてのトークンをスコアリングするインデクサーはまったく分割されないため、その二乗オーダーのコストがすべてのGPUで繰り返されます。
どちらの方式も、長いプロンプトのアテンション処理を8つのGPUに分散させながら、それに対応する各GPUにKV全体を保持しないようにすることはできません。次の2つのセクションでそれぞれの半分に対処します。PCPはプロンプトのクエリをGPU間で分割し、DCPはそのKVを分割します。
PCP:ヘッドではなくトークンを分割する
我々の8× H200プレフィルエンジンでは、PCPは各プロンプトを8つのGPUにトークン単位で分割します。すべてのGPUが64個すべてのヘッドで、プロンプトの8分の1のクエリを計算します。単純な分割では不均衡になります。因果アテンションでは、あるトークンはそれより前のすべてのトークンにアテンションするため、プロンプトの終わりを保持するGPUは始まりを保持するGPUよりはるかに多くの処理を行うことになります。そこでPCPは代わりにプロンプトを16個のチャンクに切り、それらをペアにします。GPU は先頭からチャンク を、末尾からチャンク を受け持つため、すべてのGPUが同じ割合で安価なトークンと高価なトークンを受け取ります(図3はこれを8つのGPUにわたるV字型のパターンとして示しています)。これは、 Context Parallelism for Scalable Million-Token Inferenceからの負荷分散シャーディングです。最後に、各GPUの新しいKVはall-gatherされるため、すべてのクエリが引き続き完全なコンテキストにアテンションできます。
図1はこの2つの分割を比較したものです。PCPは両方の問題を解決します。各GPUは自分のトークンのみをインデックス化するため、インデクサーは各GPUで複製されなくなり、各GPUはその8分の1を処理します。また、メモリから読み取られる各KV行が8ではなく64個すべてのヘッドに対応するため、スパースMLAは移動バイトあたり約26から約191 FLOPsに向上し、1 H200がBF16で計算律速になる地点に近づきます。2
インデクサーを複製しないことが最も重要になるのは、長いプリフィルの場合です。インデクサーのコストはプロンプト長に対して二次的に増加するのに対し、スパースMLAでは各クエリが固定の2,048トークンにのみ注意を向けるため、線形にしか増加しません。ゼロからプリフィルのFLOPsを数えると、プロンプトが約32Kトークンに達した時点で、TP8ではインデクサーがスパースMLAを上回ります。一方、どのGPUもインデクサーを複製しないPCP8では、交差点は約256Kまで後ろにずれます。
これらを合わせると、PCPは長いプロンプトのプリフィルに非常に適しています。しかし、PCPには依然として2つのコストがあります。各GPUはすべてのアテンション重みを保持する一方、MoEエキスパートはEP8によって8つのGPUに分割されたままです。また、新しいKVが毎レイヤーでall-gatherされるため、すべてのGPUが結局はKVキャッシュ全体を保存することになります。この複製されたキャッシュこそが、計算ではなく、コンテキスト長を制限する要因であり、それこそがDCPが取り組む対象です。
DCP: KVキャッシュもシャーディングする
1MトークンのGLM-5.3リクエストには、FP8 KVで53.4 GiBが必要であり、3 ただし各GPUには約15 GiB分の余裕しかありません。 Decode Context Parallelism (DCP)は、キャッシュそのものを分割することでこれを解決します。トークンを8基のGPUにラウンドロビンで割り振り、各GPUは8トークンごとに1つを保存するので、同じリクエストでもGPUあたり6.7 GiB(=53.4/8)で済みます。図2でこれをDP8やTP8と比較しています。
注: PCPはクエリを分割し、DCPはKVを分割します。 この名前は歴史的なものです。DCPはdecode用に作られました。decodeでは各リクエストのクエリトークンが1つなので、KVキャッシュだけが分割する価値のあるものだからです。PCPはprefill用に作られました。prefillではプロンプトの多数のクエリトークンこそが処理の対象だからです。私たちのセットアップでは、prefillエンジンで両方を実行しています。
このシャーディングの結果、各GPUのクエリが必要とするKVの大部分は、他のGPU上に存在することになります。decodeでは、DCPはクエリをKVのもとへ送ります。各GPUは自分のシャードに対してattentionを行い、部分的な結果をlog-sum-expで統合します。このprefillエンジンではその逆を行います。毎レイヤー、各GPUはシャードをall-gatherして一時的なフルコンテキストのコピーを作り、自分のクエリに対するattentionを行い、そのコピーを解放します。永続的なキャッシュだけが8で分割されます。
図3に全体をまとめました。PCP8 × DCP8の1レイヤーをステップ実行して、各GPUがどのKVを保存し、どのクエリを計算し、何がインターコネクトを横断するかを確認できます。比較のためにDP8、TP8、PCP8に切り替えてください。2つのレイアウトは整列していないことに注意してください。GPU は8トークンごとに1つを保存しますが、チャンク と のクエリを計算します。これが毎レイヤーでall-gatherが必要な理由です。
そのall-gatherは無料ではありません。毎レイヤーでキャッシュされたコンテキスト全体を再送するため、そのコストはコンテキスト長に伴って増加します。図4は、同じ2Kトークンのprefillチャンクを、同一のキャッシュ済みコンテキストで、DCP8ありとなしの1つのPCP8ノード上で実行することで、これを切り分けています。DCP8はステップあたり約6%のオーバーヘッドを64Kトークンのコンテキストまでで加え、248Kでは15%に上昇します。それが8倍のKVプールを得るための代償です。このオーバーヘッドは、各レイヤーのall-gatherを前のレイヤーの計算とオーバーラップさせることで削減できる可能性があり、現在その最適化に取り組んでいます。
およそ250Kトークンを超えると、PCP8だけではKVキャッシュを保持できません。そこではDCPはオーバーヘッドではなく、長いプロンプトを可能にするものです。PCP8 × DCP8を組み合わせることで、prefillエンジンに速度と容量の両方をもたらします。
デプロイ構成
私たちはこれを、2つの8× H200ノード上のprefill/decode(P/D)分離型デプロイとして提供しています。両エンジンともFP8 KVキャッシュと、3つのドラフトトークンを持つMTP投机デコーディング(MTP3)を使用します:
- Prefill: 1つのPCP8 × DCP8 × EP8エンジンで、512 GiBのCPU KVオフロードを備え、後続のターンがプレフィックスを再利用できるようにしています。
- Decode: EP8とHybrid HiSparseを備えた8つのDPランクによる Part 1 (ランクあたり48 GiBのホストプール + 16 GiBのオフロード)によるEP8とHybrid HiSparseを備えた8つのDPランクで、decodeの同時実行数はHBMではなくホストメモリによって制限されます。
プレフィックス対応の llm-d ルーターが各リクエストをprefillエンジンへ送り、NIXLコネクタがそのKVキャッシュをdecodeランクへ移動し、decodeランクがトークンをストリーミングで返します。
私たちはPCP8 × DCP8 prefillをDP8 prefill(EP8とそれぞれ64 GiBのCPU KVオフロードを備えた8つのDPランク、合計は同じ512 GiB)と比較し、decodeノード上でHybrid HiSparseを通常のCPU KVオフロードと比較しました。ホストメモリはどちらも同じ512 GiBです(HiSparseでは8 × 48 GiBのHiSparseプール + 8 × 16 GiBのオフロード)。すべての構成が同じ16 GPU、ホストメモリ、vLLMビルドを使用しています。
結果
私たちはSemiAnalysisの AgentX ベンチマークを実行しました。プレフィックス再利用ありでClaude Codeのトレースを再生し、同時実行数ごとに新しいサーバーを起動し、1時間の実行、そして合成acceptance長を2.99に固定したMTP3を使用して、すべての構成が同じ投机的高速化を得られるようにしました。スループットはGPUあたりの論理tok/s(キャッシュ済みを含む)です。つまり、プレフィックスキャッシュされた入力を含む入力トークンと出力トークンの合計を、16 GPUすべてで割ったものです。インタラクティビティはAgentXのユーザーあたりのP90 E2E正規化出力トークン/sであり、図5のx軸です。
c32まではデプロイは主にprefill律速なので、prefillerが大きな差を生みます。両セットアップでHiSparse decodeを使うと、PCP8 × DCP8 prefillは同じスループットでDP8の1.7〜3.2倍のインタラクティビティを実現し、中央値TTFTを1.5〜5.2秒から0.8〜0.9秒に短縮します。この負荷ではdecoderの違いはほとんど影響しません。c8とc16では2つのPCP8 × DCP8構成は数パーセント以内の差であり、c8ではオフロードのみのdecodeがわずかに先行しています。
c32からはデプロイがよりdecode律速になり、HiSparse decodeが優位に立ちます。c64ではスループットがほぼ2倍の8,340論理tok/s/GPU(29.6 tok/s/user)に達し、他のすべての構成は1〜2 tok/s/userに低下します。
1Mコンテキストの場合、デプロイには両方が必要になります。DP8のプリフィルランクは1Mトークンのリクエストを1つも保持できず、オフロード専用のデコードランクも同様に保持できません。
すべてを組み合わせ可能にする
vLLMにおける難しい作業の多くは、このような機能を組み合わせ可能にすることです。各機能はKVキャッシュの配置、スケジューリング、または移動の方法を変えるため、あらゆる組み合わせが正確かつ高速に動作し続けなければなりません。
P/Dでは、KVは2つのエンジン間でレイアウトを変更する必要があります。プリフィルエンジンは、各リクエストのKVをトークンごとに8つのGPUにシャーディングします。各デコードランクは、MTPレイヤーのKVを含むKV全体を、独自のページドレイアウトで保持する必要があります。NIXLコネクタが2ノード間でこの再構築を行い、CPUオフロードからのプレフィックス再利用はそれと並行して動作し続けなければなりません。
ここにあるすべての設定は次で動作します Model Runner V2. これにより、モデル固有の状態が共通の実行パスから排除され、CPUとGPUの同期なしで投機的デコーディングを実行します。Hybrid HiSparseはこれを基盤として構築されています。
試してみる
すべて vLLM v0.32.0 以降で動作します( vllm/vllm-openai:v0.32.0 画像)。上記の結果は、vLLM main の 9e38b4111a。 転載の要点 ピン 2537629eb2。プリフィルエンジンの主要なフラグ:
--prefill-context-parallel-size 8 \
--decode-context-parallel-size 8 \
--dcp-comm-backend ag_rs \
--enable-expert-parallel \
--attention-config '{"sparse_mla_force_mqa":true}'Without sparse_mla_force_mqaプロンプトが2,048トンのtop-k以内に収まるプリフィルバッチは、dense MHAパスを通ります。このフラグはこれらもsparse-MLA(MQA)カーネル上に留めるため、すべてのKV行が全ヘッドに対応します。
謝辞
この作業は、Roberto L. Castro(Red Hat)、Simon Veitner(Red Hat)、Matthew Bonanni(Red Hat)、Lucas Wilkinson(Red Hat)、Nicolò Lucchesi(Mistral)によって行われました。デプロイのストレステストを実施し、エラーを報告し、バグを修正してくれたMaroon Ayoub(Red Hat)とRobert Shaw(Red Hat)に感謝します。
備考
脚注
-
クエリごとに、スパースMLAは660バイトのKV行を選択して2,048行読み込みます(FlashMLAのFP8 KVのうち656バイト分…
fp8_ds_mlaフォーマット+4バイトのインデックス)で約1.35 MB。各ヘッドはBF16のクエリと出力のために2,176バイトを追加し、1行あたり2,176 FLOPsを実行する(QKは576次元、PVは512次元)。したがって8ヘッドでは1.37 MBに対して35.7 MFLOPs、約26 FLOPs/バイト、64ヘッドでは1.49 MBに対して285 MFLOPs、約191となる。 ↩ -
H200 SXMの場合: 989 dense BF16 TFLOP/s(データシートの1,979は2:4スパーシティを前提) 4.8 TB/s 1バイトあたり206 FLOPs(NVIDIA H200 データシート). ↩
-
トークンあたり: MLA KVで78層 × 656 B、インデクサーキーで21層 × 132 B(128個のFP8値と4バイトのスケール)、さらにMTP層用に788 B、合計54,728 B。 = 1,048,576 トークンの場合、54,728 MiB、すなわち約 53.4 GiB となります。 ↩