Repository navigation
[Bugfix][Frontend] Return all choices from /inference/v1/generate when n > 1 - #52399
DarkLight1337 merged 5 commits into
Conversation
…n n > 1 `serve_tokens` only set `sampling_params.output_kind` for streaming requests, so non-streaming ones kept the `SamplingParams` default, `CUMULATIVE`. With `n > 1`, `serve_tokens_full_generator` keeps just the last streamed `RequestOutput` and reads `final_res.outputs`, which under `CUMULATIVE` holds only the sequences updated in that step, so the other completions were silently dropped: 10 runs of `n=4` returned 2, 3 or 4 choices, and with multimodal features `n=4` returned 3 choices on 6 out of 6 runs. No error is raised, the response is simply short. Set `FINAL_ONLY` when not streaming, mirroring `CompletionRequest.to_sampling_params`, and add a regression test. Signed-off-by: Quentin Gallouédec <quentin.gallouedec@huggingface.co>
|
/ci run |
|
✅ Triggered Buildkite CI #84001 for commit |
`trl vllm-serve` ran a custom FastAPI app around `LLM`, with its own data-parallel fan-out and a worker extension for weight sync. vLLM's server covers all of it, so the app is deleted and the command becomes a deprecated wrapper that translates its flags into `vllm serve`, prints the equivalent command, and forwards anything it does not know about. - generation goes to `/v1/completions` for token IDs. Multimodal prompts have no OpenAI-compatible endpoint that takes token IDs and images at once, so the images are processed on their own and the resulting features are paired with the trainer's token IDs on `/inference/v1/generate`, which keeps multi-turn generation working with images - weight sync uses vLLM's NCCL weight-transfer engine: the tensors are announced once and streamed in a single packed broadcast, rather than one HTTP request and one broadcast per tensor - teacher logprobs for distillation come from `prompt_logprobs` - the docs teach `vllm serve` directly, and the web-server dependencies go The request sets `output_kind` explicitly, as the server would otherwise drop completions when `n > 1` (vllm-project/vllm#52399).
`trl vllm-serve` ran a custom FastAPI app around `LLM`, with its own data-parallel fan-out and a worker extension for weight sync. vLLM's server covers all of it, so the app is deleted and the command becomes a deprecated wrapper that translates its flags into `vllm serve`, prints the equivalent command, and forwards anything it does not know about. - generation goes to `/v1/completions` for token IDs. Multimodal prompts have no OpenAI-compatible endpoint that takes token IDs and images at once, so the images are processed on their own and the resulting features are paired with the trainer's token IDs on `/inference/v1/generate`, which keeps multi-turn generation working with images - weight sync uses vLLM's NCCL weight-transfer engine: the tensors are announced once and streamed in a single packed broadcast, rather than one HTTP request and one broadcast per tensor - teacher logprobs for distillation come from `prompt_logprobs` - the docs teach `vllm serve` directly, and the web-server dependencies go The request sets `output_kind` explicitly, as the server would otherwise drop completions when `n > 1` (vllm-project/vllm#52399).
`trl vllm-serve` ran a custom FastAPI app around `LLM`, with its own data-parallel fan-out and a worker extension for weight sync. vLLM's server covers all of it, so the app is deleted and the command becomes a deprecated wrapper that translates its flags into `vllm serve`, prints the equivalent command, and forwards anything it does not know about. - generation goes to `/v1/completions` for token IDs. Multimodal prompts have no OpenAI-compatible endpoint that takes token IDs and images at once, so the images are processed on their own and the resulting features are paired with the trainer's token IDs on `/inference/v1/generate`, which keeps multi-turn generation working with images - weight sync uses vLLM's NCCL weight-transfer engine: the tensors are announced once and streamed in a single packed broadcast, rather than one HTTP request and one broadcast per tensor - teacher logprobs for distillation come from `prompt_logprobs` - the docs teach `vllm serve` directly, and the web-server dependencies go The request sets `output_kind` explicitly, as the server would otherwise drop completions when `n > 1` (vllm-project/vllm#52399).
|
PTAL at the failing test: https://buildkite.com/vllm/ci/builds/84001/canvas?jid=01a009b0-abda-47a4-88a8-30180757cba6&tab=output |
|
Strange, I can't reproduce this. On main ( vllm serve Qwen/Qwen3-0.6B --dtype bfloat16 --max-model-len 1024 \
--enforce-eager --no-enable-prefix-caching --port 8123
for i in 1 2 3 4 5; do
curl -s localhost:8123/inference/v1/generate -H 'Content-Type: application/json' -d '{
"model": "Qwen/Qwen3-0.6B", "token_ids": [1,2,3], "stream": false,
"sampling_params": {"max_tokens": 5, "temperature": 1.0, "n": 4}}' \
| python -c 'import json,sys; print(sorted(c["index"] for c in json.load(sys.stdin)["choices"]))'
doneSo the bug reproduces on main and the patch fixes it. The CI result is what the unpatched path returns. Could we re-run the job? If it fails again I'll log the |
|
/ci run |
|
✅ Triggered Buildkite CI #84337 for commit |
Head branch was pushed to by a user without write access
|
ok I get it: the failing job runs this suite with The Rust frontend doesn't implement parallel sampling: its OpenAI routes reject Skipped the regression test under the Rust frontend, following the existing Follow-up PR: make the Rust generate route reject |
|
/ci run |
|
✅ Triggered Buildkite CI #84531 for commit |
|
Alright, it's green now |
…n n > 1 (vllm-project#52399) Signed-off-by: Quentin Gallouédec <quentin.gallouedec@huggingface.co> Signed-off-by: Zhu, Zufang <zufang.zhu@intel.com>
…n n > 1 (vllm-project#52399) Signed-off-by: Quentin Gallouédec <quentin.gallouedec@huggingface.co>
…n n > 1 (vllm-project#52399) Signed-off-by: Quentin Gallouédec <quentin.gallouedec@huggingface.co>
Purpose
closes #52398
serve_tokenssetssampling_params.output_kindonly for streaming requests, so non-streaming ones keep theSamplingParamsdefault,CUMULATIVE. Withn > 1,serve_tokens_full_generatorkeeps only the last streamedRequestOutputand readsfinal_res.outputs, which underCUMULATIVEholds just the sequences updated in that step,the other completions are silently dropped. No error is raised; the response is simply short.
CompletionRequest.to_sampling_paramsalready usesFINAL_ONLYwhen not streaming, so this makes thetoken-in-token-out path match it.
Test Plan
10 non-streaming requests per
n(2, 4, 8) againstvllm serve Qwen/Qwen2.5-1.5Bon an H100, before and after the patch, counting the choices returned by/inference/v1/generate. Same check with multimodal input (/v1/chat/completions/render→token_ids+features, Qwen2.5-VL-3B). Streaming,logprobs,prompt_logprobsandn=1re-checked after the patch. Adds a regression test asserting the response carries indices0..n-1.Test Result
Before:
After:
n=1, streaming,logprobsandprompt_logprobsbehave as before. The measurements were taken on v0.27.1 with thispatch applied to the installed package; the added test follows the existing fixtures in
tests/entrypoints/scale_out/token_in_token_out/test_serving_tokens.pyand will get its first full run in CI.Essential Elements of an Effective PR Description Checklist
supported_models.mdandexamplesfor a new model.