Level 3:推論サーバーを選ぶ
Inference Serving
Ollama・vLLM・SGLangのどれで動かす?
Level 2で、Nortiaはモデル・精度・ハードの組み合わせをPoC候補3案まで絞りました。残っているのは「そのモデルを、何で動かすのか」です。
ここは軽視されやすい工程です。モデルとGPUが決まれば性能も決まる、と考えてしまうからです。しかし実際には、同じモデルを同じGPUに載せても、動かすソフトウェア次第で捌ける人数が一桁変わります。
このLevelで扱う範囲
推論サーバー(推論エンジン、Serving Framework)とは、モデルをメモリに載せ、複数のリクエストをスケジューリングし、APIとして公開するソフトウェアのことです。ここでは製品の優劣ではなく、要件のどこに効くのかを計算で確かめてから選びます。
1. 現在の企業状況
- Level 2でPoC候補が3案(8B級Dense・30B級MoE・30B級Dense INT4)に絞られた
- 検証機はまだ手元にない(Level 4で調達)
- 開発メンバーは各自のPCでOllamaを動かしており、「これで十分速い」という感触を持っている
- 運用体制は専任1人+兼任2人(Level 1)のまま
- Nortiaの要件は、ピーク20〜50人の同時利用
2. 発生した課題
「手元で動いた」と「500人の社内で使える」の間には、はっきりした断絶があります。
開発メンバーの体感は正しく、1人で使う限りは十分に速いのです。問題は、その速度が同時利用者数で割られていくのか、それとも共有されるのかという点にあります。
素朴に「1リクエストずつ順番に処理する」実装を考えます。1回の回答が500トークン、出力速度が80 tok/sなら、1人あたり約6.3秒です。
逐次実行:1リクエストずつ処理する
リクエストA ████████ (6.3秒)
リクエストB ████████ (待ち6.3秒 → 処理6.3秒)
リクエストC ████████ (待ち12.6秒 → …)
…
50人目 → 約5分待ち
50人目の待ち時間は約5分12秒になります。TTFT 2秒という要件は、最初の1人にしか適用されていません。
かといって「1人1GPU」で50台を並べるのは、コストの点で成立しません。1台のGPUで複数のリクエストを同時に進める仕組みが必要です。それを担うのが推論サーバーであり、このLevelの主題です。
なぜ1台で複数人を捌けるのか
鍵はLevel 2で確認した性質にあります。デコード(1トークンずつ生成する処理)はmemory-boundで、1トークン作るたびに(アクティブな)重みを全部読む——ここに無駄があります。
重みを読む1回の作業は、実はバッチ内の全リクエストで共有できます。1人分のために読んでも、16人分のために読んでも、読むバイト数は同じだからです。
1ステップ(全リクエストが1トークンずつ進む)で読むバイト数
逐次実行(1件) │ 重み 3.0GB │ KV 0.4GB │ = 3.4GB → 1トークン
バッチ実行(16件) │ 重み 3.0GB │ KV 6.4GB │ = 9.4GB → 16トークン
↑
バッチ数を増やしても、ここは増えない
読むバイト数は2.8倍にしかならないのに、生成されるトークンは16倍です。これがバッチ処理の効用のすべてです。式にすると次のようになります。
1ステップの時間 = (重み + バッチ数 × 1リクエストのKV) ÷ メモリ帯域
合計スループット = バッチ数 ÷ 1ステップの時間
1人あたりの速度 = 1 ÷ 1ステップの時間
合計スループットは増えるが、1人あたりの速度は落ちる。 この2つが同時に起きるのがバッチ処理であり、Level 3の判断はほぼすべてこのトレードオフの上にあります。
3. 要件(この判断に関係する部分)
| 要件 | 値・内容 | この判断への効き方 |
|---|---|---|
| ピーク同時利用 | 20〜50人 | バッチ方式そのものが必要かを決める |
| 1利用者への出力速度 | 20〜30 tok/s | バッチをどこで打ち切るかを決める |
| TTFT | 2秒以内(キュー待ちを含む) | スケジューリング方式が効く |
| 回答完了 | 約5秒以内 | 同上 |
| API形式 | OpenAI互換 | Level 5のRAG基盤から呼ぶ前提 |
| 可観測性 | TTFT・スループット・KV使用率を取得したい | Level 7のメトリクス基盤に接続する |
| 量子化対応 | FP8・INT4(Level 2の案B・案C) | 対応形式が候補を制限する |
| 運用工数 | 専任1人+兼任2人 | 導入・更新・障害対応の手間が効く |
| ハード対応 | 検証機のGPUアーキで動くこと | 動かなければ他の長所は無意味 |
TTFTの定義を「キュー待ち込み」にする
推論エンジンのベンチマーク値としてのTTFTは、多くの場合サーバーが処理を開始してからの時間です。しかし利用者が体験するのは、リクエストを送ってから最初の文字が出るまでの時間です。
50人が同時に送れば、後から来たリクエストはキューで待たされます。要件としてのTTFTは必ずキュー待ちを含めて定義してください。ここを曖昧にすると、「ベンチマークは通ったのに遅い」という報告が上がってきます。
4. 選択肢
| 候補 | 位置づけ | 主な想定利用者 |
|---|---|---|
| Ollama(llama.cpp系) | ローカルでLLMを手軽に動かすためのランタイム | 個人・開発時の動作確認 |
| vLLM | 高スループットを目的とした推論サーバー | 複数利用者を捌くサーバー用途 |
| SGLang | 同上。複雑なプロンプト構造の高速化に強みを持つ | RAG・Agentのようなプロンプト再利用が多い用途 |
| TensorRT-LLM(参考) | 特定ベンダーGPUに最適化した推論ライブラリ | 最適化を極める段階 |
| Hugging Face TGI(参考) | Transformers系エコシステムの推論サーバー | 既存のHFワークフローとの統合 |
このLevelでは、Nortiaの状況で現実的なOllama・vLLM・SGLangの3つを比較します。後者2つは検証工数が読めるようになってから再評価します。
5. 技術比較
5-1. 決定的な違いは「バッチの組み方」
比較表を見る前に、原理を押さえます。バッチには2つの方式があり、この違いが同時利用時の性能をほぼ決めます。
静的バッチ(Static Batching) は、リクエストをまとめてから処理を始め、バッチ内の全員が終わるまで次を受け付けません。
静的バッチ:最も長いリクエストに全員が引きずられる
A ████ ← 早く終わってもスロットは空かない
B ████████████████
C ██████
D ███
↑ ↑
ここでバッチを組む 全員終わるまで次は入れない
■■■ = 遊んでいる計算資源
連続バッチ(Continuous Batching) は、1トークン生成するたびにバッチの中身を組み替えます。終わったリクエストは即座に抜け、待っているリクエストがその場に入ります。
連続バッチ:終わった枠に、待っているリクエストが即入る
A ████
B ████████████████
C ██████
D ███
E ██████████ ← Aが抜けた直後に開始
F █████ ← Dが抜けた直後に開始
遊びがほとんどない
出力長は事前に分かりません。「3行で答えて」と「詳しく説明して」が同じバッチに入ることは普通に起こります。出力長のばらつきが大きいほど、静的バッチの無駄は大きくなります。社内AIの用途はまさにばらつきが大きい側です。
5-2. KV Cacheをどう管理するか
もう1つの差はメモリ管理です。Level 2で見たとおり、KV Cacheはリクエストごと・トークンごとに積み上がります。
素朴な実装では、リクエスト開始時に最大コンテキスト長ぶんのKV領域を先に確保します。実装が単純になる代わりに、次の無駄が出ます。
| 無駄の種類 | 内容 |
|---|---|
| 過剰確保 | 200トークンで終わる回答にも、最大長ぶんの領域を押さえてしまう |
| 内部断片化 | 確保した領域の末尾が使われないまま占有される |
| 外部断片化 | 連続領域を要求するため、合計に余裕があっても割り当てられない |
PagedAttention は、OSの仮想メモリと同じ考え方でこれを解きます。KV Cacheを固定サイズのブロックに分割し、必要になった時点で必要な数だけ割り当てます。ブロックは物理的に連続している必要がありません。
事前確保方式 PagedAttention
┌──────────────────┐ ┌──┬──┬──┐
│使用中│ 未使用 │ │ │ │ │ ← 使った分だけブロックを割り当て
└──────────────────┘ └──┴──┴──┘
最大長ぶんを先に確保 足りなくなったら追加で割り当て
→ 実効的な同時実行数が落ちる → Level 2の計算値に近い値まで詰められる
効果は実効的な同時実行数に直接出ます。Level 2で計算した「収容できる同時実行数」は、断片化のない理想値です。事前確保方式ではその何割かしか使えず、PagedAttentionはそのギャップを詰めます。
さらに、ブロック単位で管理されていれば共有もできます。同じプレフィックス(システムプロンプトや共通の指示文)を持つリクエスト同士で、計算済みのKVブロックを使い回せます。これがPrefix Cachingで、Level 5でRAGを入れたときに効いてきます。RAGのプロンプトは、先頭の指示文が全リクエストで共通になるためです。
Prefix Cachingが効くのはTTFT側
Prefix Cachingが削るのは、入力を読み込むプリフィルの計算です。つまり縮むのはTTFTであって、生成中の速度(tok/s)ではありません。Level 2で見た「プリフィルはcompute-bound、デコードはmemory-bound」という非対称性が、ここでも同じ形で現れます。
5-3. 判断軸ごとの比較
要件(第3節)から引いた軸で並べます。
| 判断軸 | Ollama(llama.cpp系) | vLLM | SGLang |
|---|---|---|---|
| 設計目標 | 1人がローカルで手軽に動かす | 複数利用者を高スループットで捌く | 同左+プロンプト構造の再利用を最適化 |
| バッチ方式 | スロット方式(並列数を先に決める) | ◎ Continuous Batching | ◎ Continuous Batching |
| KV Cache管理 | 起動時に確保。ブロック単位ではない | ◎ PagedAttention | ◎ PagedAttention+プレフィックス共有 |
| プレフィックス再利用 | △ 限定的 | ○ オプションで有効化 | ◎ 設計の中心 |
| 同時実行時の性能 | △ 並列数を上げるとメモリを固定で消費 | ◎ 需要に応じて割り当て | ◎ 同左 |
| OpenAI互換API | ○ 対応(独自APIもある) | ◎ 標準 | ◎ 標準 |
| メトリクス | △ 限定的 | ◎ TTFT・スループット・KV使用率・待ち行列 | ○ 取得可能 |
| モデル形式 | GGUF中心(量子化済みが手軽) | safetensors+各種量子化 | 同左 |
| 量子化 | ○ GGUF量子化が容易 | ◎ FP8・INT4系・KV量子化 | ◎ 同左 |
| マルチGPU | △ 限定的 | ◎ Tensor / Pipeline Parallel | ◎ 対応 |
| 導入容易性 | ◎ バイナリ1つ、モデルをpullするだけ | △ Python環境・GPUドライバの整合が必要 | △ 同左 |
| 対応ハードの広さ | ◎ CPU・各種GPU・Apple Silicon | ○ 主要GPUアーキ中心 | ○ 同左 |
| 運用情報の多さ | ◎ 個人利用の情報が豊富 | ◎ サーバー運用の情報が豊富 | ○ 発展途上 |
この表は「判断時点」のスナップショット
推論エンジンは更新が速く、半年前の比較記事はすでに前提が変わっています。上の表は仕組みの違いに基づく比較であり、個別機能の対応状況は必ず判断時点の公式ドキュメントで確認してください。特に「対応していない」という情報は、古くなりやすい情報の代表格です。
5-4. Ollamaは「悪い選択肢」ではない
比較表だけ見ると、Ollamaが劣っているように読めます。これは正しい読み方ではありません。設計目標が違うだけです。
| 場面 | 適した選択肢 |
|---|---|
| 開発者が手元でモデルを試す | Ollama(起動が速く、モデルの切り替えが容易) |
| 数十人が同時に使う | vLLM / SGLang(連続バッチとKV管理が前提にある) |
| ベースライン測定 | Ollama(「素朴な実装だと何秒か」の基準線になる) |
NortiaのPoCでは、Ollamaを捨てずにベースラインとして残します。「vLLMが速い」と言うためには、比較対象が要るからです。
5-5. 数字で確かめる
原理の説明はここまでです。実際に数字を動かして、バッチの効きどころと限界を確認してください。
バッチ処理スループット計算機
decode = memory-bound
1ステップの時間を(重み + バッチ数 × 1リクエストのKV) ÷ 帯域で見積もり、逐次実行とバッチ実行を同じ条件で比べます。プリフィル(TTFT)と推論エンジンのオーバーヘッドは含めていません。
逐次実行(バッチなし)
80 tok/s
1人あたり 80 tok/s
最後の1人の完了まで5分12秒
連続バッチ(50並列)
590 tok/s
1人あたり 12 tok/s(目標に届かない)
最後の1人の完了まで42.4 秒
同じGPU・同じモデルのまま、合計スループットは7.4倍になり、最後の1人の待ち時間は5分12秒から42.4 秒に縮みます。
1ステップで読むバイト数の内訳(合計 23.1 GB)
- 重みの読み出し
- 3.0 GB
- KV Cacheの読み出し(50リクエスト分)
- 20.1 GB
重みの読み出しはバッチ全体で1回だけです。この割合が小さくなるほど、バッチを増やしても合計スループットは伸びなくなります。
バッチサイズを変えたときの合計スループット
| バッチ | 合計スループット | 1人あたり | 判定 |
|---|---|---|---|
| 1 | 80 | 80 | ✓ 目標速度を満たす |
| 2 | 143 | 72 | ✓ 目標速度を満たす |
| 4 | 237 | 59 | ✓ 目標速度を満たす |
| 8 | 351 | 44 | ✓ 目標速度を満たす |
| 16 | 463 | 29 | ✓ 目標速度を満たす |
| 32 | 550 | 17 | ⚠ 1人あたりが遅い |
| 64 | 607 | 9 | ⚠ 1人あたりが遅い |
| 128 | 641 | 5 | ⚠ 1人あたりが遅い |
バッチを増やすほど合計スループットは伸びますが、1人あたりの速度は落ちます。どこで止めるかを決めるのが推論サーバーの設定(vLLMなら --max-num-seqs)であり、超過分はキューで待たせます。ここに出るのは帯域だけから導いた理論上限で、実測は必ずこれを下回ります。
この計算機で確認してほしいこと
- 初期値(MoE 30B-A3B・50人)で、逐次実行と連続バッチの待ち時間の桁が違うことを見る
- バッチ掃引表で、バッチ16あたりまでは合計スループットが素直に伸びることを見る
- さらにバッチを増やすと、合計は伸び悩み、1人あたりだけが落ちていくことを見る
- このとき「1ステップで読むバイト数の内訳」で、重みの割合が小さくなっていることを確認する
- コンテキスト長を16Kにすると、同じバッチ数でも1人あたりの速度が落ちることを見る
バッチは「載るだけ載せれば速い」ものではありません。重みの読み出しを共有し尽くした時点で、伸びは止まります。
5-6. 計算から分かったこと
案B(30B級MoE・FP8・4Kコンテキスト・大容量Unified Memory機)で数字を並べると、次のようになります。
| バッチ数 | 合計スループット | 1人あたり | 判定 |
|---|---|---|---|
| 1 | 80 tok/s | 80 tok/s | 速いが1人しか処理できない |
| 8 | 351 tok/s | 44 tok/s | 余裕あり |
| 16 | 463 tok/s | 29 tok/s | 目標20〜30 tok/sを満たす上限帯 |
| 32 | 550 tok/s | 17 tok/s | 1人あたりが要件割れ |
| 64 | 607 tok/s | 9 tok/s | 合計もほぼ頭打ち |
読み取れることは3つあります。
① バッチで1台あたりの収容人数は一桁変わる。 逐次実行の80 tok/sに対し、バッチ16で463 tok/s——約5.8倍です。同時利用を捌く手段として、これに代わるものはありません。
② 上限は帯域が決める。 Level 2の計算では、このメモリ容量なら4Kコンテキストで180並列以上を収容できます。それでもバッチ32で要件割れするのは、容量ではなく帯域が先に尽きるからです。Level 2の結論がそのまま効いています。
③ 1台では要件に届かない。 Level 2で出した必要スループットは1,250 tok/s(50人 × 25 tok/s)でした。この構成の上限は600 tok/s台です。
推論サーバーは制約を緩めるが、消しはしない
Continuous BatchingもPagedAttentionも、メモリ帯域という物理制約を消すものではありません。消せるのは「使い切れていない分」だけです。
したがってこのLevelの結論は「vLLMを入れれば解決する」ではなく、**「バッチで5倍以上に増やしてなお1台では足りないので、台数はLevel 9で決める」**になります。GPU台数を50台から2台程度まで落としたのが、この判断の価値です。
6. 採用判断
Nortiaは、vLLMをPoCの本命とします。
| 要件 | vLLMを選ぶ根拠 |
|---|---|
| ピーク20〜50人の同時利用 | Continuous Batchingが前提にあり、出力長のばらつきに強い |
| 1人あたり20〜30 tok/s | --max-num-seqsで同時実行の上限を明示的に決められる |
| TTFT 2秒以内 | 待ち行列とプリフィルを分けて観測できる |
| OpenAI互換API | 標準で提供。Level 5のRAG基盤をエンジンから切り離せる |
| 可観測性 | TTFT・スループット・KV使用率をそのままLevel 7へ渡せる |
| 量子化(案B・案C) | 重みの量子化とKV Cacheの量子化を個別に設定できる |
| 将来の複数GPU | Tensor Parallelが用意されており、Level 9で選択肢が残る |
同時に、次の2つを検証計画に残します。
| 対象 | 扱い | 理由 |
|---|---|---|
| Ollama | ベースライン測定に使う | 「素朴な実装だと何秒か」の基準線がないと、改善幅を主張できない |
| SGLang | Level 5で再評価 | 強みはプレフィックス共有にあり、RAGのプロンプト構造が決まってからでないと差が出ない |
この判断が変わる条件
判断には前提があります。前提が崩れる条件を先に書いておきます。
| 前提が崩れる条件 | そのときの判断 |
|---|---|
| 検証機のGPUアーキでvLLMが動作しない | llama.cpp系でベースラインだけ取り、本番ハードの選定へ差し戻す |
| 同時利用の実測値が5人程度に留まる | 運用の軽さを優先し、より単純な構成を選び直す |
| Level 5でプロンプトの共通部分が支配的になる | SGLangとの比較を前倒しする |
| 選定したモデルの量子化形式に対応していない | Level 2の案を入れ替える(エンジンではなくモデル側を動かす) |
最初に確認するのは性能ではなく「動くか」
検証機が新しいGPUアーキテクチャの場合、推論エンジンがまだ対応していないことがあります。ビルド済みパッケージが無く、自前ビルドが必要になる場合もあります。
Level 4で最初にやるべきは性能測定ではなく、候補エンジンが起動してトークンを1つ返すことの確認です。ここで詰まると、以降の計画がすべて止まります。
7. Architecture
推論サーバーは、利用者と直接つながる場所には置きません。RAGや権限制御を差し込む余地を残すため、前段にアプリケーション層を置きます。
┌──────────┐
│ 利用者 │
└────┬─────┘
│ HTTPS
┌────▼─────────────────────────┐
│ アプリ / RAG Orchestrator │ ← Level 5・Level 6でここが厚くなる
└────┬─────────────────────────┘
│ OpenAI互換API(/v1/chat/completions)
┌────▼─────────────────────────┐
│ 推論サーバー(vLLM) │
│ ├ Scheduler │ ← 誰を今のステップに入れるか
│ ├ KV Block Manager │ ← ブロックの割り当て・解放・共有
│ └ Model Executor │
└────┬─────────────────────────┘
│
┌────▼─────┐
│ GPU │
└──────────┘
OpenAI互換APIを境界にすることには意味があります。エンジンを差し替えても上位層を書き換えずに済むため、「SGLangに乗り換える」「一部をManagedへ逃がす」(Level 1)という判断が、後から取れる状態を保てます。
リクエストの状態遷移
推論サーバーの中で、リクエストは次のように動きます。運用時に見るべき指標は、この状態の滞留です。
受信 → [waiting] ──割り当て可能──→ [running] ──完了──→ 応答
▲ │
└──────preempted───────────┘
(KVブロックが不足したとき、実行中のものが退避される)
| 状態 | 増えているときに起きていること |
|---|---|
| waiting | 同時実行の上限に達している。TTFTが伸びる |
| running | 正常。ただし多すぎると1人あたりの速度が落ちる |
| preempted | KVブロックが枯渇している。設定かコンテキスト長の見直しが要る |
8. 実装
起動パラメータは、Level 2の計算結果と対応させる
推論サーバーの設定値は、感覚で決めるものではありません。そのほとんどがLevel 2で計算した数字に対応します。
vLLMの主な起動パラメータ(値はLevel 2の計算結果から決める)
--max-model-len 1リクエストの最大コンテキスト長
--max-num-seqs 同時に処理するリクエスト数の上限
--gpu-memory-utilization GPUメモリのうち利用する割合
--kv-cache-dtype KV Cacheの精度
--quantization 重みの量子化形式
--enable-prefix-caching 共通プレフィックスのKVを再利用する
--tensor-parallel-size モデルを分割するGPU数
| パラメータ | 対応するLevel 2の数字 | 大きくしすぎるとどうなるか |
|---|---|---|
--max-model-len |
想定コンテキスト長 | 1リクエストのKV確保量が増え、同時実行数が減る |
--max-num-seqs |
目標速度を満たすバッチ数 | 1人あたりの速度が落ちる。preemptionが増える |
--gpu-memory-utilization |
メモリ収支の上乗せ分 | 断片化・他プロセスと競合してOOMする |
--kv-cache-dtype |
KV Cacheの精度 | (下げる方向)品質劣化の検証が必要 |
--quantization |
重みの精度 | (下げる方向)同上 |
--tensor-parallel-size |
GPU台数(Level 9) | 通信オーバーヘッドで期待どおり速くならない |
--max-num-seqsは「遅くしないための上限」
同時実行の上限は、大きくするほど合計スループットが伸びます。しかし5-5で見たとおり、1人あたりの速度は落ち続けます。
この値は「性能を出すための設定」ではなく、1人あたりの速度が要件を割らない位置にキューへの切り替え点を置く設定です。上限を超えたリクエストは待ち行列に入り、TTFTとして観測されます。どちらの体験が許容されるかは要件で決めます。
PoCでの測定手順
比較は、条件を固定しないと意味を持ちません。
- 負荷条件を固定する(入力長・出力長・到着パターン・プロンプト内容)
- Ollamaで並列1のベースラインを取る
- vLLMで並列1を取る(エンジン単体の差を見る)
- vLLMで並列2 → 4 → 8 → 16 → 32と上げ、各点でTTFT・1人あたり速度・合計スループットを記録する
- 1人あたりの速度が要件を割る点を探し、その手前を
--max-num-seqsの候補にする - その設定で、ピーク相当(20〜50人)の負荷をかけ、キュー待ち込みのTTFTを測る
出力長を固定しないと比較にならない
同じ負荷試験に見えても、モデルの出力が長いか短いかでスループットは変わります。比較時はmax_tokensとignore_eosのような設定で出力長を固定し、エンジンの差だけが出る状態にしてください。
品質評価(想定質問100件)は別枠で行います。性能測定と品質評価を同じ実行で兼ねようとしない——これが測定を濁らせる典型的な原因です。
9. Benchmark / Evaluation
記録する指標
| 指標 | 定義 | なぜ見るか |
|---|---|---|
| TTFT | 送信から最初のトークンまで(待ち込み) | 体感の速さ。要件の直接の対象 |
| TPOT(ITL) | トークン間の平均間隔 | 1人あたりの読み心地 |
| E2Eレイテンシ | 送信から生成完了まで | 約5秒以内の判定 |
| 合計スループット | サーバー全体のtok/s | 台数計算(Level 9)の入力 |
| Goodput | 要件を満たして完了したリクエストの割合 | 平均では見えない「実質何人捌けたか」 |
| KV Cache使用率 | 割り当て済みブロックの割合 | 同時実行を増やせる余地 |
| preemption回数 | 退避が起きた回数 | 設定が破綻しかけている兆候 |
平均ではなくp95で見る
同時実行環境では、平均レイテンシは実態を隠します。バッチに早く入れた人が速く、待たされた人が遅い——その平均は誰の体験でもありません。
要件の判定はp95(またはp99)で行ってください。「平均TTFT 1.2秒」は、20人に1人が8秒待っている状態と両立します。
Level 4で検証する仮説
| # | 仮説 | 検証方法 | 棄却されたら |
|---|---|---|---|
| 1 | 候補エンジンが検証機のGPUで起動し、応答を返す | 最小構成で1リクエスト | ハード側の選定に差し戻す |
| 2 | vLLMは並列16で、Ollamaの並列16に対し合計スループット3倍以上 | 同一条件で負荷試験 | エンジン差より設定差を疑い再測定 |
| 3 | 並列16で1人あたり20 tok/s以上を維持できる | 並列数を1→32まで変えて計測 | --max-num-seqsを下げ、台数で補う |
| 4 | ピーク負荷でもTTFT p95が2秒以内 | キュー待ちを含めて計測 | 台数(Level 9)で解く |
| 5 | 上限超過時はキューで待ち、OOMしない | 上限の2倍のリクエストを投入 | メモリ設定を見直す |
| 6 | 実測スループットは理論値の一定割合に収まる | 5-6の計算値と実測を比較 | 計算の前提(memory-bound)を見直す |
仮説6は、このLevelの計算そのものを検証する項目です。理論値と実測の比率が分かれば、以降のLevelで「測る前に見当をつける」精度が上がります。
10. 残った課題
- 検証機のGPUアーキで各エンジンが動作するかは未確認(Level 4の最初の項目)
- MoEのバッチ時の挙動は計算では読めない(複数リクエストが別々のエキスパートを呼ぶため、実効的に読まれる重みが増える)
- Prefix Cachingの効果は、RAGのプロンプト設計に依存する(Level 5で再測定)
- Embeddingモデル・Rerankerを同じGPUに同居させると、メモリと帯域を奪い合う(Level 5・Level 9)
- メトリクスの常時収集とアラートは未設計(Level 7)
- 1台では要件スループットに届かないため、台数と冗長化の判断が残る(Level 9)
11. 次のLevelへ
Level 4:GX-10でPoCするでは、ここまで机上で組み立てた前提を実機にぶつけます。
Level 2で計算したメモリ収支、Level 3で計算したバッチごとのスループット——どちらも理論上限であり、実測は必ずこれを下回ります。問題は「どれくらい下回るのか」です。その比率が分かって初めて、本番のサイジングが根拠を持ちます。