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