Skip to content

[Bugfix][Frontend] Report reasoning tokens in batched chat completions - #64935

Merged
DarkLight1337 merged 4 commits into
vllm-project:mainfrom
GCSimba:fix/batch-chat-reasoning-tokens
Nov 4, 2026
Merged

DarkLight1337 merged 4 commits into
vllm-project:mainfrom
GCSimba:fix/batch-chat-reasoning-tokens

Conversation

@GCSimba

@GCSimba GCSimba commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Overview

/v1/chat/completions/batch never sets usage.completion_tokens_details, so a server started with --reasoning-parser omits reasoning_tokens from batched responses while /v1/chat/completions reports them for the same conversation. This counts and sums them per conversation, the way the single-conversation path does. Follows #64757, which added the prompt-side prompt_tokens_details to the same endpoint.

Claims

  • With --reasoning-parser, /v1/chat/completions/batch returns usage.completion_tokens_details.reasoning_tokens summed across conversations, including when include_reasoning=false (hidden reasoning is still generated and billed), matching /v1/chat/completions.
  • Without a reasoning parser, completion_tokens_details stays null, as on /v1/chat/completions.

Validation

New test test_batch_reasoning_tokens_in_usage in tests/entrypoints/openai/chat_completion/test_include_reasoning.py, through RemoteOpenAIServer with Qwen/Qwen3-0.6B --reasoning-parser qwen3 (the module's existing server). It posts two conversations with include_reasoning=false and checks 0 < reasoning_tokens <= completion_tokens.

pytest tests/entrypoints/openai/chat_completion/test_include_reasoning.py -k test_batch_reasoning_tokens_in_usage

Before the fix (main at cfa9f96):

>       assert details is not None
E       assert None is not None
tests/entrypoints/openai/chat_completion/test_include_reasoning.py:118: AssertionError
1 failed, 6 deselected

After the fix: 1 passed, 6 deselected.

Usage for the same conversation on the same server (max_tokens=64, temperature=0, include_reasoning=false), after the fix; before it the batch completion_tokens_details is null:

Endpoint completion_tokens reasoning_tokens
/v1/chat/completions 64 63
/v1/chat/completions/batch, the conversation twice 128 126

Other checks after the fix:

Check Result
test_include_reasoning.py (whole file) 7 passed
VLLM_USE_RUST_FRONTEND=1, the new test only 1 skipped, no server started
Unit tests in test_batched_chat_completions.py (-k the six non-server tests) 6 passed
pre-commit run --files <changed files> passed (shellcheck skipped: no shell files, and its binary download timed out locally)

Environment: CPU only (Intel i5-11300H, AVX-512), Ubuntu 24.04 on WSL2, Python 3.12, --enforce-eager. The Python sources are this branch; the compiled CPU extensions come from the nightly CPU wheel for 2b009fc (20 commits behind, differing only in CUDA kernels). Validated on cfa9f96, then rebased onto 564ac0d; the commits in between only change recipes/models/*.yaml.

Not run locally: the server tests in test_batched_chat_completions.py (they need Qwen/Qwen2.5-1.5B-Instruct, which serves without a reasoning parser, so this path only adds a null field there), and GPU CI. No model evaluation: model outputs are unchanged; only response usage changes.

Details

  • Root cause: chat_completion_full_generator_batch builds UsageInfo without completion_tokens_details, and never counts reasoning tokens even though each conversation already runs through its parser.
  • The fix mirrors OpenAIServingChat.chat_completion_full_generator: call parser.count_reasoning_tokens(output.token_ids) after parse, and gate the details on _include_reasoning_tokens_details. It reuses _make_completion_tokens_details.
  • Three existing unit tests build OpenAIServingChatBatch with __new__, so they now set _include_reasoning_tokens_details = False (as [Bugfix][Frontend] Report prompt_tokens_details in batched chat completions #64757 did for enable_prompt_tokens_details), and the fake parser gains count_reasoning_tokens.
  • The Rust frontend serves /v1/chat/completions/batch as not_supported, so the new test is skipped when VLLM_USE_RUST_FRONTEND is set, as the Rust frontend CI steps do (same pattern as test_thinking_token_budget.py). The Python-frontend steps run it.
  • Docs: one sentence next to the prompt_tokens_details note for this endpoint in openai_compatible_server.md.

Not a duplicate: open and closed PRs and issues searched for "batch reasoning tokens", "completions/batch usage", "batched chat completions usage", "reasoning_tokens", OpenAIServingChatBatch and batch_serving. Related but different: #64757 (merged, prompt-side details only), #64041 (reasoning tokens on the derender endpoints), #58010 (hiding reasoning metadata in batch responses).

AI assistance (GitHub Copilot) was used to find the bug, write the change and tests, and run the validation; I reviewed every changed line and the test results.


Pull Request Checklist
  • I used vLLM's /pr-checklist skill. (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.

/v1/chat/completions/batch never set usage.completion_tokens_details, so
batched requests to a server started with --reasoning-parser omitted the
reasoning_tokens that /v1/chat/completions reports for the same
conversation. Count each conversation's reasoning tokens with its parser,
as the single-conversation path does, and sum them in the batch usage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: GCSimba <44427703+GCSimba@users.noreply.github.com>
@GCSimba
GCSimba requested a review from a team November 1, 2026 00:13

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown

👋 Hi! Thank you for contributing to the vLLM project.

💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in #pr-reviews, coordinate on features in #feat- channels, or join special interest groups in #sig- channels.

PRs do not trigger a full CI run by default. Reviewers with write access and configured trusted contributors can comment /ci run for upstream CI or /amd-ci run for AMD CI only whenever CI signals are needed.

Once the PR is approved or has the ready label, the PR author can also use the corresponding /ci run, /ci retry, and /ci cancel commands, or their /amd-ci variants. New commits do not start upstream CI automatically.

If you have any questions, please reach out to us on Slack at https://slack.vllm.ai.

Agent Guidelines

IMPORTANT: 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.

🚀

@mergify

mergify Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Documentation preview: https://vllm--64935.org.readthedocs.build/en/64935/

@mergify mergify Bot added documentation Improvements or additions to documentation ci/build frontend rust bug Something isn't working labels Nov 1, 2026
The Rust frontend does not serve /v1/chat/completions/batch. Skip the
test when VLLM_USE_RUST_FRONTEND is set instead of deselecting it in
the Buildkite steps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: GCSimba <44427703+GCSimba@users.noreply.github.com>
@DarkLight1337

Copy link
Copy Markdown
Member

Thanks!

@DarkLight1337
DarkLight1337 enabled auto-merge (squash) November 2, 2026 13:09
@DarkLight1337

Copy link
Copy Markdown
Member

/ci run

@github-actions github-actions Bot added the ready ONLY add when PR is ready to merge/full CI is needed label Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite CI #99182 for commit 2a40ba7d5f56.

ℹ️ This PR is 50 commits behind upstream main. Merged upstream main into this branch as 2a40ba7d5f56 before starting CI. Pull the branch before pushing more changes.

@GCSimba

GCSimba commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

@DarkLight1337 The only failing required check is buildkite/ci/pr, from amd-mi355-basic-models-other-shard-2-slash-2: the 26 test_muse_spark_rocm_mono.py failures that #65140 fixed on main 8 minutes after the bot merged main into this branch (the Read the Docs warnings were fixed by #65157 in the same window). As the author I can't start a new run on this commit, and /ci retry would rerun the same snapshot. Could you /ci run again when you have a moment? Auto-merge is already on. Thanks!

@DarkLight1337

Copy link
Copy Markdown
Member

/ci retry

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite CI #99937 for commit b068fa37c053, running 1 failed step(s) from Buildkite CI #99182.

@DarkLight1337
DarkLight1337 merged commit e4991c1 into vllm-project:main Nov 4, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ci/build documentation Improvements or additions to documentation frontend ready ONLY add when PR is ready to merge/full CI is needed rust

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants