@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / cbe7d18096
Fork 0

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 5, 16:00 UTC

[Misc] Rename think_start_str/think_end_str to reasoning_start_str/reasoning_end_str (#38242)

Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>

Chauncey committed Apr 2, 2026 at 00:56 UTC cbe7d1809649b1a8a954eb155b52d418a5554c4b
5 files changed +55 -49
docs/features/reasoning_outputs.md
+10 -10
@@ -244,12 +244,12 @@ response = client.chat.completions.create(
244
245 Some models, such as [Qwen3](https://qwen.readthedocs.io/en/latest/getting_started/quickstart.html#thinking-budget), [DeepSeek](https://www.alibabacloud.com/help/en/model-studio/deep-thinking), and [Nemotron3](https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16), support a thinking budget that limits the maximum number of tokens used for reasoning.
246
247 -Token counting starts from `think_start_str`. Once the reasoning token count reaches the configured `thinking_token_budget`, vLLM forces the model to produce `think_end_str`, effectively terminating the reasoning block.
247 +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.
248
249 To use this feature:
250
251 - `--reasoning-parser` enables reasoning extraction.
252 -- `--reasoning-config` defines the reasoning boundary tokens (e.g., `think_start_str`, `think_end_str`).
252 +- `--reasoning-config` defines the reasoning boundary tokens (e.g., `reasoning_start_str`, `reasoning_end_str`).
253 - `thinking_token_budget` (a sampling parameter) sets the per-request reasoning token limit.
254
255 If `thinking_token_budget` is not specified, no explicit reasoning limit is applied beyond normal generation constraints such as `max_tokens`.
@@ -257,20 +257,20 @@ If `thinking_token_budget` is not specified, no explicit reasoning limit is appl
257 `--reasoning-config` accepts a JSON object corresponding to
258 [ReasoningConfig][vllm.config.ReasoningConfig] with the following fields:
259
260 -| Field | Type | Description |
261 -|-------------------|----------------|--------------------------------------------------|
262 -| `think_start_str` | `str \| null` | String that marks the start of reasoning content |
263 -| `think_end_str` | `str \| null` | String that marks the end of reasoning content |
260 +| Field | Type | Description |
261 +|-----------------------|----------------|--------------------------------------------------|
262 +| `reasoning_start_str` | `str \| null` | String that marks the start of reasoning content |
263 +| `reasoning_end_str` | `str \| null` | String that marks the end of reasoning content |
264
265 !!! note
266 - `think_end_str` can include a transition phrase before the think end token. For example, setting `think_end_str` to `"I have to give the solution based on the thinking directly now.</think>"` instructs the model to emit that phrase when the budget is exhausted, making the reasoning termination more natural.
266 + `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.
267
268 ### Online Serving
269
270 ```bash
271 vllm serve Qwen/Qwen3-0.6B \
272 --reasoning-parser qwen3 \
273 - --reasoning-config '{"think_start_str": "<think>", "think_end_str": "I have to give the solution based on the thinking directly now.</think>"}'
273 + --reasoning-config '{"reasoning_start_str": "<think>", "reasoning_end_str": "I have to give the solution based on the reasoning directly now.</think>"}'
274 ```
275
276 Then make a request with `thinking_token_budget` to limit the reasoning tokens:
@@ -298,8 +298,8 @@ from vllm.config import ReasoningConfig
298 llm = LLM(
299 model="Qwen/Qwen3-0.6B",
300 reasoning_config=ReasoningConfig(
301 - think_start_str="<think>",
302 - think_end_str="I have to give the solution based on the thinking directly now.</think>",
301 + reasoning_start_str="<think>",
302 + reasoning_end_str="I have to give the solution based on the thinking directly now.</think>",
303 ),
304 )
305
tests/v1/entrypoints/openai/test_thinking_token_budget.py
+1 -1
@@ -20,7 +20,7 @@ def server():
20 "--reasoning-parser",
21 "qwen3",
22 "--reasoning-config",
23 - '{"think_start_str": "<think>", "think_end_str": "</think>"}',
23 + '{"reasoning_start_str": "<think>", "reasoning_end_str": "</think>"}',
24 "--max-model-len",
25 "2048",
26 "--enforce-eager",
tests/v1/logits_processors/test_correctness.py
+4 -4
@@ -103,8 +103,8 @@ class LogitsProcsRequestParams:
103 class MockReasoningConfig:
104 """Mock reasoning config for testing ThinkingTokenBudgetLogitsProcessor."""
105
106 - think_start_token_ids = [THINK_START_TOKEN_ID]
107 - think_end_token_ids = [THINK_END_TOKEN_ID]
106 + reasoning_start_token_ids = [THINK_START_TOKEN_ID]
107 + reasoning_end_token_ids = [THINK_END_TOKEN_ID]
108
109
110 def _generate_fake_sampling_metadata(
@@ -491,7 +491,7 @@ def _thinking_budget_validate(
491
492 # Find if thinking has started in output tokens
493 thinking_started = False
494 - start_tokens = tb_processor.think_start_token_ids
494 + start_tokens = tb_processor.reasoning_start_token_ids
495
496 if len(start_tokens) > 0:
497 for i in range(len(output_tokens) - len(start_tokens) + 1):
@@ -518,7 +518,7 @@ def _thinking_budget_validate(
518 )
519
520 # Validate that only end tokens are allowed
521 - end_tokens = tb_processor.think_end_token_ids
521 + end_tokens = tb_processor.reasoning_end_token_ids
522 if len(end_tokens) > 0:
523 expected_end_token_id = end_tokens[
524 min(state["end_count"], len(end_tokens) - 1)
vllm/config/reasoning.py
+24 -22
@@ -12,7 +12,7 @@ from vllm.tokenizers import cached_tokenizer_from_config
12 class ReasoningConfig:
13 """Configuration for reasoning models.
14
15 - Set `think_start_str` and `think_end_str` to the strings that delimit
15 + Set `reasoning_start_str` and `reasoning_end_str` to the strings that delimit
16 the reasoning block (e.g. `"<think>"` and `"</think>"`). The
17 corresponding token IDs are derived automatically via
18 `initialize_token_ids` and are not intended to be set directly.
@@ -20,53 +20,55 @@ class ReasoningConfig:
20
21 # NOTE: These parameters are temporary, the intent is to derive them
22 # automatically from the reasoning parser in a future version.
23 - think_start_str: str = "<think>"
23 + reasoning_start_str: str = "<think>"
24 """String that indicates the start of reasoning."""
25 - think_end_str: str = "</think>"
25 + reasoning_end_str: str = "</think>"
26 """String that indicates the end of reasoning content."""
27
28 - _think_start_token_ids: list[int] | None = field(
28 + _reasoning_start_token_ids: list[int] | None = field(
29 default=None, init=False, repr=False
30 )
31 - """Private backing field for `think_start_token_ids`. Set by
31 + """Private backing field for `reasoning_start_token_ids`. Set by
32 `initialize_token_ids`. Not intended to be configured directly."""
33 - _think_end_token_ids: list[int] | None = field(default=None, init=False, repr=False)
34 - """Private backing field for `think_end_token_ids`. Set by
33 + _reasoning_end_token_ids: list[int] | None = field(
34 + default=None, init=False, repr=False
35 + )
36 + """Private backing field for `reasoning_end_token_ids`. Set by
37 `initialize_token_ids`. Not intended to be configured directly."""
38
39 @property
38 - def think_start_token_ids(self) -> list[int] | None:
39 - """Token IDs derived from `think_start_str`. Set automatically by
40 + def reasoning_start_token_ids(self) -> list[int] | None:
41 + """Token IDs derived from `reasoning_start_str`. Set automatically by
42 `initialize_token_ids`. Not intended to be configured directly."""
41 - return self._think_start_token_ids
43 + return self._reasoning_start_token_ids
44
45 @property
44 - def think_end_token_ids(self) -> list[int] | None:
45 - """Token IDs derived from `think_end_str`. Set automatically by
46 + def reasoning_end_token_ids(self) -> list[int] | None:
47 + """Token IDs derived from `reasoning_end_str`. Set automatically by
48 `initialize_token_ids`. Not intended to be configured directly."""
47 - return self._think_end_token_ids
49 + return self._reasoning_end_token_ids
50
51 def initialize_token_ids(self, model_config: ModelConfig) -> None:
52 """Initialize reasoning token IDs from strings using the tokenizer."""
53 if (
52 - self._think_start_token_ids is not None
53 - and self._think_end_token_ids is not None
54 + self._reasoning_start_token_ids is not None
55 + and self._reasoning_end_token_ids is not None
56 ):
57 return
58
59 tokenizer = cached_tokenizer_from_config(model_config=model_config)
60
59 - self._think_start_token_ids = tokenizer.encode(
60 - self.think_start_str, add_special_tokens=False
61 + self._reasoning_start_token_ids = tokenizer.encode(
62 + self.reasoning_start_str, add_special_tokens=False
63 )
62 - self._think_end_token_ids = tokenizer.encode(
63 - self.think_end_str, add_special_tokens=False
64 + self._reasoning_end_token_ids = tokenizer.encode(
65 + self.reasoning_end_str, add_special_tokens=False
66 )
67
66 - if not self._think_start_token_ids or not self._think_end_token_ids:
68 + if not self._reasoning_start_token_ids or not self._reasoning_end_token_ids:
69 raise ValueError(
70 f"ReasoningConfig: failed to tokenize reasoning strings: "
69 - f"think_start_str='{self.think_start_str}', "
70 - f"think_end_str='{self.think_end_str}'. "
71 + f"reasoning_start_str='{self.reasoning_start_str}', "
72 + f"reasoning_end_str='{self.reasoning_end_str}'. "
73 "Ensure the strings are valid tokens in the model's vocabulary."
74 )
vllm/v1/sample/logits_processor/builtin.py
+16 -12
@@ -303,10 +303,12 @@ class ThinkingTokenBudgetLogitsProcessor(LogitsProcessor):
303 # Check if thinking is enabled
304 self.is_enabled = reasoning_config is not None
305
306 - self.think_start_token_ids = getattr(
307 - reasoning_config, "think_start_token_ids", []
306 + self.reasoning_start_token_ids = getattr(
307 + reasoning_config, "reasoning_start_token_ids", []
308 + )
309 + self.reasoning_end_token_ids = getattr(
310 + reasoning_config, "reasoning_end_token_ids", []
311 )
309 - self.think_end_token_ids = getattr(reasoning_config, "think_end_token_ids", [])
312
313 self.pin_memory = is_pin_memory
314 self.device = device
@@ -357,15 +359,15 @@ class ThinkingTokenBudgetLogitsProcessor(LogitsProcessor):
359 think_count = 0
360 else:
361 last_start = self._find_last_sequence_index(
360 - prompt_tok_ids, self.think_start_token_ids
362 + prompt_tok_ids, self.reasoning_start_token_ids
363 )
364 last_end = self._find_last_sequence_index(
363 - prompt_tok_ids, self.think_end_token_ids
365 + prompt_tok_ids, self.reasoning_end_token_ids
366 )
367 in_think = last_start > last_end
368 if in_think:
369 think_count = len(prompt_tok_ids) - (
368 - last_start + len(self.think_start_token_ids)
370 + last_start + len(self.reasoning_start_token_ids)
371 )
372 else:
373 think_count = 0
@@ -405,8 +407,8 @@ class ThinkingTokenBudgetLogitsProcessor(LogitsProcessor):
407 state["prev_output_length"] = current_length
408
409 # Check if new tokens contain think start or end sequences
408 - start_len = len(self.think_start_token_ids)
409 - end_len = len(self.think_end_token_ids)
410 + start_len = len(self.reasoning_start_token_ids)
411 + end_len = len(self.reasoning_end_token_ids)
412
413 # Look for think sequences in recent tokens (including boundary)
414 # Check overlapping regions where sequences might span boundaries
@@ -415,10 +417,10 @@ class ThinkingTokenBudgetLogitsProcessor(LogitsProcessor):
417
418 # Find any think start/end sequences in recent tokens
419 recent_start_pos = self._find_last_sequence_index(
418 - recent_tokens, self.think_start_token_ids
420 + recent_tokens, self.reasoning_start_token_ids
421 )
422 recent_end_pos = self._find_last_sequence_index(
421 - recent_tokens, self.think_end_token_ids
423 + recent_tokens, self.reasoning_end_token_ids
424 )
425
426 # Update state based on recent sequences
@@ -469,7 +471,7 @@ class ThinkingTokenBudgetLogitsProcessor(LogitsProcessor):
471 else:
472 # In end mode
473 state["end_count"] += 1
472 - if state["end_count"] >= len(self.think_end_token_ids):
474 + if state["end_count"] >= len(self.reasoning_end_token_ids):
475 state.update(
476 {
477 "in_end": False,
@@ -530,7 +532,9 @@ class ThinkingTokenBudgetLogitsProcessor(LogitsProcessor):
532 state = self._state.get(i)
533 if state and state["in_end"]:
534 self.mask[i] = True
533 - self.force_token_ids[i] = self.think_end_token_ids[state["end_count"]]
535 + self.force_token_ids[i] = self.reasoning_end_token_ids[
536 + state["end_count"]
537 + ]
538
539 # Check in CPU first not to sync with GPU
540 has_active_thinking = any(