[ModelRunner V2] Enable by default for all dense models (#44443)
Signed-off-by: yewentao256 <zhyanwentao@126.com> Signed-off-by: Nick Hill <nickhill123@gmail.com> Co-authored-by: Nick Hill <nickhill123@gmail.com>
Wentao Ye committed
Jul 2, 2026 at 06:48 UTC
a2f713002df9fd08c0fe13272c76547421721f2d
6 files changed
+55
-17
.buildkite/test_areas/model_runner_v2.yaml
+1
-3
@@ -18,9 +18,7 @@ steps:
18
- set -x
19
- export VLLM_USE_V2_MODEL_RUNNER=1
20
- pytest -v -s v1/engine/test_llm_engine.py -k "not test_engine_metrics"
21
- # This requires eager until we sort out CG correctness issues.
22
- # TODO: remove ENFORCE_EAGER here after https://github.com/vllm-project/vllm/pull/32936 is merged.
23
- - ENFORCE_EAGER=1 pytest -v -s v1/e2e/general/test_async_scheduling.py -k "not ngram"
21
+ - pytest -v -s v1/e2e/general/test_async_scheduling.py -k "not ngram"
22
- pytest -v -s v1/e2e/general/test_context_length.py
23
- pytest -v -s v1/e2e/general/test_min_tokens.py
24
# Temporary hack filter to exclude ngram spec decoding based tests.
tests/distributed/test_multiproc_executor.py
+8
-3
@@ -283,9 +283,14 @@ def test_multiproc_executor_pipeline_parallel():
283
output_rank = executor._get_output_rank()
284
assert output_rank == 2, "Output rank should be 2 (first rank of last PP stage)"
285
286
- # Verify max_concurrent_batches for pipeline parallel
287
- assert vllm_config.max_concurrent_batches == 2, (
288
- "Max concurrent batches should equal PP size"
286
+ # V2 model runner uses one extra batch to overlap async scheduling.
287
+ expected_concurrent_batches = 2 + int(
288
+ vllm_config.scheduler_config.async_scheduling
289
+ and vllm_config.use_v2_model_runner
290
+ )
291
+ assert vllm_config.max_concurrent_batches == expected_concurrent_batches, (
292
+ "Max concurrent batches should follow the configured PP/async "
293
+ "scheduling policy"
294
)
295
296
finally:
tests/distributed/test_ray_v2_executor.py
+7
-1
@@ -84,7 +84,13 @@ def assert_executor(executor, tp_size, pp_size):
84
assert executor._get_output_rank() == expected_output_rank
85
86
if pp_size > 1:
87
- assert executor.vllm_config.max_concurrent_batches == pp_size
87
+ expected_concurrent_batches = pp_size + int(
88
+ executor.vllm_config.scheduler_config.async_scheduling
89
+ and executor.vllm_config.use_v2_model_runner
90
+ )
91
+ assert (
92
+ executor.vllm_config.max_concurrent_batches == expected_concurrent_batches
93
+ )
94
95
executor.check_health()
96
assert not executor.is_failed
tests/test_config.py
+23
-1
@@ -118,7 +118,17 @@ def test_v2_model_runner_env_tri_state(monkeypatch, env_value, expected):
118
is_moe=False,
119
is_quantized=False,
120
),
121
- False,
121
+ True,
122
+ ),
123
+ (
124
+ SimpleNamespace(
125
+ model="google/gemma-2-2b",
126
+ architectures=["Gemma2ForCausalLM"],
127
+ runner_type="generate",
128
+ is_moe=False,
129
+ is_quantized=False,
130
+ ),
131
+ True,
132
),
133
(
134
SimpleNamespace(
@@ -197,6 +207,18 @@ def test_v2_model_runner_env_tri_state(monkeypatch, env_value, expected):
207
runner_type="generate",
208
is_moe=False,
209
is_quantized=False,
210
+ is_hybrid=True,
211
+ ),
212
+ False,
213
+ ),
214
+ (
215
+ SimpleNamespace(
216
+ model="state-spaces/mamba-130m-hf",
217
+ architectures=["MambaForCausalLM"],
218
+ runner_type="generate",
219
+ is_moe=False,
220
+ is_quantized=False,
221
+ is_attention_free=True,
222
),
223
False,
224
),
tests/v1/kv_connector/unit/test_remote_prefill_lifecycle.py
+8
-4
@@ -478,10 +478,14 @@ def test_cannot_schedule_after_recv():
478
# request is retrieved from preempted list.
479
scheduler_output = scheduler.schedule()
480
model_runner_output = create_model_runner_output(reqs=[request_remote])
481
- assert (
482
- scheduler_output.scheduled_cached_reqs.num_computed_tokens[0]
483
- == NUM_PROMPT_BLOCKS * BLOCK_SIZE
484
- )
481
+ # V2 emits a resumed (previously preempted) request as a NewRequestData
482
+ # rather than a cached request.
483
+ if scheduler.use_v2_model_runner:
484
+ num_computed = scheduler_output.scheduled_new_reqs[0].num_computed_tokens
485
+ else:
486
+ cached = scheduler_output.scheduled_cached_reqs
487
+ num_computed = cached.num_computed_tokens[0]
488
+ assert num_computed == NUM_PROMPT_BLOCKS * BLOCK_SIZE
489
scheduler.update_from_output(scheduler_output, model_runner_output)
490
assert len(scheduler.running) == 1
491
assert _num_waiting_requests(scheduler) == 0
vllm/config/vllm.py
+8
-5
@@ -67,12 +67,9 @@ logger = init_logger(__name__)
67
68
DEFAULT_V2_MODEL_RUNNER_ARCHITECTURES = frozenset(
69
{
70
- "Qwen3ForCausalLM",
70
"DeepseekV2ForCausalLM",
71
"Qwen2MoeForCausalLM",
72
"GraniteMoeForCausalLM",
74
- "LlamaForCausalLM",
75
- "MistralForCausalLM",
73
}
74
)
75
@@ -565,9 +562,15 @@ class VllmConfig:
562
if model_config.runner_type != "generate":
563
return False
564
565
+ if getattr(model_config, "is_hybrid", False):
566
+ return False
567
+
568
+ if getattr(model_config, "is_attention_free", False):
569
+ return False
570
architectures = getattr(model_config, "architectures", [])
569
- return any(
570
- arch in DEFAULT_V2_MODEL_RUNNER_ARCHITECTURES for arch in architectures
571
+ return (
572
+ any(arch in DEFAULT_V2_MODEL_RUNNER_ARCHITECTURES for arch in architectures)
573
+ or not model_config.is_moe
574
)
575
576
@property