diff --git a/tests/e2e/online_serving/test_qwen3_omni.py b/tests/e2e/online_serving/test_qwen3_omni.py index 7d1a181d2..c9494d9fe 100644 --- a/tests/e2e/online_serving/test_qwen3_omni.py +++ b/tests/e2e/online_serving/test_qwen3_omni.py @@ -180,14 +180,19 @@ def test_text_to_text_001(omni_server, openai_client) -> None: @pytest.mark.omni @hardware_test(res={"cuda": "H100", "rocm": "MI325"}, num_cards=2) @pytest.mark.parametrize("omni_server", prefix_test_params, indirect=True) -@pytest.mark.skip(reason="issue: #2833") def test_thinker_prefix_caching(omni_server, openai_client) -> None: """ Test thinker prefix caching by sending identical requests with an image (i.e., a large shared prefix) and verifying that the second request uses cached tokens - & produces the same output. + & produces the same output with greedy decoding. + + NOTE: The seed for this test is used as a regression test for the issue linked below; + https://github.com/vllm-project/vllm-omni/issues/2833; without passing the sampling + params, this test will fail with the current default stage configs. """ - image_data_url = f"data:image/jpeg;base64,{generate_synthetic_image(224, 224)['base64']}" + seed = 10 + img_res = generate_synthetic_image(224, 224, seed=seed) + image_data_url = f"data:image/jpeg;base64,{img_res['base64']}" messages = dummy_messages_from_mix_data( system_prompt=get_system_prompt(), image_data_url=image_data_url, @@ -199,16 +204,14 @@ def test_thinker_prefix_caching(omni_server, openai_client) -> None: "messages": messages, "stream": False, "modalities": ["text"], + "sampling_params_list": [{"seed": seed, "temperature": 0, "max_tokens": 16}] * 3, } response_1 = openai_client.send_omni_request(request_config, request_num=1)[0] response_2 = openai_client.send_omni_request(request_config, request_num=1)[0] - assert response_1.success - assert response_2.success - assert response_2.cached_tokens is not None # We should cache the vast majority of the prompt (image + up to last full block), - # and set seed in the CI config, so the second request should give an identical + # and set seed + temperature, so the second request should give an identical # response for the generated input image, even if we use dummy weights - assert response_2.cached_tokens > 0 + assert response_2.cached_tokens is not None and response_2.cached_tokens > 0 assert response_1.text_content == response_2.text_content diff --git a/tests/helpers/media.py b/tests/helpers/media.py index 2e99788b1..c0fb97171 100644 --- a/tests/helpers/media.py +++ b/tests/helpers/media.py @@ -447,12 +447,16 @@ def generate_synthetic_image( *, force_regenerate: bool = False, cache_dir: Path | str | None = None, + seed: int | None = None, ) -> dict[str, Any]: """ Random colored squares on white background. Caches JPEG by ``width`` / ``height`` unless ``force_regenerate`` is true. Cache root: ``cache_dir`` if given, else the default temp subdirectory. """ + if seed is not None: + random.seed(seed) + root = _resolve_synthetic_media_cache_dir(cache_dir) root.mkdir(parents=True, exist_ok=True) cache_path = root / f"synth_image_w{width}_h{height}.jpg" diff --git a/tests/helpers/runtime.py b/tests/helpers/runtime.py index 190cb66b4..0cf0f9e48 100644 --- a/tests/helpers/runtime.py +++ b/tests/helpers/runtime.py @@ -620,6 +620,9 @@ class OpenAIClientHandler: mm = dict(extra_body.get("mm_processor_kwargs") or {}) mm["use_audio_in_video"] = True extra_body["mm_processor_kwargs"] = mm + if "sampling_params_list" in request_config: + extra_body["sampling_params_list"] = request_config["sampling_params_list"] + create_kwargs: dict[str, Any] = { "model": request_config.get("model"), "messages": request_config.get("messages"),