A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 4, 12:30 UTC
[DSV4] Support `max` reasoning effort (#40982)
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Bugen Zhao committed
Apr 29, 2026 at 19:03 UTC
33f36d42605a476a09ed75936e7c931cb8b432c5
6 files changed
+126
-6
tests/entrypoints/openai/chat_completion/test_chat.py
+25
@@ -1002,6 +1002,31 @@ def test_chat_completion_request_n_parameter_default():
1002
assert sampling_params.n == 1, f"Expected n=1 (default), got n={sampling_params.n}"
1003
1004
1005
+def test_chat_completion_request_accepts_model_specific_reasoning_effort():
1006
+ request = ChatCompletionRequest(
1007
+ model="test-model",
1008
+ messages=[{"role": "user", "content": "Hello"}],
1009
+ reasoning_effort="max",
1010
+ )
1011
+
1012
+ chat_params = request.build_chat_params(
1013
+ default_template=None,
1014
+ default_template_content_format="auto",
1015
+ )
1016
+
1017
+ assert request.reasoning_effort == "max"
1018
+ assert chat_params.chat_template_kwargs["reasoning_effort"] == "max"
1019
+
1020
+
1021
+def test_chat_completion_request_rejects_unknown_reasoning_effort():
1022
+ with pytest.raises(ValueError, match="Input should be"):
1023
+ ChatCompletionRequest(
1024
+ model="test-model",
1025
+ messages=[{"role": "user", "content": "Hello"}],
1026
+ reasoning_effort="extra_high",
1027
+ )
1028
+
1029
+
1030
def test_chat_completion_request_n_parameter_various_values():
1031
"""Test n parameter with various values."""
1032
for n_value in [1, 2, 5, 10]:
tests/entrypoints/openai/parser/test_harmony_utils.py
+7
@@ -843,6 +843,13 @@ class TestGetSystemMessage:
843
f"{channel} missing when with_custom_tools={with_tools}"
844
)
845
846
+ def test_unsupported_reasoning_effort_raises_clear_error(self) -> None:
847
+ with pytest.raises(
848
+ ValueError,
849
+ match="reasoning_effort='max' is not supported by Harmony",
850
+ ):
851
+ get_system_message(reasoning_effort="max")
852
+
853
854
class TestResponseInputToHarmonyReasoningItem:
855
"""Tests for response_input_to_harmony handling of reasoning input items.
tests/tokenizers_/test_deepseek_v4.py
+66
-1
@@ -182,7 +182,7 @@ def test_deepseek_v4_renders_parsed_history_tool_arguments():
182
assert 'parameter name="arguments"' not in prompt
183
184
185
-@pytest.mark.parametrize("reasoning_effort", ["none", "low", "medium", "high"])
185
+@pytest.mark.parametrize("reasoning_effort", ["minimal", "low", "medium", "high"])
186
def test_deepseek_v4_accepts_openai_reasoning_effort_values(reasoning_effort):
187
prompt = _tokenizer().apply_chat_template(
188
[{"role": "user", "content": "Hello"}],
@@ -195,6 +195,58 @@ def test_deepseek_v4_accepts_openai_reasoning_effort_values(reasoning_effort):
195
assert "Reasoning Effort: Absolute maximum" not in prompt
196
197
198
+def test_deepseek_v4_none_reasoning_effort_disables_thinking():
199
+ prompt = _tokenizer().apply_chat_template(
200
+ [{"role": "user", "content": "Hello"}],
201
+ tokenize=False,
202
+ enable_thinking=True,
203
+ reasoning_effort="none",
204
+ )
205
+
206
+ assert prompt == ("<|begin▁of▁sentence|><|User|>Hello<|Assistant|></think>")
207
+
208
+
209
+@pytest.mark.parametrize(
210
+ ("reasoning_effort", "expected_mode", "expected_effort"),
211
+ [
212
+ ("none", "chat", None),
213
+ ("minimal", "thinking", "high"),
214
+ ("low", "thinking", "high"),
215
+ ("medium", "thinking", "high"),
216
+ ("high", "thinking", "high"),
217
+ ("xhigh", "thinking", "max"),
218
+ ("max", "thinking", "max"),
219
+ ("unexpected", "thinking", "high"),
220
+ ],
221
+)
222
+def test_deepseek_v4_maps_compatible_thinking_reasoning_effort_values(
223
+ monkeypatch: pytest.MonkeyPatch,
224
+ reasoning_effort,
225
+ expected_mode,
226
+ expected_effort,
227
+):
228
+ captured_kwargs = []
229
+
230
+ def fake_encode_messages(messages, **kwargs):
231
+ captured_kwargs.append(kwargs)
232
+ return "prompt"
233
+
234
+ monkeypatch.setattr(
235
+ "vllm.tokenizers.deepseek_v4.encode_messages",
236
+ fake_encode_messages,
237
+ )
238
+
239
+ _tokenizer().apply_chat_template(
240
+ [{"role": "user", "content": "Hello"}],
241
+ tokenize=False,
242
+ enable_thinking=True,
243
+ reasoning_effort=reasoning_effort,
244
+ )
245
+
246
+ assert captured_kwargs[-1]["thinking_mode"] == expected_mode
247
+ assert captured_kwargs[-1]["reasoning_effort"] == expected_effort
248
+
249
+
250
def test_deepseek_v4_preserves_reference_max_reasoning_effort():
251
prompt = _tokenizer().apply_chat_template(
252
[{"role": "user", "content": "Hello"}],
@@ -208,6 +260,19 @@ def test_deepseek_v4_preserves_reference_max_reasoning_effort():
260
)
261
262
263
+def test_deepseek_v4_maps_xhigh_to_reference_max_reasoning_effort():
264
+ prompt = _tokenizer().apply_chat_template(
265
+ [{"role": "user", "content": "Hello"}],
266
+ tokenize=False,
267
+ enable_thinking=True,
268
+ reasoning_effort="xhigh",
269
+ )
270
+
271
+ assert prompt.startswith(
272
+ "<|begin▁of▁sentence|>Reasoning Effort: Absolute maximum"
273
+ )
274
+
275
+
276
@pytest.mark.parametrize(
277
("case_id", "kwargs"),
278
[
vllm/entrypoints/openai/chat_completion/protocol.py
+13
-1
@@ -182,7 +182,19 @@ class ChatCompletionRequest(OpenAIBaseModel):
182
| ChatCompletionNamedToolChoiceParam
183
| None
184
) = "none"
185
- reasoning_effort: Literal["none", "low", "medium", "high"] | None = None
185
+ reasoning_effort: (
186
+ Literal["none", "minimal", "low", "medium", "high", "xhigh", "max"] | None
187
+ ) = Field(
188
+ default=None,
189
+ description=(
190
+ "Constrains effort on reasoning for reasoning models. "
191
+ "Currently supported values are none, minimal, low, medium, "
192
+ "high, xhigh, and max. Reducing reasoning effort can result in "
193
+ "faster responses and fewer tokens used on reasoning in a response. "
194
+ "Note that 'max' is specific to the DeepSeek V4 series and is not "
195
+ "part of the standard OpenAI API specification."
196
+ ),
197
+ )
198
thinking_token_budget: int | None = None
199
include_reasoning: bool = True
200
parallel_tool_calls: bool | None = True
vllm/entrypoints/openai/parser/harmony_utils.py
+7
-2
@@ -3,7 +3,6 @@
3
4
import datetime
5
from collections.abc import Iterable, Sequence
6
-from typing import Literal
6
7
from openai.types.responses.tool import Tool
8
from openai_harmony import (
@@ -66,7 +65,7 @@ def get_encoding():
65
66
def get_system_message(
67
model_identity: str | None = None,
69
- reasoning_effort: Literal["high", "medium", "low"] | None = None,
68
+ reasoning_effort: str | None = None,
69
start_date: str | None = None,
70
browser_description: str | None = None,
71
python_description: str | None = None,
@@ -84,6 +83,12 @@ def get_system_message(
83
)
84
sys_msg_content = sys_msg_content.with_model_identity(new_identity)
85
if reasoning_effort is not None:
86
+ if reasoning_effort not in REASONING_EFFORT:
87
+ supported_values = ", ".join(REASONING_EFFORT)
88
+ raise ValueError(
89
+ f"reasoning_effort={reasoning_effort!r} is not supported by "
90
+ f"Harmony. Supported values are: {supported_values}."
91
+ )
92
sys_msg_content = sys_msg_content.with_reasoning_effort(
93
REASONING_EFFORT[reasoning_effort]
94
)
vllm/tokenizers/deepseek_v4.py
+8
-2
@@ -40,10 +40,16 @@ def get_deepseek_v4_tokenizer(tokenizer: HfTokenizer) -> HfTokenizer:
40
messages.insert(0, {"role": "system"})
41
messages[0]["tools"] = tools # type: ignore[typeddict-unknown-key]
42
43
- # The V4 reference currently accepts only "max", "high", or None.
43
reasoning_effort = kwargs.get("reasoning_effort")
45
- if reasoning_effort not in ("max", "high"):
44
+ if not isinstance(reasoning_effort, str):
45
reasoning_effort = None
46
+ elif reasoning_effort == "none":
47
+ thinking_mode = "chat"
48
+ reasoning_effort = None
49
+ elif reasoning_effort in ("max", "xhigh"):
50
+ reasoning_effort = "max"
51
+ else:
52
+ reasoning_effort = "high"
53
54
encode_config = dict(
55
thinking_mode=thinking_mode,