[Config][EC] Normalize producer-only encoder config (#53656)
Signed-off-by: Tianyu Guo <guoty@inferact.ai>
Tianyu Guo committed
Aug 25, 2026 at 15:53 UTC
12c84b98ddeb71186da8b77382b0fad71ad03c8c
3 files changed
+48
-10
tests/config/test_multimodal_config.py
+28
@@ -329,6 +329,34 @@ def test_auto_mm_processor_device_leaves_an_explicit_request_alone():
329
assert _resolve_mm_processor_device(ec_role="ec_producer", device="cpu") == "cpu"
330
331
332
+@pytest.mark.parametrize(
333
+ ("ec_role", "expected"),
334
+ [
335
+ (None, False),
336
+ ("ec_consumer", False),
337
+ ("ec_both", False),
338
+ ("ec_producer", True),
339
+ ],
340
+)
341
+def test_ec_producer_only_enables_mm_encoder_only(
342
+ ec_role: ECRole | None, expected: bool
343
+):
344
+ mm_config = MultiModalConfig()
345
+ model_config = MagicMock(spec=ModelConfig)
346
+ model_config.multimodal_config = mm_config
347
+ vllm_config = MagicMock(spec=VllmConfig)
348
+ vllm_config.model_config = model_config
349
+ vllm_config.ec_transfer_config = (
350
+ None
351
+ if ec_role is None
352
+ else ECTransferConfig(ec_connector="ECExampleConnector", ec_role=ec_role)
353
+ )
354
+
355
+ VllmConfig._resolve_mm_encoder_only(vllm_config)
356
+
357
+ assert mm_config.mm_encoder_only is expected
358
+
359
+
360
def test_vllm_config_runs_the_mm_processor_device_check():
361
"""Startup must reach the check; the rule itself is covered above.
362
tests/v1/core/utils.py
+3
@@ -10,6 +10,7 @@ from vllm.config import (
10
ECTransferConfig,
11
KVTransferConfig,
12
ModelConfig,
13
+ MultiModalConfig,
14
ObservabilityConfig,
15
ParallelConfig,
16
SchedulerConfig,
@@ -94,6 +95,8 @@ def create_scheduler(
95
seed=42,
96
skip_tokenizer_init=skip_tokenizer_init,
97
)
98
+ if use_ec_connector and ec_role == "ec_producer":
99
+ model_config.multimodal_config = MultiModalConfig()
100
if max_model_len is None:
101
max_model_len = max_num_batched_tokens
102
scheduler_config = SchedulerConfig(
vllm/config/vllm.py
+17
-10
@@ -562,15 +562,6 @@ class VllmConfig:
562
]
563
return hash_str
564
565
- @property
566
- def is_ec_producer_only(self) -> bool:
567
- ec_config = self.ec_transfer_config
568
- return (
569
- ec_config is not None
570
- and ec_config.is_ec_producer
571
- and not ec_config.is_ec_consumer
572
- )
573
-
565
@property
566
def is_mm_encoder_only(self) -> bool:
567
mm_config = (
@@ -578,7 +569,7 @@ class VllmConfig:
569
if self.model_config is not None
570
else None
571
)
581
- return self.is_ec_producer_only or bool(mm_config and mm_config.mm_encoder_only)
572
+ return bool(mm_config and mm_config.mm_encoder_only)
573
574
@property
575
def max_concurrent_batches(self) -> int:
@@ -1121,6 +1112,8 @@ class VllmConfig:
1112
# To give each torch profile run a unique instance name.
1113
self.instance_id = f"{time.time_ns()}"
1114
1115
+ self._resolve_mm_encoder_only()
1116
+
1117
if self.performance_mode != "balanced":
1118
logger.info_once("Performance mode set to '%s'.", self.performance_mode)
1119
@@ -2380,6 +2373,20 @@ class VllmConfig:
2373
"omit the embedding tensor."
2374
)
2375
2376
+ def _resolve_mm_encoder_only(self) -> None:
2377
+ """Enable encoder-only mode for a dedicated EC producer."""
2378
+ ec_config = self.ec_transfer_config
2379
+ if ec_config is None or not ec_config.is_encode_only:
2380
+ return
2381
+
2382
+ model_config = self.model_config
2383
+ mm_config = model_config.multimodal_config if model_config is not None else None
2384
+ if mm_config is None:
2385
+ raise ValueError(
2386
+ "An EC producer-only instance requires a multimodal model."
2387
+ )
2388
+ mm_config.mm_encoder_only = True
2389
+
2390
def _resolve_mm_processor_device(self) -> None:
2391
"""Settle `--mm-processor-device=auto` now that the EC role is known.
2392