@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 0d4044edd8
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 10, 19:00 UTC

fix no think of GLM-4.5 / GLM-4.7 (#31449)

Signed-off-by: zRzRzRzRzRzRzR <2448370773@qq.com>

Yuxuan Zhang committed Jan 4, 2026 at 11:43 UTC 0d4044edd85de30d7d4558aeea4d1e95c7c556d6
1 file changed +4 -163
vllm/reasoning/glm4_moe_reasoning_parser.py
+4 -163
@@ -1,171 +1,12 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 -from collections.abc import Sequence
4 +from vllm.reasoning.deepseek_r1_reasoning_parser import DeepSeekR1ReasoningParser
5
6 -from transformers import PreTrainedTokenizerBase
6
8 -from vllm.entrypoints.openai.protocol import ChatCompletionRequest, DeltaMessage
9 -from vllm.logger import init_logger
10 -from vllm.reasoning import ReasoningParser
11 -
12 -logger = init_logger(__name__)
13 -
14 -
15 -class Glm4MoeModelReasoningParser(ReasoningParser):
7 +class Glm4MoeModelReasoningParser(DeepSeekR1ReasoningParser):
8 """
17 - Reasoning parser for the Glm4MoeModel model.
18 -
19 - The Glm4MoeModel model uses <think>...</think> tokens to denote reasoning
20 - text within its output. The model provides a strict switch to disable
21 - reasoning output via the 'enable_thinking=False' parameter. This parser
22 - extracts the reasoning content enclosed by <think> and </think> tokens
23 - from the model's output.
9 + Reasoning parser for the Glm4MoeModel model is same as DeepSeekR1ReasoningParser.
10 """
11
26 - def __init__(self, tokenizer: PreTrainedTokenizerBase, *args, **kwargs):
27 - super().__init__(tokenizer, *args, **kwargs)
28 - self.think_start_token = "<think>"
29 - self.think_end_token = "</think>"
30 - self.assistant_token = "<|assistant|>"
31 -
32 - if not self.model_tokenizer:
33 - raise ValueError(
34 - "The model tokenizer must be passed to the ReasoningParser "
35 - "constructor during construction."
36 - )
37 -
38 - self.think_start_token_id = self.vocab.get(self.think_start_token)
39 - self.think_end_token_id = self.vocab.get(self.think_end_token)
40 - self.assistant_token_id = self.vocab.get(self.assistant_token)
41 - if (
42 - self.think_start_token_id is None
43 - or self.think_end_token_id is None
44 - or self.assistant_token_id is None
45 - ):
46 - raise RuntimeError(
47 - "Glm4MoeModel reasoning parser could not locate "
48 - "think start/end or assistant tokens in the tokenizer!"
49 - )
50 -
51 - def is_reasoning_end(self, input_ids: list[int]) -> bool:
52 - """
53 - GLM's chat template has <think></think> tokens after every
54 - <|assistant|> token. Thus, we need to check if </think> is
55 - after the most recent <|assistant|> token (if present).
56 - """
57 - for token_id in input_ids[::-1]:
58 - if token_id == self.think_end_token_id:
59 - return True
60 - elif token_id == self.assistant_token_id:
61 - return False
62 - return False
63 -
64 - def extract_content_ids(self, input_ids: list[int]) -> list[int]:
65 - """
66 - Extract the content after the end tokens
67 - """
68 - if self.think_end_token_id not in input_ids[:-1]:
69 - return []
70 - else:
71 - return input_ids[input_ids.index(self.think_end_token_id) + 1 :]
72 -
73 - def extract_reasoning_streaming(
74 - self,
75 - previous_text: str,
76 - current_text: str,
77 - delta_text: str,
78 - previous_token_ids: Sequence[int],
79 - current_token_ids: Sequence[int],
80 - delta_token_ids: Sequence[int],
81 - ) -> DeltaMessage | None:
82 - """
83 - Extract reasoning content from a delta message.
84 - Handles streaming output where previous + delta = current.
85 - Uses token IDs for faster processing.
86 - For text <think>abc</think>xyz:
87 - - 'abc' goes to reasoning
88 - - 'xyz' goes to content
89 - """
90 - # Skip single special tokens
91 - if len(delta_token_ids) == 1 and (
92 - delta_token_ids[0] in [self.think_start_token_id, self.think_end_token_id]
93 - ):
94 - return None
95 -
96 - if self.think_start_token_id in previous_token_ids:
97 - if self.think_end_token_id in delta_token_ids:
98 - # <think> in previous, </think> in delta,
99 - # extract reasoning content
100 - end_index = delta_text.find(self.think_end_token)
101 - reasoning = delta_text[:end_index]
102 - content = delta_text[end_index + len(self.think_end_token) :]
103 - return DeltaMessage(
104 - reasoning=reasoning,
105 - content=content if content else None,
106 - )
107 - elif self.think_end_token_id in previous_token_ids:
108 - # <think> in previous, </think> in previous,
109 - # reasoning content continues
110 - return DeltaMessage(content=delta_text)
111 - else:
112 - # <think> in previous, no </think> in previous or delta,
113 - # reasoning content continues
114 - return DeltaMessage(reasoning=delta_text)
115 - elif self.think_start_token_id in delta_token_ids:
116 - if self.think_end_token_id in delta_token_ids:
117 - # <think> in delta, </think> in delta, extract reasoning content
118 - start_index = delta_text.find(self.think_start_token)
119 - end_index = delta_text.find(self.think_end_token)
120 - reasoning = delta_text[
121 - start_index + len(self.think_start_token) : end_index
122 - ]
123 - content = delta_text[end_index + len(self.think_end_token) :]
124 - return DeltaMessage(
125 - reasoning=reasoning,
126 - content=content if content else None,
127 - )
128 - else:
129 - # <think> in delta, no </think> in delta,
130 - # reasoning content continues
131 - return DeltaMessage(reasoning=delta_text)
132 - else:
133 - # thinking is disabled, just content
134 - return DeltaMessage(content=delta_text)
135 -
136 - def extract_reasoning(
137 - self, model_output: str, request: ChatCompletionRequest
138 - ) -> tuple[str | None, str | None]:
139 - """
140 - Extract reasoning content from the model output.
141 -
142 - For text <think>abc</think>xyz:
143 - - 'abc' goes to reasoning
144 - - 'xyz' goes to content
145 -
146 - Returns:
147 - tuple[Optional[str], Optional[str]]: reasoning content and content
148 - """
149 -
150 - # Check if the model output contains the <think> and </think> tokens.
151 - if (
152 - self.think_start_token not in model_output
153 - or self.think_end_token not in model_output
154 - ):
155 - return None, model_output
156 - # Check if the <think> is present in the model output, remove it
157 - # if it is present.
158 - model_output_parts = model_output.partition(self.think_start_token)
159 - model_output = (
160 - model_output_parts[2] if model_output_parts[1] else model_output_parts[0]
161 - )
162 - # Check if the model output contains the </think> tokens.
163 - # If the end token is not found, return the model output as is.
164 - if self.think_end_token not in model_output:
165 - return None, model_output
166 -
167 - # Extract reasoning content from the model output.
168 - reasoning, _, content = model_output.partition(self.think_end_token)
169 -
170 - final_content = content or None
171 - return reasoning, final_content
12 + pass