Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ tools, or reconstruct content from routing projections. Model rewrites happen
before token production and apply to both rendering and forwarding.
`vllm.prefillOnly` rewrites only the output budget fields of the render copy;
see [Render-only output budget](#render-only-output-budget). `vllm.omitMMKwargs`
adds one field to the render copy; see
adds two fields to the render copy; see
[Render responses without multimodal tensors](#render-responses-without-multimodal-tensors).

The parsed payload keeps nested objects, arrays, Completions `prompt`, and
Expand Down Expand Up @@ -497,11 +497,13 @@ The producer reads token IDs, `mm_hashes`, and `mm_placeholders` from a render
response. By default vLLM also returns the processed multimodal tensors in
`features.kwargs_data`, which the producer discards and which can reach tens of
megabytes per request. Set `vllm.omitMMKwargs: true` to add
`"return_mm_kwargs": false` to the render copy, so vLLM leaves the tensors out
and skips serializing them. The inference payload is unchanged. The option
requires a vLLM version with the `return_mm_kwargs` render field; other
versions ignore the field and return the tensors. It is false by default and
works with `vllm.url` and `vllm.endpointDiscovery`.
`"return_mm_kwargs": false` and `"mm_payload": "none"` to the render copy, so
vLLM leaves the tensors out and skips serializing them. The inference payload
is unchanged. vLLM v0.32 reads `return_mm_kwargs`; versions with
vllm-project/vllm#61427 read `mm_payload`, which takes precedence. Values the
client sent for either field are overridden. vLLM versions without these fields
ignore them and return the tensors. The option is false by default and works
with `vllm.url` and `vllm.endpointDiscovery`.

A complete sample config that pairs this with `precise-prefix-cache-producer` and `prefix-cache-scorer` is at [`deploy/config/sim-epp-tokenizer-vllm-http-config.yaml`](../../../../../../../deploy/config/sim-epp-tokenizer-vllm-http-config.yaml).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,10 +342,10 @@ func TestModelLimitEligibility(t *testing.T) {

func TestOmitMMKwargs(t *testing.T) {
for _, tc := range []struct{ name, payload, want string }{
{"appends", `{"model":"m","messages":[]}`, `{"model":"m","messages":[],"return_mm_kwargs":false}`},
{"empty object", `{ }`, `{ "return_mm_kwargs":false}`},
{"trailing space", "{\"model\":\"m\"}\n", "{\"model\":\"m\",\"return_mm_kwargs\":false}\n"},
{"client value loses", `{"return_mm_kwargs":true}`, `{"return_mm_kwargs":true,"return_mm_kwargs":false}`},
{"appends", `{"model":"m","messages":[]}`, `{"model":"m","messages":[],"return_mm_kwargs":false,"mm_payload":"none"}`},
{"empty object", `{ }`, `{ "return_mm_kwargs":false,"mm_payload":"none"}`},
{"trailing space", "{\"model\":\"m\"}\n", "{\"model\":\"m\",\"return_mm_kwargs\":false,\"mm_payload\":\"none\"}\n"},
{"client values lose", `{"return_mm_kwargs":true,"mm_payload":"tensors"}`, `{"return_mm_kwargs":true,"mm_payload":"tensors","return_mm_kwargs":false,"mm_payload":"none"}`},
} {
t.Run(tc.name, func(t *testing.T) {
out, err := omitMMKwargs([]byte(tc.payload))
Expand All @@ -372,6 +372,7 @@ func TestOmitMMKwargsAppliesToRawPayload(t *testing.T) {
_, _, err = renderer.RenderChat(context.Background(), raw)
require.NoError(t, err)
assert.Equal(t, "false", string(seen["return_mm_kwargs"]))
assert.Equal(t, `"none"`, string(seen["mm_payload"]))
assert.Equal(t, "1", string(seen["max_tokens"]))
assert.Equal(t, `[{"role":"user","content":"hi"}]`, string(seen["messages"]))
}
Original file line number Diff line number Diff line change
Expand Up @@ -437,23 +437,26 @@ func renderOnlyBudget(payload []byte) ([]byte, error) {
return json.Marshal(envelope)
}

var omitMMKwargsField = []byte(`"return_mm_kwargs":false`)
// omitMMKwargsFields carries both spellings of the vLLM render option. vLLM v0.32 reads
// return_mm_kwargs; versions with vllm-project/vllm#61427 read mm_payload, which takes precedence
// over return_mm_kwargs. A version without a field ignores it.
var omitMMKwargsFields = []byte(`"return_mm_kwargs":false,"mm_payload":"none"`)

// omitMMKwargs adds "return_mm_kwargs":false before the closing brace of the render copy of a JSON
// omitMMKwargs adds omitMMKwargsFields before the closing brace of the render copy of a JSON
// object. It splices instead of decoding, because the body can carry megabytes of base64 images.
// A later duplicate key wins in vLLM's parser, so a client-sent value cannot override it.
// A later duplicate key wins in vLLM's parser, so client-sent values cannot override them.
func omitMMKwargs(payload []byte) ([]byte, error) {
end := bytes.LastIndexByte(payload, '}')
head := bytes.TrimSpace(payload[:max(end, 0)])
if end < 0 || len(head) == 0 || head[0] != '{' || len(bytes.TrimSpace(payload[end+1:])) != 0 {
return nil, errors.New("render payload is not a JSON object")
}
out := make([]byte, 0, len(payload)+len(omitMMKwargsField)+1)
out := make([]byte, 0, len(payload)+len(omitMMKwargsFields)+1)
out = append(out, payload[:end]...)
if head[len(head)-1] != '{' {
out = append(out, ',')
}
out = append(out, omitMMKwargsField...)
out = append(out, omitMMKwargsFields...)
return append(out, payload[end:]...), nil
}

Expand Down
Loading