LLM推論コストとの戦い
LLMの推論コストは、プロダクション運用における最大の課題の一つだ。GPT-4oのAPI料金は下がったとはいえ、月間数百万リクエストの規模では依然として月額数万ドルの費用がかかる。自社でモデルをホスティングする場合も、A100やH100の調達コストとGPU利用効率の最適化が避けられない。
KGAでは2025年前半からvLLM v0.6系とTensorRT-LLM v0.12系の両方を本番環境で運用している。結論から言えば、ワークロードの特性によって最適な選択は変わる。この記事では実測データに基づいて判断材料を提供する。
vLLMのPagedAttention: 何が革新的なのか
vLLMの中核技術であるPagedAttentionは、OSの仮想メモリ管理をKVキャッシュに応用したものだ。従来の推論エンジンでは、各リクエストにmax_seq_len分のKVキャッシュメモリを事前確保していた。つまり最大4096トークンの設定なら、実際の入力が100トークンでも4096トークン分のメモリを専有する。これは典型的なワークロードで60-80%のメモリが無駄になることを意味する。
PagedAttentionはKVキャッシュを固定サイズのブロック(デフォルト16トークン)に分割し、必要に応じて動的に割り当てる。物理メモリ上では不連続なブロックを論理的に連続したシーケンスとして扱う。これにより実効的なバッチサイズが2-4倍に拡大し、同一GPUでのスループットが大幅に向上する。
KGAの実測では、Llama 3.1 70BをA100 80GB x4でtensor parallel実行した場合、vLLMのスループットは従来のHugging Face text-generation-inferenceの約2.8倍だった。
TensorRT-LLMのアプローチ: コンパイル時最適化
TensorRT-LLMはNVIDIAのアプローチで、モデルを事前にコンパイルして最適化する。FP8量子化、カーネルフュージョン、Flash Attention 2の統合により、単一リクエストのレイテンシでは最速クラスだ。
Llama 3.1 70BをH100 x4でtensor parallel実行した場合のTTFT(Time To First Token)は、TensorRT-LLM FP8で平均85ms、vLLMではFP16で平均140ms。ただしこれは単一リクエストの数値で、高負荷時のバッチ処理効率ではvLLMが逆転する。
TensorRT-LLMの最大の難点はビルドプロセスの複雑さだ。モデルの変換、エンジンのビルド、quantizationの設定など、デプロイまでに数時間から半日を要する。vLLMなら python -m vllm.entrypoints.openai.api_server --model ... で即座に起動できるのとは対照的だ。
continuous batchingの実装差
両フレームワークともcontinuous batching(動的バッチング)をサポートしているが、実装に重要な差がある。vLLMはイテレーションレベルのスケジューリングを採用し、各デコードステップごとにバッチの構成を変更できる。リクエストの完了と新規リクエストの追加がデコードステップ単位で行われるため、GPUの遊び時間が最小化される。
TensorRT-LLMのin-flight batchingも同様のコンセプトだが、prefill(入力処理)とdecode(出力生成)のスケジューリングポリシーがより明示的に制御できる。prefill-heavyなワークロード(長い入力、短い出力)ではTensorRT-LLMのチューニングが効果を発揮する。
KVキャッシュの実践的な管理
KVキャッシュのメモリ管理は推論パフォーマンスの生命線だ。vLLMではgpu_memory_utilizationパラメータ(デフォルト0.9)でKVキャッシュに割り当てるGPUメモリの割合を制御する。KGAでは0.92に設定している。0.95以上にするとOOM(Out of Memory)のリスクが高まるため推奨しない。
プレフィックスキャッシュも重要な最適化だ。vLLM v0.5以降でサポートされたAutomatic Prefix Cachingにより、共通のsystem promptを持つリクエスト群でKVキャッシュを再利用できる。同一system promptの繰り返しリクエストでTTFTが40-60%改善される。チャットボットやAPIサーバーなど、system promptが固定のユースケースでは必ず有効にすべきだ。
ベンチマーク: 本番ワークロードでの比較
KGAの本番環境を模したワークロード(平均入力500トークン、平均出力800トークン、同時接続50-200)での比較結果を示す。
スループット(トークン/秒、H100 x4): vLLM FP16は毎秒約12,500トークン。TensorRT-LLM FP8は毎秒約15,800トークン。TensorRT-LLM FP16は毎秒約13,200トークン。
P99レイテンシ(同時接続100時): vLLMは4.2秒。TensorRT-LLM FP8は3.1秒。TensorRT-LLM FP16は3.8秒。
GPU利用率: vLLMは平均87%。TensorRT-LLM FP8は平均92%。
TensorRT-LLM FP8が数値上は最強だが、デプロイの複雑さ、モデル更新時の再ビルド時間、デバッグの困難さを考慮すると、多くのチームにはvLLMを推奨する。KGAでは、レイテンシ要件が厳しいリアルタイム対話系にはTensorRT-LLM、それ以外のバッチ処理やAPI提供にはvLLMという使い分けをしている。
運用で学んだこと
半年間の運用で最も痛い経験をしたのは、vLLMのメモリリーク問題だ。v0.5.xの特定の条件下で、長時間運用するとKVキャッシュの解放が不完全になりスループットが徐々に劣化する現象に遭遇した。v0.6.2で修正されたが、それまでは12時間ごとのローリングリスタートで対処していた。推論サーバーのメトリクス(GPU memory usage、batch size、queue depth)の監視は必須だ。Prometheusエンドポイントを活用し、異常検知のアラートを設定することを強く推奨する。