Repository navigation
[Frontend] Apply each endpoint's top_logprobs cut in derender - #59518
Conversation
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in PRs do not trigger a full CI run by default. Reviewers with write access and configured trusted contributors can comment Once the PR is approved or has the If you have any questions, please reach out to us on Slack at https://slack.vllm.ai. Agent GuidelinesIMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban. 🚀 |
|
Documentation preview: https://vllm--59518.org.readthedocs.build/en/59518/ |
|
This pull request has merge conflicts that must be resolved before it can be |
293b2af to
c864782
Compare
|
This pull request has merge conflicts that must be resolved before it can be |
c864782 to
3cc6ce9
Compare
74afaaf to
31d233b
Compare
|
This pull request has merge conflicts that must be resolved before it can be |
31d233b to
f5f94d6
Compare
|
@hickeyma Rebased onto main. Two upstream changes overlapped, so in addition to the rebase:
|
9f85a5e to
0e38921
Compare
|
/ci run |
|
❌ @hickeyma, Only reviewers with write access can use CI commands before CI is delegated to the PR author. |
hickeyma
left a comment
There was a problem hiding this comment.
LGTM, thanks @yinli-systems
|
/ci run |
|
✅ Triggered Buildkite CI #95111 for commit |
…no logprobs A chat_request that does not ask for logprobs says nothing about the cut, so derender now passes through what generate returned (as without a chat_request and as completions derender already does for logprobs unset) instead of cutting to top_logprobs=0. Fixes test_text_parity_logprobs, which sends a chat_request without logprobs fields. Signed-off-by: Yin Li <kevinli.ai.work@gmail.com>
|
@DarkLight1337 @hickeyma Thanks for the approvals and for starting CI. CI found two failures in Entrypoints Integration (API Server):
The three AMD kernel and model jobs that exited with -1 look like infrastructure failures, not test failures. |
Head branch was pushed to by a user without write access
|
Should be fixed by #61757, let's wait for that and then we could rebase this PR |
|
/ci retry |
|
✅ Triggered Buildkite CI #95139 for commit |
Resolves the overlap with vllm-project#59518: the batch path keeps both the hidden-reasoning gate and the top_logprobs cut, and the parsed streaming path now passes top_limit=_chat_top_logprobs_limit(chat_request) to _resolve_logprobs like the plain path, as agreed on the PRs.
Adapt to vllm-project#59518, which replaced ResponseOptions.logprobs with include_logprobs and dropped the top_logprobs cut: carry the requested k as ResponseOptions.top_k_logprobs, and feed k + 1 wide rows to the top-k/default render parity test. Signed-off-by: hao-aaron <aaronhao@inferact.ai> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adapt to vllm-project#59518, which dropped the top_logprobs cut from the generate response: render_tokens_logprobs no longer takes k and emits every candidate of the row (one fewer when the sampled id repeats in the top-k), matching the per-entry path. Signed-off-by: hao-aaron <aaronhao@inferact.ai> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…roject#59518) Signed-off-by: Yin Li <kevinli.ai.work@gmail.com> Co-authored-by: Yin Li <kevinli.ai.work@gmail.com> Co-authored-by: Cyrus Leung <tlleungac@connect.ust.hk>
Purpose
Fixes #59513. Builds on the generate logprobs shape from #58181 (merged); rebased on main, one commit.
The engine's per-position logprobs hold the sampled token first and then ranks
1..k, sokdistinct entries when the sampled token is in the topkandk + 1when it is not./v1/chat/completionskeeps the firstkand/v1/completionsthe firstk + 1(the OpenAI completions convention). Generate cut tomax(k, 1)and derender passed that through, so/v1/completions/derenderreturnedkentries where the coupled endpoint returnsk + 1whenever the sampled token was outside the topk. The greedy parity tests never produce that case. Following @shimib's suggestion on #58181:output_modes) returns every candidate the engine produced, sampled first, with no cut. Rust drops the repeated sampled entry (its engine row lists a sampled top-1 token twice) by skipping later entries equal to the sampled token (linear, no allocation, even forlogprobs=-1).chat_top_logprobs_limit/completion_top_logprobs_limit), read fromchat_request/completion_request: chat keeps entryiwhenlogprob_token_idsis set,top_logprobs == -1ori < top_logprobs(_get_top_logprobs); completions whenlogprob_token_idsis set orlogprobs >= i. The cut happens before decoding. Without the request derender returns every candidate (documented)./v1/chat/completionsdrops the repeated sampled entry, like Python; before, a sampled top-1 token appeared twice and one candidate was lost.renderer.md(what generate returns) andderenderer.md(the per-endpoint cut).Test Plan
tests/entrypoints/scale_out/derender/test_logprobs_endpoint_parity.py: engine dicts built with the engine's ownappend_logprobs_for_next_positionand detokenized as the engine does, with the sampled token at rank 1, inside and outside the topk, run through the real coupled chat / completions helpers and through generate + derender;kin 0, 1, 2, 5 (and -1 for chat). Plus: without the request, every candidate is kept.--enable-scale-out, Qwen3-4B, L20): the same request (temperature=1.5, seeds 7/11/23,k= 1/2/5, 96 tokens) through the coupled endpoint and through render ->/inference/v1/generate-> derender, compared per position (token ids,top_logprobslength, tokens, bytes, logprobs within 1e-4), before and after this change.top_logprobs=20.Test Result
End-to-end, 18 trials (9 chat, 9 completions), 1,632 comparable positions:
kBefore the change the mismatches were exactly the 215 completions positions with the sampled token outside the top
k. One chat trial is excluded on both sides because the coupled endpoint itself is not run-to-run deterministic there (two identical coupled requests diverge at position 73 once the prefix is cached, attemperature=1.5); generate is repeatable.Benchmark (1,000 positions,
top_logprobs=20, 30% of positions with the sampled token outside the topk, Qwen2.5 tokenizer, median of 7):_create_tokens_logprobsTests on an L20 with live servers (tiny Llama, gpt2, Qwen3-0.6B):
test_derender.py27,test_derender_stream.py52,test_logprobs_endpoint_parity.py10,test_generate_logprobs_conversion.py5,test_serving_tokens.py13,test_generate_stream.py31,test_tokens_logprobs.py7 passed; not run there: the DeepSeek parser and gpt-oss harmony tests (model size) and the LoRA test (adapters not downloaded). CPU-only runs: 414 passed acrossscale_out,test_serving_chat.pyandopenai/completion(3 failures that fail identically on main). Rust:vllm-server440 passed,cargo clippy -D warningsandcargo fmtclean. mypy (tools/pre_commit/mypy.py 3.12) reports only the 2 existingParsererrors inonline_derenderer.pythat main has too; ruff and typos clean.AI assistance (Claude Code) was used for this change; the submitter reviewed every changed line and ran the tests above.