- なぜこの五つが紛らわしいのか
- 一目でわかる比較表
- コンテキストウィンドウとmax_model_len
- max_tokensと名前が変わった話
- max_num_batched_tokensとmax_num_seqs
- シナリオ1 — 8kモデルに6k入力とmax_tokens 4000
- シナリオ2 — 128kモデルなのになぜ8192で引っかかるのか
- シナリオ3 — リクエストより前に起動で引っかかる場合
- 本当の限界を決めるのはKVキャッシュメモリ
- エラーメッセージから原因を見つける
- 試してみる
- 参考資料
なぜこの五つが紛らわしいのか
vLLMを運用していてもっとも多く出てくる質問は、性能ではなく長さについてだ。コンテキストウィンドウが128kというモデルを載せたのに、なぜ8192で引っかかるのか。max_tokensを4000にしたのに、なぜ拒否されるのか。max_num_batched_tokensとはそもそも何なのか。
紛らわしい理由ははっきりしている。名前がどれも似ていて、それぞれ違う場所で決まり、超えたときに現れる症状もばらばらだからだ。あるものはリクエストが拒否され、あるものは応答が静かに切り詰められ、あるものはサーバーがそもそも起動しない。
この記事はその五つを一度に整理する。順序はこうだ。まず比較表で全体の見取り図をつかみ、それぞれを説明したあと、実際によく起きる三つのシナリオを数字で追い、最後にエラーメッセージから原因を逆にたどる方法を整理する。
内容は 2026-08-12 に公式ドキュメントとソースで確認しました。vLLM は変化が速いため、設定値と挙動は使用中のバージョンのドキュメントで再確認してください。
一目でわかる比較表
| 名前 | 決まる場所 | 制限する対象 | 超えたときに起きること |
|---|---|---|---|
| コンテキストウィンドウ | モデル自体(モデル設定ファイル) | モデルが一度に見られるトークン数 | これより大きいエンジン設定を要求すると起動段階で問題になる |
max_model_len | エンジン起動引数 | リクエスト一つの入力と出力を合わせた長さ | リクエストが拒否される |
max_tokens(またはmax_completion_tokens) | リクエスト本文 | そのリクエストが新たに生成するトークン数 | その時点で生成が打ち切られる |
max_num_batched_tokens | エンジン起動引数 | 1ステップでバッチ全体が処理するトークン数 | リクエストが複数ステップに分割されるか、後回しになる |
max_num_seqs | エンジン起動引数 | 1ステップに同時に詰め込めるシーケンス数 | 待機キューで待つ |
表でもっとも重要な行は二番目だ。max_model_lenが制限するのは入力ではなく、入力と出力の合計だ。公式のエンジン引数ドキュメントは、この値をプロンプトと出力を合わせたモデルのコンテキスト長だと明記している。長さに関する誤解の半分は、ここから生まれる。
コンテキストウィンドウとmax_model_len
この二つは、層が違う。
コンテキストウィンドウはモデルの性質だ。学習方法から生まれる構造的な上限であり、設定ファイルを書き換えて増やせる性質のものではない。モデルカードに128kと書かれている、あの数字のことだ。
max_model_lenはエンジンの設定だ。公式ドキュメントによれば、この値を指定しなければモデル設定から自動的に導出される。つまり何も与えなければ、たいていはモデルのコンテキストウィンドウに従う。しかし明示的に指定すれば、その値が実際の上限になる。
ここで最初の誤解が解ける。モデルが128kに対応しているからといって、あなたのサーバーが128kを受け付けるわけではない。実際に受け付けるのはmax_model_lenだ。そしてこの値を低めに設定しておくのはミスではなく、たいていは意図された選択だ。理由は後で扱う。
デフォルト値をここで具体的な数字として書かない理由も明らかにしておく。公式ドキュメントは、この引数について固定されたデフォルト値を提示しておらず、モデル設定から導出されるとだけ説明している。だから、自分のデプロイで実際にいくつになっているかは、起動ログで確認する。
max_tokensと名前が変わった話
max_tokensはリクエスト本文に入れる値で、そのリクエストが新たに生成するトークン数の上限だ。入力の長さはここに含まれない。だからこの値自体は「どれだけ長く答えるか」を決めるだけで、どれだけ長い質問を受け取るかとは無関係だ。
ここで最新の情報を一つ押さえておく。mainブランチのチャット補完リクエスト定義を見ると、max_tokensフィールドには非推奨の表示が付いており、max_completion_tokensを使うようにという案内が添えられている。そして両方の値が渡された場合はmax_completion_tokensが優先される。OpenAI互換APIの流れに沿った変化だ。新しくコードを書くならmax_completion_tokensを使うほうがよく、既存のコードがmax_tokensを使っているなら、今すぐ壊れることはないが、いずれ整理すべき負債として残しておけばよい。
この値をまったく与えないとどうなるか。残っている余裕の分だけ生成が続き、モデルが自分で終えるか上限に達するまで進む。サービスの観点では、上限を明示しておくほうがほぼ常に良い。上限がないと、ユーザー一人がKVキャッシュを長く占有することになり、それが第4回で見たプリエンプションにつながる。
max_num_batched_tokensとmax_num_seqs
この二つは名前のせいで長さの上限のように見えるが、性格はまったく違う。リクエスト一つに対する制限ではなく、1ステップでエンジンが処理する作業量に対する制限だ。
max_num_batched_tokensは、今回のステップでバッチ全体が処理するトークン数の上限だ。リクエスト一つがこの値を超えたからといって拒否されるわけではない。チャンクドプリフィルが有効になっていれば、単に複数のステップに分かれて処理される。
max_num_seqsは、1ステップに同時に詰め込めるシーケンス数の上限だ。これを超えると待機するだけで、失敗はしない。
mainブランチのSchedulerConfigには、それぞれのクラスのデフォルト値が2048と128として宣言されている。ただし実際に適用される値は、利用状況や環境によって調整されることがあるため、起動ログで確認する。
この二つが長さの問題と交わる地点が一つだけある。公式の最適化ドキュメントは、チャンクドプリフィルを無効にした場合、max_num_batched_tokensがmax_model_lenより大きくなければならないと明記している。分割処理ができないのに、最大長のプロンプトを1ステップに収められなければ、どうにもならないからだ。
シナリオ1 — 8kモデルに6k入力とmax_tokens 4000
もっとも多いケースから見る。コンテキスト8192のモデルを載せていて、ユーザーが6000トークンの文書を貼り付けながらmax_tokensを4000にした。
max_model_len = 8192 (入力 + 出力が共有する予算)
入力 6000 ██████████████████████████████
出力 4000 ████████████████████
合計 10000 ────────────────────────────────────────── 8192 超過
結果: 生成が始まる前にリクエストが拒否される。
ここで初心者がもっとも多くしてしまう予想は、「入力6000は8192より小さいから通って、答えは2192トークンあたりで切られるだろう」というものだ。そうはならない。vLLMはリクエストを受け取った時点で入力とmax_tokensを足して検査し、超えていれば拒否する。
実際に出るメッセージはこういう形だ。公開されているvLLMのIssueに報告された原文をそのまま引用する。
This model's maximum context length is 16384 tokens. However, you requested
122946 tokens (112946 in the messages, 10000 in the completion).
Please reduce the length of the messages or completion.
メッセージを分解してみると、構造がそのまま見える。かっこの中は入力と出力に分かれていて、二つの合計が前半の上限と比較されている。この一行こそが、「入力と出力は同じ予算を分け合う」という事実のもっとも確かな証拠だ。
だから解決策も三つのうちのどれかになる。入力を減らすか、max_tokensを減らすか、max_model_lenを増やすかだ。前の二つはリクエスト側の修正で、最後はサーバーの再起動が必要になる。ちなみに、自動的に切り詰めず拒否するこの挙動については、vLLMのリポジトリに改善要望のIssueが上がっている。つまりバージョンによって変わりうる領域なので、使用中のバージョンで直接確認する。
実践的なコツを一つ。アプリケーション側でmax_tokensを定数として固定しておくと、長い入力が来るたびにこのエラーに当たる。入力トークン数を数えたうえで、残っている余裕から安全マージンを引いた値を計算して入れるほうが安定する。
シナリオ2 — 128kモデルなのになぜ8192で引っかかるのか
モデルカードには128kと書かれているのに、サーバーはずっと小さい値でリクエストを拒否する。確認する順序はこうだ。
第一に、起動コマンドで--max-model-lenを直接指定したことがあるか見る。指定していたなら、その値が答えだ。モデルの能力とは無関係に、エンジンが定めた上限が優先される。
第二に、指定していなければ、エンジンがモデル設定から導出した値を見る。公式ドキュメントが明らかにしているとおり、指定しなければモデル設定から自動的に導出されるが、この値はモデルカードの宣伝文句とは異なる場合がある。拡張手法によって長いコンテキストに対応しているモデルは、設定ファイルにはより小さいデフォルトのウィンドウが書かれていることもある。
第三に、エラーメッセージが語る数字を信じる。先ほどのメッセージで「maximum context length is」の後に出てくる値が、今このエンジンで実際に効いている上限だ。モデルカードより、この数字のほうが事実だ。
第四に、それでも128kが必要なら、KVキャッシュがそれを支えられるかをまず計算する。そして、これが三番目のシナリオにつながる。
シナリオ3 — リクエストより前に起動で引っかかる場合
--max-model-lenを大きく指定したら、サーバーがそもそも起動しない場合だ。vLLMのIssueに報告された原文の形はこうだ。
ValueError: The model's max seq len (4096) is larger than the maximum number
of tokens that can be stored in KV cache (3664). Try increasing
gpu_memory_utilization or decreasing max_model_len when initializing the engine.
このメッセージこそが、この記事の中でもっとも重要かもしれない。なぜならここに、本当の構造が現れているからだ。エンジンは起動時に重みを載せ、残ったメモリでKVキャッシュを確保する。そして、そのキャッシュに何個のトークンを収められるかを計算する。もしその数がmax_model_lenより小さければ、最大長のリクエスト一つすら最後まで処理できないという意味になるため、起動を中断する。
つまり長さの上限を最終的に決めるのは、モデルでも設定でもなく、メモリだ。
本当の限界を決めるのはKVキャッシュメモリ
先の三つのシナリオを一般化すると、こうなる。
GPU全体のメモリ
└─ gpu_memory_utilization の比率分をvLLMが使用
├─ モデルの重み (モデルサイズと量子化が決める)
├─ アクティベーションと各種オーバーヘッド
└─ 残り全部 = KVキャッシュ ← ここが長さと同時実行数を一緒に食う
KVキャッシュは二つの要求を同時に受ける。一つは長さだ。リクエスト一つが長いほど、ブロックを多く使う。もう一つは同時実行数だ。リクエストが多いほど、ブロックを多く使う。だからmax_model_lenを二倍にすると、同じメモリで支えられる同時リクエスト数はおおよそ半分になる。
この関係は実務ではこう現れる。128kを開けておくと、実際に128kを使うユーザーがいなくても、同時処理能力は減る。エンジンは最悪のケースに耐えられて初めて起動するからだ。だからほとんどの本番デプロイは、モデルが対応する最大値ではなく、実際のワークロードの上位パーセンタイルに合わせてmax_model_lenを設定する。これが、先ほどこの値を低めにしておくのはミスではないと述べた理由だ。
エラーメッセージから原因を見つける
最後に、症状から逆にたどっていく表だ。
| 症状 | もっとも有力な原因 | まず確認すること |
|---|---|---|
| リクエストが400系で拒否され、メッセージにmessagesとcompletionの数字が見える | 入力とmax_tokensの合計がmax_model_lenを超過 | リクエストのmax_tokensの計算方法 |
| サーバー起動中にKVキャッシュへ収められるトークン数が不足しているというエラー | max_model_lenが利用可能なメモリに対して大きい | --gpu-memory-utilizationと--max-model-len |
| 応答が文の途中で急に切れる | リクエストの生成上限に到達 | レスポンスの終了理由フィールド |
| モデルカードより小さい値で引っかかる | エンジンが導出したか、指定されたmax_model_len | 起動ログでの実際の適用値 |
| 同時リクエストが増えると急激に遅くなる | 長さの上限ではなくKVキャッシュ不足とプリエンプション | プリエンプションの警告ログ(第4回参照) |
まとめると、手順は一つだ。まずエラーメッセージがリクエスト段階で出たのか起動段階で出たのかを見分け、リクエスト段階なら入力と生成上限の合計を見て、起動段階ならメモリとmax_model_lenの関係を見る。この二つの枝分かれさえ区別できれば、長さの問題の大部分は十分で片付く。
試してみる
- LLM GPUメモリ(VRAM)計算機 —
max_model_lenをどこまで大きくできるかは、結局KVキャッシュが決める。モデルとGPUを入れて長さを変えながら計算できる。この記事のシナリオ3が数字で再現される。 - LLM APIコスト計算機 — 入力と出力のトークンがそれぞれコストにどう反映されるかを比較できる。長さの設計は性能だけでなく、コストの設計でもある。
- 前回: vLLM 内部構造 (5) — プレフィックスキャッシュ、システムプロンプト設計が性能になる理由
- 次回: vLLM 内部構造 (7) — デプロイのチューニングとよくある落とし穴、OOM の切り分け順
参考資料
- vLLM Engine Arguments (docs.vllm.ai) —
max-model-lenがプロンプトと出力を合わせた長さであり、指定しなければモデル設定から導出されるという記述の出典。 - vLLM Optimization and Tuning (docs.vllm.ai) — チャンクドプリフィルを無効にしたとき
max_num_batched_tokensがmax_model_lenより大きくなければならないという条件の出典。 - vLLM チャット補完リクエスト定義ソース (GitHub main) —
max_tokensの非推奨表示とmax_completion_tokensの優先適用を読んだ場所。 - vLLM Issue 20409 — 入力と生成上限を合計して検査することを示す、実際のエラーメッセージの出典。
- vLLM Issue 2418 — KVキャッシュの容量不足で起動が失敗するエラーメッセージの出典。
- vLLM Issue 42474 — 生成上限を超えたときに切り詰めず拒否する挙動についての改善要望。
현재 단락 (1/77)
vLLMを運用していてもっとも多く出てくる質問は、性能ではなく長さについてだ。コンテキストウィンドウが128kというモデルを載せたのに、なぜ8192で引っかかるのか。`max_tokens`を4000...