Skip to main content

Reasoning Outputs

还没翻译译自英文(docs.vllm.ai)本页 69 段都还没译

Reasoning Outputs

vLLM offers support for reasoning models like DeepSeek R1, which are designed to generate outputs containing both reasoning steps and final conclusions.

Reasoning models return an additional reasoning field in their outputs, which contains the reasoning steps that led to the final conclusion. This field is not present in the outputs of other models.

Warning

reasoning used to be called reasoning_content. To migrate, directly replace reasoning_content with reasoning. It is important that you also update your client code. Otherwise, your client code could silently read an empty reasoning_content, even when reasoning is populated.

Supported Models

vLLM currently supports the following reasoning models:

Model SeriesParser NameStructured Output SupportTool Calling
Cohere Command A Reasoningcohere_command3json, regex✅
Cohere Command A Pluscohere_command4json, regex✅
DeepSeek R1 seriesdeepseek_r1json, regex❌
Gemma 4 seriesgemma4json, regex✅
DeepSeek-V3.1deepseek_v3json, regex❌
ERNIE-4.5-VL seriesernie45json, regex❌
ERNIE-4.5-21B-A3B-Thinkingernie45json, regex✅
GLM-4.5 seriesglm45json, regex✅
Holo2 seriesholo2json, regex✅
Hunyuan A13B serieshunyuan_a13bjson, regex✅
IBM Granite 3.2 language modelsgranite❌❌
IBM Granite 4.2 language modelsgranite_thinking_parserjson, regex✅
Kolibri 1hfjson, regex✅
MiniMax-M2minimax_m2_append_thinkjson, regex✅
Qwen3 seriesqwen3json, regex✅
QwQ-32Bdeepseek_r1json, regex✅
Step-3.5 / Step-3.7 Flashstep3p5json, regex✅

Note

IBM Granite 3.2 and DeepSeek-V3.1 reasoning is disabled by default; to enable it, you must also pass thinking=True in your chat_template_kwargs. IBM Granite 4.2 reasoning is enabled by default. To disable it, you must pass enable_thinking=False in your chat_template_kwargs. The reasoning feature for the Qwen3 series is enabled by default. To disable it, you must pass enable_thinking=False in your chat_template_kwargs. Gemma 4 reasoning is disabled by default; to enable it, pass enable_thinking=True in your chat_template_kwargs or set reasoning_effort (which enables it automatically). DeepSeek-V3.1 tool calling is supported in non-thinking mode. Holo2 reasoning is enabled by default. To disable it, you must also pass thinking=False in your chat_template_kwargs. Kolibri 1 reasoning is enabled by default. To disable it, set reasoning_effort="none" or pass enable_thinking=False in your chat_template_kwargs.

Quickstart

To use reasoning models, you need to specify the --reasoning-parser flags when making a request to the chat completion endpoint. The --reasoning-parser flag specifies the reasoning parser to use for extracting reasoning content from the model output.

vllm serve deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B \
    --reasoning-parser deepseek_r1

Next, make a request to the model that should return the reasoning content in the response.

The reasoning field contains the reasoning steps that led to the final conclusion, while the content field contains the final conclusion.

Streaming chat completions

Streaming chat completions are also supported for reasoning models. The reasoning field is available in the delta field in chat completion response chunks.

OpenAI Python client library does not officially support reasoning attribute for streaming output. But the client supports extra attributes in the response. You can use getattr to check if the reasoning attribute is present in the response. For example:

Remember to check whether the reasoning exists in the response before accessing it. You could check out the example.

Tool Calling

The reasoning content is also available when both tool calling and the reasoning parser are enabled. Additionally, tool calling only parses functions from the content field, not from the reasoning.

For more examples, please refer to examples/reasoning/openai_chat_completion_tool_calls_with_reasoning.py.

Server-Level Default Chat Template Kwargs

You can set default chat_template_kwargs at the server level using the --default-chat-template-kwargs CLI argument. This is useful for configuring reasoning behavior across all requests without requiring clients to specify it in each request.

Disabling Thinking Mode by Default

For models like Qwen3 where thinking is enabled by default, you can disable it server-wide:

vllm serve Qwen/Qwen3-8B \
    --reasoning-parser qwen3 \
    --default-chat-template-kwargs '{"enable_thinking": false}'

Enabling Thinking Mode by Default

For models like IBM Granite 3.2 or DeepSeek-V3.1 where thinking is disabled by default, you can enable it server-wide:

vllm serve ibm-granite/granite-3.2-2b-instruct \
    --reasoning-parser granite \
    --default-chat-template-kwargs '{"thinking": true}'

Mapping Reasoning Efforts

Chat templates differ in which reasoning_effort values they recognize, and some silently fall back to another effort (e.g. maximum reasoning) for values they do not know. Use --reasoning-effort-map to rewrite the efforts clients send into ones the template supports. For a template that only recognizes low, high and max:

vllm serve <model> \
    --reasoning-effort-map '{"minimal": "low", "medium": "low", "xhigh": "max"}'

The map applies to the effort set through the Chat Completions (reasoning_effort), Responses (reasoning.effort) and Anthropic Messages (output_config.effort) APIs. Efforts that are not listed pass through unchanged, and a reasoning_effort set directly in chat_template_kwargs is not rewritten. Keys must be one of none, minimal, low, medium, high, xhigh or max; values are passed to the chat template as-is. Mapping an effort to none disables thinking for templates that honor enable_thinking.

Request-Level Override

Request-level chat_template_kwargs always take priority over server defaults. For example, if the server is started with enable_thinking=false, a client can still enable it for a specific request:

response = client.chat.completions.create(
    model=model,
    messages=messages,
    extra_body={"chat_template_kwargs": {"enable_thinking": True}}  # Overrides server default
)

Thinking Budget Control

Some models, such as Qwen3, DeepSeek, and Nemotron3, support a thinking budget that limits the maximum number of tokens used for reasoning.

Token counting starts from reasoning_start_str. Once the reasoning token count reaches the configured thinking_token_budget, vLLM forces the model to produce reasoning_end_str, effectively terminating the reasoning block.

To use this feature:

  • --reasoning-parser enables reasoning extraction.
  • --reasoning-config defines the reasoning boundary tokens (e.g., reasoning_start_str, reasoning_end_str). If not set, vLLM will attempt to automatically initialize these tokens from the reasoning parser.
  • thinking_token_budget (a sampling parameter) sets the per-request reasoning token limit.

If thinking_token_budget is not specified, no explicit reasoning limit is applied beyond normal generation constraints such as max_tokens.

--reasoning-config accepts a JSON object corresponding to
ReasoningConfig with the following fields:

FieldTypeDescription
reasoning_start_strstr | nullString that marks the start of reasoning content
reasoning_end_strstr | nullString that marks the end of reasoning content

Note

reasoning_end_str can include a transition phrase before the reasoning end token. For example, setting reasoning_end_str to "I have to give the solution based on the reasoning directly now.</think>" instructs the model to emit that phrase when the budget is exhausted, making the reasoning termination more natural.

Online Serving

vllm serve Qwen/Qwen3-0.6B \
    --reasoning-parser qwen3 \
    --reasoning-config '{"reasoning_start_str": "<think>", "reasoning_end_str": "I have to give the solution based on the reasoning directly now.</think>"}'

Then make a request with thinking_token_budget to limit the reasoning tokens:

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen3-0.6B",
    "messages": [
      { "role": "user", "content": "9.11 and 9.8, which is greater?" }
    ],
    "thinking_token_budget": 10
  }'

Offline Inference

from vllm import LLM, SamplingParams
from vllm.config import ReasoningConfig

llm = LLM(
    model="Qwen/Qwen3-0.6B",
    reasoning_config=ReasoningConfig(
        reasoning_start_str="<think>",
        reasoning_end_str="I have to give the solution based on the thinking directly now.</think>",
    ),
)

sampling_params = SamplingParams(thinking_token_budget=10)

messages = [
    {"role": "user", "content": "9.11 and 9.8, which is greater?"},
]

outputs = llm.chat(messages, sampling_params=sampling_params)

for output in outputs:
    print("text:", output.outputs[0].text)

Automatic enable_thinking Activation

Some models (such as Gemma 4, DeepSeek-V4-Pro and IBM Granite 3.2) require enable_thinking: true in their chat template kwargs to activate thinking mode — without it, reasoning tokens are never generated regardless of other settings.

When you set reasoning_effort in a Chat Completions request (or reasoning.effort in a Responses API request), vLLM automatically injects enable_thinking into the chat template kwargs:

  • reasoning_effort = "low", "medium", or "high" → enable_thinking = true
  • reasoning_effort = "none" → enable_thinking = false
  • reasoning_effort not set → enable_thinking is not injected (preserves existing behavior)

This means you no longer need to manually pass chat_template_kwargs: {"enable_thinking": true} when using reasoning_effort — it is handled automatically.

Note

If you explicitly set enable_thinking in chat_template_kwargs, your value takes priority over the automatic injection. This allows you to override the behavior if needed.

For models whose templates don't declare enable_thinking (e.g., DeepSeek R1), the injected kwarg is harmlessly filtered out by resolve_chat_template_kwargs.

Example

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")

# reasoning_effort automatically enables thinking for models that need it
response = client.chat.completions.create(
    model="google/gemma-4-26B-A4B-it",
    messages=[{"role": "user", "content": "What is 15 * 37?"}],
    reasoning_effort="high",  # Automatically sets enable_thinking=true
)

print(response.choices[0].message.reasoning)
print(response.choices[0].message.content)

Suppressing Reasoning Output

You can suppress reasoning content from API responses using the include_reasoning parameter. When set to false, reasoning tokens are still generated (so model quality is unaffected) but excluded from the response. This reduces network traffic without changing inference behavior.

The parameter is supported in both the Chat Completions API and the Responses API, for streaming and non-streaming requests.

When include_reasoning=false, vLLM also suppresses per-token metadata (logprobs and token IDs) to prevent leaking reasoning content through decoded token text in logprob entries or raw token IDs.

Chat Completions API

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
model = client.models.list().data[0].id

# Reasoning is included by default (include_reasoning=True)
response = client.chat.completions.create(
    model=model,
    messages=[{"role": "user", "content": "What is 15 * 37?"}],
    extra_body={"include_reasoning": False},
)

msg = response.choices[0].message
assert msg.content  # Content is still present
assert not getattr(msg, "reasoning", None)  # Reasoning is suppressed

Streaming works the same way, reasoning deltas are omitted from chunks:

stream = client.chat.completions.create(
    model=model,
    messages=[{"role": "user", "content": "What is 15 * 37?"}],
    stream=True,
    extra_body={"include_reasoning": False},
)

for chunk in stream:
    delta = chunk.choices[0].delta
    # delta.reasoning will always be None
    if delta.content:
        print(delta.content, end="", flush=True)

Responses API

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")

response = client.responses.create(
    model=client.models.list().data[0].id,
    input="What is 15 * 37?",
    include_reasoning=False,
)

# No "reasoning" items in output
types = [item.type for item in response.output]
assert "reasoning" not in types

Limitations

  • The reasoning content is only available for online serving's chat completion endpoint (/v1/chat/completions), Anthropic Messages API (/v1/messages) and the Responses API (/v1/responses).

How to support a new reasoning model

You can add a new ReasoningParser similar to vllm/reasoning/deepseek_r1_reasoning_parser.py.

Additionally, to enable structured output, you'll need to create a new Reasoner similar to the one in vllm/reasoning/deepseek_r1_reasoning_parser.py.

The structured output engine like xgrammar will use end_token_id to check if the reasoning content is present in the model output and skip the structured output if it is the case.

Finally, you can enable reasoning for the model by using the --reasoning-parser flags.

vllm serve <model_tag> --reasoning-parser example