Repository navigation
[Frontend] Add return_mm_kwargs to render requests - #60728
Conversation
Cache-aware routers call the render endpoints for token ids, item hashes and placeholder ranges, and discard the processed tensors. Serializing those tensors dominates render time for image requests and holds the API server's event loop: four 1080p images produce a 66.9 MB response, of which a router reads 58 KB. `return_mm_kwargs: false` leaves `kwargs_data` and `mm_metadata` null on the chat, completions, Messages and Responses render endpoints. Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Maroon Ayoub <mayoub@redhat.com>
|
Documentation preview: https://vllm--60728.org.readthedocs.build/en/60728/ |
sagearc
left a comment
There was a problem hiding this comment.
great! left 2 style nits though
| kwargs_data: dict[str, list[str | None]] | None = None | ||
| mm_metadata: dict[str, list[str | None]] | None = None | ||
| if raw_mm_kwargs := mm_engine_input.get("mm_kwargs"): | ||
| if include_kwargs and (raw_mm_kwargs := mm_engine_input.get("mm_kwargs")): |
There was a problem hiding this comment.
nit: more python-idiomatic way
| if include_kwargs and (raw_mm_kwargs := mm_engine_input.get("mm_kwargs")): | |
| if include_kwargs: | |
| raw_mm_kwargs = mm_engine_input.get("mm_kwargs") | |
| if raw_mm_kwargs: | |
| kwargs_data, mm_metadata = _encode_mm_kwargs_with_metadata( | |
| raw_mm_kwargs, | |
| metadata_fields_for=metadata_fields_for, | |
| ) |
| engine_input: EngineInput, | ||
| *, | ||
| metadata_fields_for: Callable[[str], Collection[str]] | None = None, | ||
| include_kwargs: bool = True, |
There was a problem hiding this comment.
Could we rename include_kwargs to include_mm_kwargs in both helpers? It would make the scope explicit and align it with return_mm_kwargs.
There was a problem hiding this comment.
Done in 8b8c271, in both helpers and the test.
Matches the request field `return_mm_kwargs`, per review. Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Maroon Ayoub <mayoub@redhat.com>
|
/ci run |
|
❌ This PR is 19 commits behind upstream |
…args Signed-off-by: Maroon Ayoub <mayoub@redhat.com>
|
/ci run |
|
✅ Triggered Buildkite CI #93789 for commit |
Signed-off-by: Maroon Ayoub <mayoub@redhat.com> Co-authored-by: Claude <noreply@anthropic.com>
Overview
Add
return_mm_kwargsto render requests. When false, the render response leaves out the processed multimodal tensors (kwargs_data) andmm_metadata, for callers that need only token ids, item hashes and placeholder ranges, such as cache-aware routers. Part of #46722.Claims
return_mm_kwargs: falseon the chat, completions, Messages and Responses render endpoints returnskwargs_dataandmm_metadataas null. Token ids,mm_hashesandmm_placeholdersare unchanged. The default (true) keeps current behavior./healthp99 during back-to-back renders goes from 114.5 to 2.0 ms.Validation
pytest tests/entrypoints/scale_out/token_in_token_out/test_mm_serde.py tests/entrypoints/scale_out/token_in_token_out/test_protocol.py: 45 passed, including the newtest_extract_without_kwargs_keeps_layout.End to end on this head:
vllm launch render Qwen/Qwen3-VL-8B-Instructon CPU (M4 Pro,OMP_NUM_THREADS=1), four 1920x1080 PNGs by URL, median of 3 after a warm-up:return_mm_kwargs: falseMeasured with the same change on main
1afb029839, processor cache off (--mm-processor-cache-gb 0): render 193.9 to 73.6 ms. The time removed isjson.dumpsof the response (102 ms) and msgpack plus base64 (4.8 ms), both on the event loop, plus 14 ms of transfer. With renders back to back,/healthp99 goes from 114.5 to 2.0 ms and max from 117.4 to 4.1 ms.On GPUs: 2 x H100 serving Qwen3-VL-8B (nightly
81198e97with this change laid over the installed package) behind llm-d-router with llm-d/llm-d-router#3273, closed loop, four 1080p images by URL per request, 60 s per step, flag off, on, off. At 16 concurrent clients throughput went from 2.6 to 8.3 req/s, client p95 from 15.2 to 3.0 s, and engine/healthp99 from 1,177 to 11 ms. With the flag on, the router's predicted cached tokens equal the engine's cached tokens (6 of 6 repeats, chat and Messages).Not run: the GPU
vllm serverender tests (tests/entrypoints/scale_out/render/test_render_multimodal.py). No model eval: the change affects only render responses.Details
skip_pixel_valuesreplaces the tensors with the original image bytes so/inference/v1/generatecan rebuild them. A router discards those bytes as well (about 33 MB of base64 for the images above). If both land, they could share one field with three values: tensors, source bytes, none./inference/v1/generate, which reads a nullkwargs_dataas every item being cached. The field description andrenderer.mdsay so.pixel_valuespreprocessing to/generate#46722 and out of scope here.AI assistance (Claude) was used to write this change and run the validation above.
Pull Request Checklist
I used vLLM's
/pr-checklistskill. (Mandatory for agents, optional for humans).AI assistance was used during the creation of this PR.
Design Fit: Minimizes impact on core components, reuses existing functionality, and justifies added complexity.
Testing and Validation: Validates the change and ensures any added tests are meaningful and reliable, with CI coverage or documented CI resource constraints and validation performed outside CI.
Code Quality and Style: Keeps code and comments clear and concise, and updates relevant documentation and examples.
Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.