[Bugfix] Restore multimodal support on the plain "vllm" throughput backend (#52168)

Signed-off-by: Michal Ganczarenko <michal.ganczarenko@intel.com>

Michał Ganczarenko committed Aug 28, 2026 at 12:28 UTC d1922cb5a718259976fcb9044c18c9711c9ca694
2 files changed +50 -4
tests/benchmarks/test_throughput_cli.py
+47
@@ -230,3 +230,50 @@ def test_get_requests_resolves_mmvu(
230 requests = get_requests(args, hf_tokenizer)
231 assert len(requests) == 3
232 assert all(isinstance(r, SampleRequest) for r in requests)
233 +
234 +
235 +@pytest.mark.benchmark
236 +def test_get_requests_allows_multimodal_on_plain_vllm_backend(
237 + monkeypatch: pytest.MonkeyPatch,
238 + hf_tokenizer: PreTrainedTokenizerBase,
239 +) -> None:
240 + """Regression: --backend vllm must accept multimodal datasets such as ASR.
241 +
242 + _run_vllm_requests forwards multi_modal_data straight to LLM.generate, so
243 + the vllm-chat-only gate in get_samples rejected a backend that always
244 + worked.
245 + """
246 + import vllm.benchmarks.datasets.datasets as dsmod
247 +
248 + class _StubASRDataset:
249 + IS_MULTIMODAL = True
250 + SUPPORTED_DATASET_PATHS = {"openslr/librispeech_asr"}
251 +
252 + def __init__(self, **kwargs):
253 + self.__dict__.update(kwargs)
254 +
255 + def sample(self, *, num_requests, tokenizer, **kwargs): # noqa: ARG002
256 + return [
257 + SampleRequest(prompt="q", prompt_len=1, expected_output_len=1)
258 + for _ in range(num_requests)
259 + ]
260 +
261 + monkeypatch.setattr(dsmod, "ASRDataset", _StubASRDataset)
262 +
263 + parser = FlexibleArgumentParser()
264 + add_cli_args(parser)
265 + args = parser.parse_args(
266 + [
267 + "--dataset-name",
268 + "hf",
269 + "--dataset-path",
270 + "openslr/librispeech_asr",
271 + "--backend",
272 + "vllm",
273 + "--num-prompts",
274 + "3",
275 + ]
276 + )
277 + requests = get_requests(args, hf_tokenizer)
278 + assert len(requests) == 3
279 + assert all(isinstance(r, SampleRequest) for r in requests)
vllm/benchmarks/throughput.py
+3 -4
@@ -567,10 +567,9 @@ def _to_serve_args(args: argparse.Namespace) -> argparse.Namespace:
567
568 def get_requests(args, tokenizer):
569 serve_args = _to_serve_args(args)
570 - # Throughput reuses bench serve's dataset dispatch. vllm-chat is the only
571 - # multimodal-capable throughput backend, so it is the only one allowed past
572 - # the multimodal gates inside get_samples; other backends raise there.
573 - mm_backends = ("vllm-chat",) if args.backend == "vllm-chat" else ()
570 + # Both offline vLLM backends forward multi_modal_data to the engine;
571 + # "hf" and "mii" are text-only and get rejected inside get_samples.
572 + mm_backends = ("vllm", "vllm-chat")
573 requests = get_samples(serve_args, tokenizer, multimodal_backends=mm_backends)
574 requests = assign_loras(requests, args)
575 requests = filter_requests_for_dp(requests, args.data_parallel_size)