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 2, 04:45 UTC
[Refactor] Remove dead code from parser infrastructure (#44279)
Signed-off-by: sfeng33 <4florafeng@gmail.com>
Flora Feng committed
Jun 2, 2026 at 12:08 UTC
478b49ddec6685a4afe39c34fbe03d73d15a469b
5 files changed
+35
-328
tests/parser/test_streaming.py
+6
-4
@@ -7,7 +7,7 @@ import pytest
7
8
from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionRequest
9
from vllm.entrypoints.openai.engine.protocol import DeltaMessage
10
-from vllm.parser.abstract_parser import _WrappedParser
10
+from vllm.parser.abstract_parser import DelegatingParser
11
from vllm.reasoning.basic_parsers import BaseThinkingReasoningParser
12
from vllm.tool_parsers.hermes_tool_parser import Hermes2ProToolParser
13
@@ -45,9 +45,11 @@ def request_obj():
45
46
47
def make_parser(tokenizer, reasoning=False, tool=False):
48
- _WrappedParser.reasoning_parser_cls = ThinkReasoningParser if reasoning else None
49
- _WrappedParser.tool_parser_cls = Hermes2ProToolParser if tool else None
50
- return _WrappedParser(tokenizer)
48
+ class TestParser(DelegatingParser):
49
+ reasoning_parser_cls = ThinkReasoningParser if reasoning else None
50
+ tool_parser_cls = Hermes2ProToolParser if tool else None
51
+
52
+ return TestParser(tokenizer)
53
54
55
def stream_text(parser, tokenizer, text, request, prompt_token_ids=None):
vllm/parser/__init__.py
-18
@@ -4,7 +4,6 @@
4
from vllm.parser.abstract_parser import (
5
DelegatingParser,
6
Parser,
7
- _WrappedParser,
7
)
8
from vllm.parser.parser_manager import ParserManager
9
@@ -12,21 +11,4 @@ __all__ = [
11
"Parser",
12
"DelegatingParser",
13
"ParserManager",
15
- "_WrappedParser",
14
]
17
-
18
-_PARSERS_TO_REGISTER = {
19
- "minimax_m2": ( # name
20
- "minimax_m2_parser", # filename
21
- "MiniMaxM2Parser", # class_name
22
- ),
23
-}
24
-
25
-
26
-def register_lazy_parsers():
27
- for name, (file_name, class_name) in _PARSERS_TO_REGISTER.items():
28
- module_path = f"vllm.parser.{file_name}"
29
- ParserManager.register_lazy_module(name, module_path, class_name)
30
-
31
-
32
-register_lazy_parsers()
vllm/parser/abstract_parser.py
+15
-41
@@ -37,12 +37,11 @@ from vllm.entrypoints.openai.responses.protocol import ResponsesRequest
37
from vllm.logger import init_logger
38
from vllm.reasoning.abs_reasoning_parsers import ReasoningParser
39
from vllm.tokenizers import TokenizerLike
40
-from vllm.tool_parsers.abstract_tool_parser import ToolParser
40
+from vllm.tool_parsers.abstract_tool_parser import Tool, ToolParser
41
from vllm.tool_parsers.streaming import (
42
extract_named_tool_call_streaming,
43
extract_required_tool_call_streaming,
44
)
45
-from vllm.tool_parsers.utils import Tool
45
from vllm.utils import random_uuid
46
from vllm.utils.mistral import is_mistral_tool_parser
47
@@ -91,19 +90,25 @@ class Parser:
90
reasoning_parser_cls: type[ReasoningParser] | None = None
91
tool_parser_cls: type[ToolParser] | None = None
92
94
- def __init__(self, tokenizer: TokenizerLike, *args, **kwargs):
95
- """
96
- Initialize the Parser.
97
-
98
- Args:
99
- tokenizer: The tokenizer used by the model. This is required for
100
- token-based parsing operations.
101
- """
93
+ def __init__(
94
+ self,
95
+ tokenizer: TokenizerLike,
96
+ tools: list[Tool] | None = None,
97
+ *args,
98
+ **kwargs,
99
+ ):
100
self.model_tokenizer = tokenizer
101
self._reasoning_parser: ReasoningParser | None = None
102
self._tool_parser: ToolParser | None = None
103
self._stream_state = StreamState()
104
105
+ if self.__class__.reasoning_parser_cls is not None:
106
+ self._reasoning_parser = self.__class__.reasoning_parser_cls(
107
+ tokenizer, *args, **kwargs
108
+ )
109
+ if self.__class__.tool_parser_cls is not None:
110
+ self._tool_parser = self.__class__.tool_parser_cls(tokenizer, tools)
111
+
112
@cached_property
113
def vocab(self) -> dict[str, int]:
114
"""Get the vocabulary mapping from tokens to IDs."""
@@ -893,34 +898,3 @@ class DelegatingParser(Parser):
898
self._append_unstreamed_tool_args(delta_message)
899
900
return delta_message
896
-
897
-
898
-class _WrappedParser(DelegatingParser):
899
- """
900
- A DelegatingParser subclass that instantiates parsers from class attributes.
901
-
902
- This class is used to dynamically create a parser that wraps individual
903
- ReasoningParser and ToolParser classes. The class attributes
904
- `reasoning_parser_cls` and `tool_parser_cls` should be set before
905
- instantiation.
906
-
907
- Usage:
908
- _WrappedParser.reasoning_parser_cls = MyReasoningParser
909
- _WrappedParser.tool_parser_cls = MyToolParser
910
- parser = _WrappedParser(tokenizer)
911
- """
912
-
913
- reasoning_parser_cls: type[ReasoningParser] | None = None
914
- tool_parser_cls: type[ToolParser] | None = None
915
-
916
- def __init__(
917
- self, tokenizer: TokenizerLike, tools: list[Tool] | None = None, **kwargs
918
- ):
919
- super().__init__(tokenizer)
920
- # Instantiate the underlying parsers from class attributes
921
- if self.__class__.reasoning_parser_cls is not None:
922
- self._reasoning_parser = self.__class__.reasoning_parser_cls(
923
- tokenizer, **kwargs
924
- )
925
- if self.__class__.tool_parser_cls is not None:
926
- self._tool_parser = self.__class__.tool_parser_cls(tokenizer, tools)
vllm/parser/minimax_m2_parser.py
deleted
-61
@@ -1,61 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-"""
5
-MiniMax M2 Parser - A unified parser for MiniMax M2 models.
6
-
7
-This parser combines the existing MiniMaxM2ReasoningParser and
8
-MinimaxM2ToolParser into a single unified interface by delegating
9
-to those implementations.
10
-"""
11
-
12
-from vllm.logger import init_logger
13
-from vllm.parser.abstract_parser import DelegatingParser
14
-from vllm.reasoning.minimax_m2_reasoning_parser import MiniMaxM2ReasoningParser
15
-from vllm.tokenizers import TokenizerLike
16
-from vllm.tool_parsers.abstract_tool_parser import (
17
- Tool,
18
-)
19
-from vllm.tool_parsers.minimax_m2_tool_parser import MinimaxM2ToolParser
20
-
21
-logger = init_logger(__name__)
22
-
23
-
24
-class MiniMaxM2Parser(DelegatingParser):
25
- """
26
- Unified parser for MiniMax M2 models that handles both reasoning
27
- extraction and tool call parsing.
28
-
29
- This parser delegates to the existing implementations:
30
- - MiniMaxM2ReasoningParser for reasoning extraction
31
- - MinimaxM2ToolParser for tool call parsing
32
-
33
- MiniMax M2 models have two special behaviors:
34
- 1. Reasoning: They don't generate <think> start token, only </think> end
35
- token. All content before </think> is reasoning, content after is the
36
- actual response.
37
- 2. Tool Calls: They use <minimax:tool_call>...</minimax:tool_call> tags
38
- with <invoke name="...">...</invoke> and <parameter name="...">...</parameter>
39
- syntax.
40
- """
41
-
42
- # Class-level parser classes for compatibility
43
- reasoning_parser_cls = MiniMaxM2ReasoningParser
44
- tool_parser_cls = MinimaxM2ToolParser
45
-
46
- def __init__(
47
- self,
48
- tokenizer: TokenizerLike,
49
- tools: list[Tool] | None = None,
50
- *args,
51
- **kwargs,
52
- ):
53
- super().__init__(tokenizer, *args, **kwargs)
54
-
55
- # Initialize the underlying parsers
56
- self._reasoning_parser = MiniMaxM2ReasoningParser(tokenizer, *args, **kwargs)
57
- self._tool_parser = MinimaxM2ToolParser(tokenizer, tools)
58
-
59
- logger.debug(
60
- "vLLM Successfully initialized parser %s!", self.__class__.__name__
61
- )
vllm/parser/parser_manager.py
+14
-204
@@ -3,14 +3,9 @@
3
4
from __future__ import annotations
5
6
-import importlib
7
-import os
8
-from collections.abc import Callable
6
from typing import TYPE_CHECKING
7
8
from vllm.logger import init_logger
12
-from vllm.utils.collection_utils import is_list_of
13
-from vllm.utils.import_utils import import_from_path
9
10
if TYPE_CHECKING:
11
from vllm.parser.abstract_parser import Parser
@@ -22,170 +17,10 @@ logger = init_logger(__name__)
17
18
class ParserManager:
19
"""
25
- Central registry for Parser implementations.
26
-
27
- Supports two registration modes:
28
- - Eager registration via `register_module`
29
- - Lazy registration via `register_lazy_module`
20
+ Provides a unified Parser by composing individual reasoning and tool
21
+ parsers from their respective registries.
22
"""
23
32
- parsers: dict[str, type[Parser]] = {}
33
- lazy_parsers: dict[str, tuple[str, str]] = {} # name -> (module_path, class_name)
34
-
35
- @classmethod
36
- def get_parser_internal(cls, name: str) -> type[Parser]:
37
- """
38
- Retrieve a registered or lazily registered Parser class.
39
-
40
- Args:
41
- name: The registered name of the parser.
42
-
43
- Returns:
44
- The Parser class.
45
-
46
- Raises:
47
- KeyError: If no parser is found under the given name.
48
- """
49
- if name in cls.parsers:
50
- return cls.parsers[name]
51
-
52
- if name in cls.lazy_parsers:
53
- return cls._load_lazy_parser(name)
54
-
55
- registered = ", ".join(cls.list_registered())
56
- raise KeyError(f"Parser '{name}' not found. Available parsers: {registered}")
57
-
58
- @classmethod
59
- def _load_lazy_parser(cls, name: str) -> type[Parser]:
60
- """Import and register a lazily loaded parser."""
61
- from vllm.parser.abstract_parser import Parser
62
-
63
- module_path, class_name = cls.lazy_parsers[name]
64
- try:
65
- mod = importlib.import_module(module_path)
66
- parser_cls = getattr(mod, class_name)
67
- if not issubclass(parser_cls, Parser):
68
- raise TypeError(
69
- f"{class_name} in {module_path} is not a Parser subclass."
70
- )
71
- cls.parsers[name] = parser_cls # cache
72
- return parser_cls
73
- except Exception as e:
74
- logger.exception(
75
- "Failed to import lazy parser '%s' from %s: %s",
76
- name,
77
- module_path,
78
- e,
79
- )
80
- raise
81
-
82
- @classmethod
83
- def _register_module(
84
- cls,
85
- module: type[Parser],
86
- module_name: str | list[str] | None = None,
87
- force: bool = True,
88
- ) -> None:
89
- """Register a Parser class immediately."""
90
- from vllm.parser.abstract_parser import Parser
91
-
92
- if not issubclass(module, Parser):
93
- raise TypeError(
94
- f"module must be subclass of Parser, but got {type(module)}"
95
- )
96
-
97
- if module_name is None:
98
- module_names = [module.__name__]
99
- elif isinstance(module_name, str):
100
- module_names = [module_name]
101
- elif is_list_of(module_name, str):
102
- module_names = module_name
103
- else:
104
- raise TypeError("module_name must be str, list[str], or None.")
105
-
106
- for name in module_names:
107
- if not force and name in cls.parsers:
108
- existed = cls.parsers[name]
109
- raise KeyError(f"{name} is already registered at {existed.__module__}")
110
- cls.parsers[name] = module
111
-
112
- @classmethod
113
- def register_lazy_module(cls, name: str, module_path: str, class_name: str) -> None:
114
- """
115
- Register a lazy module mapping for delayed import.
116
-
117
- Example:
118
- ParserManager.register_lazy_module(
119
- name="minimax_m2",
120
- module_path="vllm.parser.minimax_m2_parser",
121
- class_name="MiniMaxM2Parser",
122
- )
123
- """
124
- cls.lazy_parsers[name] = (module_path, class_name)
125
-
126
- @classmethod
127
- def register_module(
128
- cls,
129
- name: str | list[str] | None = None,
130
- force: bool = True,
131
- module: type[Parser] | None = None,
132
- ) -> type[Parser] | Callable[[type[Parser]], type[Parser]]:
133
- """
134
- Register a Parser class.
135
-
136
- Can be used as a decorator or called directly.
137
-
138
- Usage:
139
- @ParserManager.register_module("my_parser")
140
- class MyParser(Parser):
141
- ...
142
-
143
- Or:
144
- ParserManager.register_module(module=MyParser)
145
- """
146
- if not isinstance(force, bool):
147
- raise TypeError(f"force must be a boolean, but got {type(force)}")
148
-
149
- # Immediate registration
150
- if module is not None:
151
- cls._register_module(module=module, module_name=name, force=force)
152
- return module
153
-
154
- # Decorator usage
155
- def _decorator(obj: type[Parser]) -> type[Parser]:
156
- module_path = obj.__module__
157
- class_name = obj.__name__
158
-
159
- if isinstance(name, str):
160
- names = [name]
161
- elif name is not None and is_list_of(name, str):
162
- names = name
163
- else:
164
- names = [class_name]
165
-
166
- for n in names:
167
- cls.lazy_parsers[n] = (module_path, class_name)
168
-
169
- return obj
170
-
171
- return _decorator
172
-
173
- @classmethod
174
- def list_registered(cls) -> list[str]:
175
- """Return names of all registered parsers."""
176
- return sorted(set(cls.parsers.keys()) | set(cls.lazy_parsers.keys()))
177
-
178
- @classmethod
179
- def import_parser(cls, plugin_path: str) -> None:
180
- """Import a user-defined parser from an arbitrary path."""
181
- module_name = os.path.splitext(os.path.basename(plugin_path))[0]
182
- try:
183
- import_from_path(module_name, plugin_path)
184
- except Exception:
185
- logger.exception(
186
- "Failed to load module '%s' from %s.", module_name, plugin_path
187
- )
188
-
24
@classmethod
25
def get_tool_parser(
26
cls,
@@ -246,12 +81,10 @@ class ParserManager:
81
model_name: str | None = None,
82
) -> type[Parser] | None:
83
"""
249
- Get a unified Parser that handles both reasoning and tool parsing.
84
+ Get a Parser that handles both reasoning and tool parsing.
85
251
- This method checks if a unified Parser exists that can handle both
252
- reasoning extraction and tool call parsing. If no unified parser
253
- exists, it creates a DelegatingParser that wraps the individual
254
- reasoning and tool parsers.
86
+ Composes individual reasoning and tool parsers into a single
87
+ DelegatingParser subclass.
88
89
Args:
90
tool_parser_name: The name of the tool parser.
@@ -262,37 +95,9 @@ class ParserManager:
95
Returns:
96
A Parser class, or None if neither parser is specified.
97
"""
265
- from vllm.parser.abstract_parser import _WrappedParser
266
-
98
if not tool_parser_name and not reasoning_parser_name:
99
return None
100
270
- # Strategy 1: If both names match, check for a unified parser with that name
271
- if tool_parser_name and tool_parser_name == reasoning_parser_name:
272
- try:
273
- parser = cls.get_parser_internal(tool_parser_name)
274
- logger.info(
275
- "Using unified parser '%s' for both reasoning and tool parsing.",
276
- tool_parser_name,
277
- )
278
- return parser
279
- except KeyError:
280
- pass # No unified parser with this name
281
-
282
- # Strategy 2: Check for parser with either name
283
- for name in [tool_parser_name, reasoning_parser_name]:
284
- if name:
285
- try:
286
- parser = cls.get_parser_internal(name)
287
- logger.info(
288
- "Using unified parser '%s' for reasoning and tool parsing.",
289
- name,
290
- )
291
- return parser
292
- except KeyError:
293
- pass
294
-
295
- # Strategy 3: Create a DelegatingParser with the individual parser classes
101
reasoning_parser_cls = cls.get_reasoning_parser(reasoning_parser_name)
102
tool_parser_cls = cls.get_tool_parser(
103
tool_parser_name, enable_auto_tools, model_name
@@ -301,8 +106,13 @@ class ParserManager:
106
if reasoning_parser_cls is None and tool_parser_cls is None:
107
return None
108
304
- # Set the class-level attributes on the imported _WrappedParser
305
- _WrappedParser.reasoning_parser_cls = reasoning_parser_cls
306
- _WrappedParser.tool_parser_cls = tool_parser_cls
109
+ from vllm.parser.abstract_parser import DelegatingParser
110
+
111
+ r_cls = reasoning_parser_cls
112
+ t_cls = tool_parser_cls
113
+
114
+ class _Parser(DelegatingParser):
115
+ reasoning_parser_cls = r_cls
116
+ tool_parser_cls = t_cls
117
308
- return _WrappedParser
118
+ return _Parser