@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 34a984274e
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 12, 08:30 UTC

[Misc] Refactor tokenizer interface (#29693)

Signed-off-by: DarkLight1337 <tlleungac@connect.ust.hk>

Cyrus Leung committed Nov 29, 2025 at 20:02 UTC 34a984274eae2f8fb9d1d6413abd08d7fcde741c
119 files changed +758 -827
.buildkite/test-amd.yaml
+2 -2
@@ -316,7 +316,7 @@ steps:
316 source_file_dependencies:
317 - vllm/
318 - tests/engine
319 - - tests/tokenization
319 + - tests/tokenizers_
320 - tests/test_sequence
321 - tests/test_config
322 - tests/test_logger
@@ -324,7 +324,7 @@ steps:
324 commands:
325 - pytest -v -s engine test_sequence.py test_config.py test_logger.py test_vllm_port.py
326 # OOM in the CI unless we run this separately
327 - - pytest -v -s tokenization
327 + - pytest -v -s tokenizers_
328
329 - label: V1 Test e2e + engine # 30min
330 timeout_in_minutes: 45
.buildkite/test-pipeline.yaml
+2 -2
@@ -282,7 +282,7 @@ steps:
282 source_file_dependencies:
283 - vllm/
284 - tests/engine
285 - - tests/tokenization
285 + - tests/tokenizers_
286 - tests/test_sequence
287 - tests/test_config
288 - tests/test_logger
@@ -290,7 +290,7 @@ steps:
290 commands:
291 - pytest -v -s engine test_sequence.py test_config.py test_logger.py test_vllm_port.py
292 # OOM in the CI unless we run this separately
293 - - pytest -v -s tokenization
293 + - pytest -v -s tokenizers_
294
295 - label: V1 Test e2e + engine # 30min
296 timeout_in_minutes: 45
benchmarks/backend_request_func.py
+1 -1
@@ -620,7 +620,7 @@ def get_tokenizer(
620 kwargs["use_fast"] = False
621 if tokenizer_mode == "mistral":
622 try:
623 - from vllm.transformers_utils.tokenizer import MistralTokenizer
623 + from vllm.tokenizers import MistralTokenizer
624 except ImportError as e:
625 raise ImportError(
626 "MistralTokenizer requires vllm package.\n"
docs/features/reasoning_outputs.md
+2 -3
@@ -216,14 +216,13 @@ You can add a new `ReasoningParser` similar to [vllm/reasoning/deepseek_r1_reaso
216 # import the required packages
217
218 from vllm.reasoning import ReasoningParser, ReasoningParserManager
219 - from vllm.entrypoints.openai.protocol import (ChatCompletionRequest,
220 - DeltaMessage)
219 + from vllm.entrypoints.openai.protocol import ChatCompletionRequest, DeltaMessage
220
221 # define a reasoning parser and register it to vllm
222 # the name list in register_module can be used
223 # in --reasoning-parser.
224 class ExampleParser(ReasoningParser):
226 - def __init__(self, tokenizer: AnyTokenizer):
225 + def __init__(self, tokenizer: TokenizerLike):
226 super().__init__(tokenizer)
227
228 def extract_reasoning_streaming(
docs/features/tool_calling.md
+1 -1
@@ -422,7 +422,7 @@ Here is a summary of a plugin file:
422 # in --tool-call-parser. you can define as many
423 # tool parsers as you want here.
424 class ExampleToolParser(ToolParser):
425 - def __init__(self, tokenizer: AnyTokenizer):
425 + def __init__(self, tokenizer: TokenizerLike):
426 super().__init__(tokenizer)
427
428 # adjust request. e.g.: set skip special tokens
tests/entrypoints/openai/test_serving_engine.py
+1 -1
@@ -10,7 +10,7 @@ import pytest
10 from vllm.config import ModelConfig
11 from vllm.entrypoints.openai.serving_engine import OpenAIServing
12 from vllm.entrypoints.openai.serving_models import OpenAIServingModels
13 -from vllm.transformers_utils.tokenizers.mistral import MistralTokenizer
13 +from vllm.tokenizers import MistralTokenizer
14
15
16 @pytest.fixture()
tests/entrypoints/openai/tool_parsers/conftest.py
+2 -2
@@ -4,9 +4,9 @@
4 import pytest
5 from transformers import AutoTokenizer
6
7 -from vllm.transformers_utils.tokenizer import AnyTokenizer
7 +from vllm.tokenizers import TokenizerLike
8
9
10 @pytest.fixture(scope="function")
11 -def default_tokenizer() -> AnyTokenizer:
11 +def default_tokenizer() -> TokenizerLike:
12 return AutoTokenizer.from_pretrained("gpt2")
tests/entrypoints/openai/tool_parsers/test_hermes_tool_parser.py
+6 -6
@@ -7,7 +7,7 @@ import pytest
7
8 from vllm.entrypoints.openai.protocol import ChatCompletionRequest
9 from vllm.entrypoints.openai.tool_parsers.hermes_tool_parser import Hermes2ProToolParser
10 -from vllm.transformers_utils.tokenizer import AnyTokenizer
10 +from vllm.tokenizers import TokenizerLike
11
12 from ....utils import RemoteOpenAIServer
13
@@ -270,14 +270,14 @@ async def test_streaming_product_tool_call():
270
271
272 @pytest.fixture
273 -def qwen_tokenizer() -> AnyTokenizer:
273 +def qwen_tokenizer() -> TokenizerLike:
274 from vllm.transformers_utils.tokenizer import get_tokenizer
275
276 return get_tokenizer("Qwen/Qwen3-32B")
277
278
279 @pytest.fixture
280 -def hermes_parser(qwen_tokenizer: AnyTokenizer) -> Hermes2ProToolParser:
280 +def hermes_parser(qwen_tokenizer: TokenizerLike) -> Hermes2ProToolParser:
281 return Hermes2ProToolParser(qwen_tokenizer)
282
283
@@ -291,7 +291,7 @@ def any_chat_request() -> ChatCompletionRequest:
291
292
293 def test_hermes_parser_streaming_just_forward_text(
294 - qwen_tokenizer: AnyTokenizer,
294 + qwen_tokenizer: TokenizerLike,
295 hermes_parser: Hermes2ProToolParser,
296 any_chat_request: ChatCompletionRequest,
297 ) -> None:
@@ -323,7 +323,7 @@ def test_hermes_parser_streaming_just_forward_text(
323
324
325 def test_hermes_parser_streaming_failure_case_bug_19056(
326 - qwen_tokenizer: AnyTokenizer,
326 + qwen_tokenizer: TokenizerLike,
327 hermes_parser: Hermes2ProToolParser,
328 any_chat_request: ChatCompletionRequest,
329 ) -> None:
@@ -357,7 +357,7 @@ def test_hermes_parser_streaming_failure_case_bug_19056(
357
358
359 def test_hermes_parser_streaming(
360 - qwen_tokenizer: AnyTokenizer,
360 + qwen_tokenizer: TokenizerLike,
361 hermes_parser: Hermes2ProToolParser,
362 any_chat_request: ChatCompletionRequest,
363 ) -> None:
tests/entrypoints/openai/tool_parsers/test_llama3_json_tool_parser.py
+2 -2
@@ -7,11 +7,11 @@ import pytest
7
8 from vllm.entrypoints.openai.protocol import ExtractedToolCallInformation
9 from vllm.entrypoints.openai.tool_parsers.llama_tool_parser import Llama3JsonToolParser
10 -from vllm.transformers_utils.tokenizer import AnyTokenizer
10 +from vllm.tokenizers import TokenizerLike
11
12
13 @pytest.fixture
14 -def parser(default_tokenizer: AnyTokenizer):
14 +def parser(default_tokenizer: TokenizerLike):
15 return Llama3JsonToolParser(default_tokenizer)
16
17
tests/entrypoints/openai/tool_parsers/test_llama4_pythonic_tool_parser.py
+5 -5
@@ -11,7 +11,7 @@ from tests.entrypoints.openai.tool_parsers.utils import (
11 )
12 from vllm.entrypoints.openai.protocol import FunctionCall
13 from vllm.entrypoints.openai.tool_parsers import ToolParser, ToolParserManager
14 -from vllm.transformers_utils.tokenizer import AnyTokenizer
14 +from vllm.tokenizers import TokenizerLike
15
16 # Test cases similar to pythonic parser but with Llama4 specific format
17 SIMPLE_FUNCTION_OUTPUT = "[get_weather(city='LA', metric='C')]"
@@ -64,7 +64,7 @@ PYTHON_TAG_FUNCTION_OUTPUT = (
64
65
66 @pytest.mark.parametrize("streaming", [True, False])
67 -def test_no_tool_call(streaming: bool, default_tokenizer: AnyTokenizer):
67 +def test_no_tool_call(streaming: bool, default_tokenizer: TokenizerLike):
68 tool_parser: ToolParser = ToolParserManager.get_tool_parser("llama4_pythonic")(
69 default_tokenizer
70 )
@@ -208,7 +208,7 @@ def test_tool_call(
208 streaming: bool,
209 model_output: str,
210 expected_tool_calls: list[FunctionCall],
211 - default_tokenizer: AnyTokenizer,
211 + default_tokenizer: TokenizerLike,
212 ):
213 tool_parser: ToolParser = ToolParserManager.get_tool_parser("llama4_pythonic")(
214 default_tokenizer
@@ -224,7 +224,7 @@ def test_tool_call(
224 assert actual.function == expected
225
226
227 -def test_streaming_tool_call_with_large_steps(default_tokenizer: AnyTokenizer):
227 +def test_streaming_tool_call_with_large_steps(default_tokenizer: TokenizerLike):
228 tool_parser: ToolParser = ToolParserManager.get_tool_parser("llama4_pythonic")(
229 default_tokenizer
230 )
@@ -246,7 +246,7 @@ def test_streaming_tool_call_with_large_steps(default_tokenizer: AnyTokenizer):
246
247
248 @pytest.mark.parametrize("streaming", [False])
249 -def test_regex_timeout_handling(streaming: bool, default_tokenizer: AnyTokenizer):
249 +def test_regex_timeout_handling(streaming: bool, default_tokenizer: TokenizerLike):
250 """test regex timeout is handled gracefully"""
251 tool_parser: ToolParser = ToolParserManager.get_tool_parser("llama4_pythonic")(
252 default_tokenizer
tests/entrypoints/openai/tool_parsers/test_olmo3_tool_parser.py
+5 -5
@@ -11,7 +11,7 @@ from tests.entrypoints.openai.tool_parsers.utils import (
11 )
12 from vllm.entrypoints.openai.protocol import FunctionCall
13 from vllm.entrypoints.openai.tool_parsers import ToolParser, ToolParserManager
14 -from vllm.transformers_utils.tokenizer import AnyTokenizer
14 +from vllm.tokenizers import TokenizerLike
15
16 # https://github.com/meta-llama/llama-models/blob/main/models/llama3_2/text_prompt_format.md#model-response-format-1
17 SIMPLE_FUNCTION_OUTPUT = "get_weather(city='San Francisco', metric='celsius')"
@@ -69,7 +69,7 @@ ESCAPED_STRING_FUNCTION_CALL = FunctionCall(
69
70
71 @pytest.mark.parametrize("streaming", [True, False])
72 -def test_no_tool_call(streaming: bool, default_tokenizer: AnyTokenizer):
72 +def test_no_tool_call(streaming: bool, default_tokenizer: TokenizerLike):
73 tool_parser: ToolParser = ToolParserManager.get_tool_parser("olmo3")(
74 default_tokenizer
75 )
@@ -188,7 +188,7 @@ def test_tool_call(
188 streaming: bool,
189 model_output: str,
190 expected_tool_calls: list[FunctionCall],
191 - default_tokenizer: AnyTokenizer,
191 + default_tokenizer: TokenizerLike,
192 ):
193 tool_parser: ToolParser = ToolParserManager.get_tool_parser("olmo3")(
194 default_tokenizer
@@ -205,7 +205,7 @@ def test_tool_call(
205 assert actual.function == expected
206
207
208 -def test_streaming_tool_call_with_large_steps(default_tokenizer: AnyTokenizer):
208 +def test_streaming_tool_call_with_large_steps(default_tokenizer: TokenizerLike):
209 tool_parser: ToolParser = ToolParserManager.get_tool_parser("olmo3")(
210 default_tokenizer
211 )
@@ -228,7 +228,7 @@ def test_streaming_tool_call_with_large_steps(default_tokenizer: AnyTokenizer):
228
229
230 @pytest.mark.parametrize("streaming", [False])
231 -def test_regex_timeout_handling(streaming: bool, default_tokenizer: AnyTokenizer):
231 +def test_regex_timeout_handling(streaming: bool, default_tokenizer: TokenizerLike):
232 """test regex timeout is handled gracefully"""
233 tool_parser: ToolParser = ToolParserManager.get_tool_parser("olmo3")(
234 default_tokenizer
tests/entrypoints/openai/tool_parsers/test_pythonic_tool_parser.py
+5 -5
@@ -11,7 +11,7 @@ from tests.entrypoints.openai.tool_parsers.utils import (
11 )
12 from vllm.entrypoints.openai.protocol import FunctionCall
13 from vllm.entrypoints.openai.tool_parsers import ToolParser, ToolParserManager
14 -from vllm.transformers_utils.tokenizer import AnyTokenizer
14 +from vllm.tokenizers import TokenizerLike
15
16 # https://github.com/meta-llama/llama-models/blob/main/models/llama3_2/text_prompt_format.md#model-response-format-1
17 SIMPLE_FUNCTION_OUTPUT = "get_weather(city='San Francisco', metric='celsius')"
@@ -61,7 +61,7 @@ ESCAPED_STRING_FUNCTION_CALL = FunctionCall(
61
62
63 @pytest.mark.parametrize("streaming", [True, False])
64 -def test_no_tool_call(streaming: bool, default_tokenizer: AnyTokenizer):
64 +def test_no_tool_call(streaming: bool, default_tokenizer: TokenizerLike):
65 tool_parser: ToolParser = ToolParserManager.get_tool_parser("pythonic")(
66 default_tokenizer
67 )
@@ -168,7 +168,7 @@ def test_tool_call(
168 streaming: bool,
169 model_output: str,
170 expected_tool_calls: list[FunctionCall],
171 - default_tokenizer: AnyTokenizer,
171 + default_tokenizer: TokenizerLike,
172 ):
173 tool_parser: ToolParser = ToolParserManager.get_tool_parser("pythonic")(
174 default_tokenizer
@@ -185,7 +185,7 @@ def test_tool_call(
185 assert actual.function == expected
186
187
188 -def test_streaming_tool_call_with_large_steps(default_tokenizer: AnyTokenizer):
188 +def test_streaming_tool_call_with_large_steps(default_tokenizer: TokenizerLike):
189 tool_parser: ToolParser = ToolParserManager.get_tool_parser("pythonic")(
190 default_tokenizer
191 )
@@ -208,7 +208,7 @@ def test_streaming_tool_call_with_large_steps(default_tokenizer: AnyTokenizer):
208
209
210 @pytest.mark.parametrize("streaming", [False])
211 -def test_regex_timeout_handling(streaming: bool, default_tokenizer: AnyTokenizer):
211 +def test_regex_timeout_handling(streaming: bool, default_tokenizer: TokenizerLike):
212 """test regex timeout is handled gracefully"""
213 tool_parser: ToolParser = ToolParserManager.get_tool_parser("pythonic")(
214 default_tokenizer
tests/entrypoints/openai/tool_parsers/utils.py
+2 -2
@@ -11,7 +11,7 @@ from vllm.entrypoints.openai.protocol import (
11 ToolCall,
12 )
13 from vllm.entrypoints.openai.tool_parsers import ToolParser
14 -from vllm.transformers_utils.tokenizer import AnyTokenizer
14 +from vllm.tokenizers import TokenizerLike
15
16
17 class StreamingToolReconstructor:
@@ -111,7 +111,7 @@ def run_tool_extraction_nonstreaming(
111 return tool_parser.extract_tool_calls(model_output, request)
112
113
114 -def split_string_into_token_deltas(tokenizer: AnyTokenizer, text: str) -> list[str]:
114 +def split_string_into_token_deltas(tokenizer: TokenizerLike, text: str) -> list[str]:
115 # Split a string into a series of deltas using the provided tokenizer. Each
116 # delta will be the string equivalent of a single token.
117 token_ids = tokenizer.encode(text, add_special_tokens=False)
tests/entrypoints/test_chat_utils.py
+1 -1
@@ -28,8 +28,8 @@ from vllm.multimodal.utils import (
28 encode_image_base64,
29 encode_video_base64,
30 )
31 +from vllm.tokenizers import MistralTokenizer
32 from vllm.transformers_utils.tokenizer import get_tokenizer
32 -from vllm.transformers_utils.tokenizers.mistral import MistralTokenizer
33
34 from ..models.registry import HF_EXAMPLE_MODELS
35 from ..utils import VLLM_PATH
tests/models/language/generation/test_mistral.py
+1 -1
@@ -10,7 +10,7 @@ from vllm.entrypoints.openai.tool_parsers.mistral_tool_parser import (
10 MistralToolParser,
11 )
12 from vllm.sampling_params import SamplingParams
13 -from vllm.transformers_utils.tokenizer import MistralTokenizer
13 +from vllm.tokenizers import MistralTokenizer
14
15 from ...utils import check_logprobs_close
16
tests/models/multimodal/generation/test_voxtral.py
+1 -1
@@ -9,7 +9,7 @@ from mistral_common.audio import Audio
9 from mistral_common.protocol.instruct.chunk import AudioChunk, RawAudio, TextChunk
10 from mistral_common.protocol.instruct.messages import UserMessage
11
12 -from vllm.transformers_utils.tokenizer import MistralTokenizer
12 +from vllm.tokenizers import MistralTokenizer
13
14 from ....conftest import AudioTestAssets
15 from ....utils import RemoteOpenAIServer
tests/models/multimodal/generation/vlm_utils/core.py
+2 -2
@@ -9,7 +9,7 @@ import torch
9 from transformers.models.auto.auto_factory import _BaseAutoModelClass
10
11 from vllm.config.model import RunnerOption
12 -from vllm.transformers_utils.tokenizer import AnyTokenizer
12 +from vllm.tokenizers import TokenizerLike
13
14 from .....conftest import HfRunner, VllmRunner
15 from ....registry import HF_EXAMPLE_MODELS
@@ -33,7 +33,7 @@ def run_test(
33 auto_cls: type[_BaseAutoModelClass],
34 use_tokenizer_eos: bool,
35 comparator: Callable[..., None],
36 - get_stop_token_ids: Callable[[AnyTokenizer], list[int]] | None,
36 + get_stop_token_ids: Callable[[TokenizerLike], list[int]] | None,
37 stop_str: list[str] | None,
38 limit_mm_per_prompt: dict[str, int],
39 vllm_runner_kwargs: dict[str, Any] | None,
tests/models/multimodal/generation/vlm_utils/types.py
+2 -2
@@ -14,7 +14,7 @@ from transformers.models.auto.auto_factory import _BaseAutoModelClass
14
15 from vllm.config.model import RunnerOption
16 from vllm.logprobs import SampleLogprobs
17 -from vllm.transformers_utils.tokenizer import AnyTokenizer
17 +from vllm.tokenizers import TokenizerLike
18
19 from .....conftest import (
20 AUDIO_ASSETS,
@@ -126,7 +126,7 @@ class VLMTestInfo(NamedTuple):
126 vllm_runner_kwargs: dict[str, Any] | None = None
127
128 # Optional callable which gets a list of token IDs from the model tokenizer
129 - get_stop_token_ids: Callable[[AnyTokenizer], list[int]] | None = None
129 + get_stop_token_ids: Callable[[TokenizerLike], list[int]] | None = None
130 # Optional list of strings to stop generation, useful when stop tokens are
131 # not special tokens in the tokenizer
132 stop_str: list[str] | None = None
tests/models/multimodal/processing/test_common.py
+1 -1
@@ -22,8 +22,8 @@ from vllm.multimodal import MULTIMODAL_REGISTRY, MultiModalDataDict
22 from vllm.multimodal.cache import MultiModalProcessorOnlyCache
23 from vllm.multimodal.inputs import MultiModalInputs
24 from vllm.multimodal.processing import BaseMultiModalProcessor, InputProcessingContext
25 +from vllm.tokenizers import MistralTokenizer
26 from vllm.transformers_utils.tokenizer import (
26 - MistralTokenizer,
27 cached_tokenizer_from_config,
28 encode_tokens,
29 )
tests/multimodal/test_processing.py
+10 -11
@@ -1,6 +1,7 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 +import time
5 from contextlib import nullcontext
6 from typing import cast
7
@@ -23,7 +24,7 @@ from vllm.multimodal.processing import (
24 replace_token_matches,
25 )
26 from vllm.multimodal.profiling import MultiModalProfiler
26 -from vllm.transformers_utils.tokenizer import AnyTokenizer
27 +from vllm.tokenizers import TokenizerLike
28
29 from .utils import random_image
30
@@ -238,7 +239,7 @@ def test_find_token_matches(
239 update_type,
240 ):
241 # Should not be used since there is nothing to convert to token IDs
241 - mock_tokenizer = cast(AnyTokenizer, object())
242 + mock_tokenizer = cast(TokenizerLike, object())
243
244 prompt_updates = {
245 key: update_type(key, target, []).resolve(0)
@@ -385,7 +386,7 @@ def test_find_text_matches(
386 update_type,
387 ):
388 # Should not be used since there is nothing to convert to text
388 - mock_tokenizer = cast(AnyTokenizer, object())
389 + mock_tokenizer = cast(TokenizerLike, object())
390
391 prompt_updates = {
392 key: update_type(key, target, []).resolve(0)
@@ -545,7 +546,7 @@ def test_find_update_text(
546 expected_by_update_type_mm_count,
547 ):
548 # Should not be used since there is nothing to convert to text
548 - mock_tokenizer = cast(AnyTokenizer, object())
549 + mock_tokenizer = cast(TokenizerLike, object())
550
551 for (
552 update_type,
@@ -750,7 +751,7 @@ def test_find_update_tokens(
751 expected_by_update_type_mm_count,
752 ):
753 # Should not be used since there is nothing to convert to tokens
753 - mock_tokenizer = cast(AnyTokenizer, object())
754 + mock_tokenizer = cast(TokenizerLike, object())
755
756 for (
757 update_type,
@@ -900,7 +901,7 @@ def test_find_mm_placeholders(
901 update_type,
902 ):
903 # Should not be used since there is nothing to convert to tokens
903 - mock_tokenizer = cast(AnyTokenizer, object())
904 + mock_tokenizer = cast(TokenizerLike, object())
905
906 mm_prompt_updates = {
907 key: [[update_type(key, [], repl).resolve(i)] for i in range(3)]
@@ -1029,7 +1030,7 @@ def test_hf_processor_init_kwargs(
1030 expected_kwargs,
1031 ):
1032 # Should not be used since there is nothing to convert to tokens
1032 - mock_tokenizer = cast(AnyTokenizer, object())
1033 + mock_tokenizer = cast(TokenizerLike, object())
1034
1035 ctx = InputProcessingContext(
1036 model_config=ModelConfig(model_id, mm_processor_kwargs=config_kwargs),
@@ -1065,7 +1066,7 @@ def test_hf_processor_call_kwargs(
1066 expected_kwargs,
1067 ):
1068 # Should not be used since there is nothing to convert to tokens
1068 - mock_tokenizer = cast(AnyTokenizer, object())
1069 + mock_tokenizer = cast(TokenizerLike, object())
1070
1071 ctx = InputProcessingContext(
1072 model_config=ModelConfig(model_id, mm_processor_kwargs=config_kwargs),
@@ -1088,9 +1089,7 @@ def test_apply_matches_no_match_exits_quickly():
1089
1090 With the fix, it should exit immediately when no match is found.
1091 """
1091 - import time
1092 -
1093 - mock_tokenizer = cast(AnyTokenizer, object())
1092 + mock_tokenizer = cast(TokenizerLike, object())
1093
1094 # Create a long prompt with no placeholder
1095 long_prompt = "x" * 10000
tests/reasoning/test_mistral_reasoning_parser.py
+1 -1
@@ -5,7 +5,7 @@ import pytest
5
6 from tests.reasoning.utils import run_reasoning_extraction_mistral
7 from vllm.reasoning import ReasoningParser, ReasoningParserManager
8 -from vllm.transformers_utils.tokenizers.mistral import MistralTokenizer
8 +from vllm.tokenizers import MistralTokenizer
9
10 parser_name = "mistral"
11
tests/reasoning/utils.py
+1 -1
@@ -4,7 +4,7 @@
4
5 from vllm.entrypoints.openai.protocol import ChatCompletionRequest, DeltaMessage
6 from vllm.reasoning import ReasoningParser
7 -from vllm.transformers_utils.tokenizers.mistral import MistralTokenizer
7 +from vllm.tokenizers import MistralTokenizer
8
9
10 class StreamingReasoningReconstructor:
tests/tokenization/__init__.py
tests/tokenization/test_do_lower_case.py deleted
-18
@@ -1,18 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -import pytest
5 -
6 -from vllm.transformers_utils.tokenizer import get_tokenizer
7 -
8 -TOKENIZER_NAMES = ["BAAI/bge-base-en"]
9 -
10 -
11 -@pytest.mark.parametrize("tokenizer_name", TOKENIZER_NAMES)
12 -@pytest.mark.parametrize("n_tokens", [510])
13 -def test_special_tokens(tokenizer_name: str, n_tokens: int):
14 - tokenizer = get_tokenizer(tokenizer_name, revision="main")
15 -
16 - prompts = "[UNK]" * n_tokens
17 - prompt_token_ids = tokenizer.encode(prompts)
18 - assert len(prompt_token_ids) == n_tokens + 2
tests/tokenization/test_get_eos.py deleted
-32
@@ -1,32 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -"""
4 -This test file includes some cases where it is inappropriate to
5 -only get the `eos_token_id` from the tokenizer as defined by
6 -{meth}`vllm.LLMEngine._get_eos_token_id`.
7 -"""
8 -
9 -from vllm.transformers_utils.config import try_get_generation_config
10 -from vllm.transformers_utils.tokenizer import get_tokenizer
11 -
12 -
13 -def test_get_llama3_eos_token():
14 - model_name = "meta-llama/Llama-3.2-1B-Instruct"
15 -
16 - tokenizer = get_tokenizer(model_name)
17 - assert tokenizer.eos_token_id == 128009
18 -
19 - generation_config = try_get_generation_config(model_name, trust_remote_code=False)
20 - assert generation_config is not None
21 - assert generation_config.eos_token_id == [128001, 128008, 128009]
22 -
23 -
24 -def test_get_blip2_eos_token():
25 - model_name = "Salesforce/blip2-opt-2.7b"
26 -
27 - tokenizer = get_tokenizer(model_name)
28 - assert tokenizer.eos_token_id == 2
29 -
30 - generation_config = try_get_generation_config(model_name, trust_remote_code=False)
31 - assert generation_config is not None
32 - assert generation_config.eos_token_id == 50118
tests/tokenization/test_tokenizer.py deleted
-23
@@ -1,23 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -import pytest
5 -from transformers import PreTrainedTokenizerBase
6 -
7 -from vllm.transformers_utils.tokenizer import get_tokenizer
8 -
9 -TOKENIZER_NAMES = [
10 - "facebook/opt-125m",
11 - "gpt2",
12 -]
13 -
14 -
15 -@pytest.mark.parametrize("tokenizer_name", TOKENIZER_NAMES)
16 -def test_tokenizer_revision(tokenizer_name: str):
17 - # Assume that "main" branch always exists
18 - tokenizer = get_tokenizer(tokenizer_name, revision="main")
19 - assert isinstance(tokenizer, PreTrainedTokenizerBase)
20 -
21 - # Assume that "never" branch always does not exist
22 - with pytest.raises(OSError, match="not a valid git identifier"):
23 - get_tokenizer(tokenizer_name, revision="never")
tests/tokenization/test_tokenizer_registry.py deleted
-120
@@ -1,120 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -from typing import TYPE_CHECKING, Any
5 -
6 -from vllm.transformers_utils.tokenizer import get_tokenizer
7 -from vllm.transformers_utils.tokenizer_base import TokenizerBase, TokenizerRegistry
8 -
9 -if TYPE_CHECKING:
10 - from vllm.entrypoints.chat_utils import ChatCompletionMessageParam
11 -
12 -
13 -class TestTokenizer(TokenizerBase):
14 - @classmethod
15 - def from_pretrained(cls, *args, **kwargs) -> "TestTokenizer":
16 - return TestTokenizer()
17 -
18 - @property
19 - def all_special_tokens(self) -> list[str]:
20 - raise NotImplementedError()
21 -
22 - @property
23 - def all_special_ids(self) -> list[int]:
24 - raise NotImplementedError()
25 -
26 - @property
27 - def bos_token_id(self) -> int:
28 - return 0
29 -
30 - @property
31 - def eos_token_id(self) -> int:
32 - return 1
33 -
34 - @property
35 - def sep_token(self) -> str:
36 - raise NotImplementedError()
37 -
38 - @property
39 - def pad_token(self) -> str:
40 - raise NotImplementedError()
41 -
42 - @property
43 - def is_fast(self) -> bool:
44 - raise NotImplementedError()
45 -
46 - @property
47 - def vocab_size(self) -> int:
48 - raise NotImplementedError()
49 -
50 - @property
51 - def max_token_id(self) -> int:
52 - raise NotImplementedError()
53 -
54 - @property
55 - def truncation_side(self) -> str:
56 - raise NotImplementedError()
57 -
58 - def __call__(
59 - self,
60 - text: str | list[str] | list[int],
61 - text_pair: str | None = None,
62 - add_special_tokens: bool = False,
63 - truncation: bool = False,
64 - max_length: int | None = None,
65 - ):
66 - raise NotImplementedError()
67 -
68 - def get_vocab(self) -> dict[str, int]:
69 - raise NotImplementedError()
70 -
71 - def get_added_vocab(self) -> dict[str, int]:
72 - raise NotImplementedError()
73 -
74 - def encode_one(
75 - self,
76 - text: str,
77 - truncation: bool = False,
78 - max_length: int | None = None,
79 - ) -> list[int]:
80 - raise NotImplementedError()
81 -
82 - def encode(self, text: str, add_special_tokens: bool | None = None) -> list[int]:
83 - raise NotImplementedError()
84 -
85 - def apply_chat_template(
86 - self,
87 - messages: list["ChatCompletionMessageParam"],
88 - tools: list[dict[str, Any]] | None = None,
89 - **kwargs,
90 - ) -> list[int]:
91 - raise NotImplementedError()
92 -
93 - def convert_tokens_to_string(self, tokens: list[str]) -> str:
94 - raise NotImplementedError()
95 -
96 - def decode(self, ids: list[int] | int, skip_special_tokens: bool = True) -> str:
97 - raise NotImplementedError()
98 -
99 - def convert_ids_to_tokens(
100 - self,
101 - ids: list[int],
102 - skip_special_tokens: bool = True,
103 - ) -> list[str]:
104 - raise NotImplementedError()
105 -
106 -
107 -def test_customized_tokenizer():
108 - TokenizerRegistry.register(
109 - "test_tokenizer", "tests.tokenization.test_tokenizer_registry", "TestTokenizer"
110 - )
111 -
112 - tokenizer = TokenizerRegistry.get_tokenizer("test_tokenizer")
113 - assert isinstance(tokenizer, TestTokenizer)
114 - assert tokenizer.bos_token_id == 0
115 - assert tokenizer.eos_token_id == 1
116 -
117 - tokenizer = get_tokenizer("test_tokenizer", tokenizer_mode="custom")
118 - assert isinstance(tokenizer, TestTokenizer)
119 - assert tokenizer.bos_token_id == 0
120 - assert tokenizer.eos_token_id == 1
tests/tokenizers_/__init__.py new
+4
@@ -0,0 +1,4 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +# NOTE: Since CI runs the tests from the `tests` directory, it is necessary to rename
4 +# this module to avoid conflicting with HF's `tokenizers` package
tests/tokenizers_/test_basic.py new
+59
@@ -0,0 +1,59 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +from typing import _get_protocol_attrs # type: ignore
4 +
5 +import pytest
6 +from transformers import PreTrainedTokenizerBase
7 +
8 +from vllm.tokenizers import TokenizerLike
9 +from vllm.transformers_utils.tokenizer import get_tokenizer
10 +
11 +
12 +def _get_missing_attrs(obj: object, target: type):
13 + return [k for k in _get_protocol_attrs(target) if not hasattr(obj, k)]
14 +
15 +
16 +def test_tokenizer_like_protocol():
17 + assert not (
18 + missing_attrs := _get_missing_attrs(
19 + get_tokenizer("gpt2", use_fast=False),
20 + TokenizerLike,
21 + )
22 + ), f"Missing attrs: {missing_attrs}"
23 +
24 + assert not (
25 + missing_attrs := _get_missing_attrs(
26 + get_tokenizer("gpt2", use_fast=True),
27 + TokenizerLike,
28 + )
29 + ), f"Missing attrs: {missing_attrs}"
30 +
31 + assert not (
32 + missing_attrs := _get_missing_attrs(
33 + get_tokenizer(
34 + "mistralai/Mistral-7B-Instruct-v0.3", tokenizer_mode="mistral"
35 + ),
36 + TokenizerLike,
37 + )
38 + ), f"Missing attrs: {missing_attrs}"
39 +
40 +
41 +@pytest.mark.parametrize("tokenizer_name", ["facebook/opt-125m", "gpt2"])
42 +def test_tokenizer_revision(tokenizer_name: str):
43 + # Assume that "main" branch always exists
44 + tokenizer = get_tokenizer(tokenizer_name, revision="main")
45 + assert isinstance(tokenizer, PreTrainedTokenizerBase)
46 +
47 + # Assume that "never" branch always does not exist
48 + with pytest.raises(OSError, match="not a valid git identifier"):
49 + get_tokenizer(tokenizer_name, revision="never")
50 +
51 +
52 +@pytest.mark.parametrize("tokenizer_name", ["BAAI/bge-base-en"])
53 +@pytest.mark.parametrize("n_tokens", [510])
54 +def test_special_tokens(tokenizer_name: str, n_tokens: int):
55 + tokenizer = get_tokenizer(tokenizer_name, revision="main")
56 +
57 + prompts = "[UNK]" * n_tokens
58 + prompt_token_ids = tokenizer.encode(prompts)
59 + assert len(prompt_token_ids) == n_tokens + 2
tests/tokenizers_/test_cached_tokenizer.py renamed
+3 -2
@@ -6,7 +6,8 @@ from copy import deepcopy
6 import pytest
7 from transformers import AutoTokenizer
8
9 -from vllm.transformers_utils.tokenizer import AnyTokenizer, get_cached_tokenizer
9 +from vllm.tokenizers import TokenizerLike
10 +from vllm.transformers_utils.tokenizer import get_cached_tokenizer
11
12
13 @pytest.mark.parametrize("model_id", ["gpt2", "zai-org/chatglm3-6b"])
@@ -25,7 +26,7 @@ def test_cached_tokenizer(model_id: str):
26 _check_consistency(unpickled_tokenizer, reference_tokenizer)
27
28
28 -def _check_consistency(target: AnyTokenizer, expected: AnyTokenizer):
29 +def _check_consistency(target: TokenizerLike, expected: TokenizerLike):
30 assert isinstance(target, type(expected))
31
32 # Cached attributes
tests/tokenizers_/test_detokenize.py renamed
+1 -1
@@ -8,7 +8,7 @@ import pytest
8 from transformers import AutoTokenizer, PreTrainedTokenizer, PreTrainedTokenizerFast
9
10 from vllm.sampling_params import SamplingParams
11 -from vllm.transformers_utils.tokenizers.mistral import MistralTokenizer
11 +from vllm.tokenizers import MistralTokenizer
12 from vllm.v1.engine import EngineCoreRequest
13 from vllm.v1.engine.detokenizer import (
14 FastIncrementalDetokenizer,
tests/tokenizers_/test_mistral.py renamed
+1 -20
@@ -7,7 +7,7 @@ import pytest
7 from mistral_common.exceptions import InvalidMessageStructureException
8 from mistral_common.tokens.tokenizers.base import SpecialTokenPolicy
9
10 -from vllm.transformers_utils.tokenizers.mistral import (
10 +from vllm.tokenizers.mistral import (
11 MistralTokenizer,
12 _prepare_apply_chat_template_tools_and_messages,
13 )
@@ -308,25 +308,6 @@ class TestMistralTokenizer:
308 def test_get_added_vocab(self, mistral_tokenizer: MistralTokenizer):
309 assert mistral_tokenizer.get_added_vocab() == {}
310
311 - def test_encode_one(self, mistral_tokenizer: MistralTokenizer):
312 - token_ids = (
313 - [22177, 4304, 2662] if mistral_tokenizer.is_tekken else [23325, 2294, 1686]
314 - )
315 -
316 - assert mistral_tokenizer.encode_one("Hello world !") == token_ids
317 - assert mistral_tokenizer.encode_one("Hello world !", max_length=1) == token_ids
318 - assert (
319 - mistral_tokenizer.encode_one("Hello world !", truncation=True, max_length=1)
320 - == token_ids[:-2]
321 - )
322 - assert (
323 - mistral_tokenizer.encode_one(
324 - "Hello world !", truncation=False, max_length=1
325 - )
326 - == token_ids
327 - )
328 - assert mistral_tokenizer.encode_one("") == []
329 -
311 def test_encode(self, mistral_tokenizer: MistralTokenizer):
312 token_ids = (
313 [1, 22177, 4304, 2662]
tests/tokenizers_/test_registry.py new
+36
@@ -0,0 +1,36 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +from vllm.tokenizers import TokenizerLike, TokenizerRegistry
4 +from vllm.transformers_utils.tokenizer import get_tokenizer
5 +
6 +
7 +class TestTokenizer(TokenizerLike):
8 + @classmethod
9 + def from_pretrained(cls, *args, **kwargs) -> "TestTokenizer":
10 + return TestTokenizer() # type: ignore
11 +
12 + @property
13 + def bos_token_id(self) -> int:
14 + return 0
15 +
16 + @property
17 + def eos_token_id(self) -> int:
18 + return 1
19 +
20 +
21 +def test_customized_tokenizer():
22 + TokenizerRegistry.register(
23 + "test_tokenizer",
24 + __name__,
25 + TestTokenizer.__name__,
26 + )
27 +
28 + tokenizer = TokenizerRegistry.get_tokenizer("test_tokenizer")
29 + assert isinstance(tokenizer, TestTokenizer)
30 + assert tokenizer.bos_token_id == 0
31 + assert tokenizer.eos_token_id == 1
32 +
33 + tokenizer = get_tokenizer("test_tokenizer", tokenizer_mode="custom")
34 + assert isinstance(tokenizer, TestTokenizer)
35 + assert tokenizer.bos_token_id == 0
36 + assert tokenizer.eos_token_id == 1
tests/tool_use/test_ernie45_moe_tool_parser.py
+3 -2
@@ -14,8 +14,9 @@ from vllm.entrypoints.openai.protocol import (
14 ToolCall,
15 )
16 from vllm.entrypoints.openai.tool_parsers.ernie45_tool_parser import Ernie45ToolParser
17 +from vllm.tokenizers import TokenizerLike
18 from vllm.transformers_utils.detokenizer_utils import detokenize_incrementally
18 -from vllm.transformers_utils.tokenizer import AnyTokenizer, get_tokenizer
19 +from vllm.transformers_utils.tokenizer import get_tokenizer
20
21 # Use a common model that is likely to be available
22 MODEL = "baidu/ERNIE-4.5-21B-A3B-Thinking"
@@ -173,7 +174,7 @@ def test_extract_tool_calls(
174
175 def stream_delta_message_generator(
176 ernie45_tool_parser: Ernie45ToolParser,
176 - ernie45_tokenizer: AnyTokenizer,
177 + ernie45_tokenizer: TokenizerLike,
178 model_output: str,
179 request: ChatCompletionRequest | None = None,
180 ) -> Generator[DeltaMessage, None, None]:
tests/tool_use/test_jamba_tool_parser.py
+5 -2
@@ -10,8 +10,9 @@ from partial_json_parser.core.options import Allow
10
11 from vllm.entrypoints.openai.protocol import DeltaMessage, FunctionCall, ToolCall
12 from vllm.entrypoints.openai.tool_parsers.jamba_tool_parser import JambaToolParser
13 +from vllm.tokenizers import TokenizerLike
14 from vllm.transformers_utils.detokenizer_utils import detokenize_incrementally
14 -from vllm.transformers_utils.tokenizer import AnyTokenizer, get_tokenizer
15 +from vllm.transformers_utils.tokenizer import get_tokenizer
16
17 pytestmark = pytest.mark.cpu_test
18
@@ -44,7 +45,9 @@ def assert_tool_calls(
45
46
47 def stream_delta_message_generator(
47 - jamba_tool_parser: JambaToolParser, jamba_tokenizer: AnyTokenizer, model_output: str
48 + jamba_tool_parser: JambaToolParser,
49 + jamba_tokenizer: TokenizerLike,
50 + model_output: str,
51 ) -> Generator[DeltaMessage, None, None]:
52 all_token_ids = jamba_tokenizer.encode(model_output, add_special_tokens=False)
53
tests/tool_use/test_qwen3coder_tool_parser.py
+3 -2
@@ -17,8 +17,9 @@ from vllm.entrypoints.openai.tool_parsers.qwen3coder_tool_parser import (
17 Qwen3CoderToolParser,
18 )
19 from vllm.entrypoints.openai.tool_parsers.qwen3xml_tool_parser import Qwen3XMLToolParser
20 +from vllm.tokenizers import TokenizerLike
21 from vllm.transformers_utils.detokenizer_utils import detokenize_incrementally
21 -from vllm.transformers_utils.tokenizer import AnyTokenizer, get_tokenizer
22 +from vllm.transformers_utils.tokenizer import get_tokenizer
23
24 pytestmark = pytest.mark.cpu_test
25
@@ -104,7 +105,7 @@ def assert_tool_calls(
105
106 def stream_delta_message_generator(
107 qwen3_tool_parser,
107 - qwen3_tokenizer: AnyTokenizer,
108 + qwen3_tokenizer: TokenizerLike,
109 model_output: str,
110 request: ChatCompletionRequest | None = None,
111 ) -> Generator[DeltaMessage, None, None]:
tests/tool_use/test_seed_oss_tool_parser.py
+3 -2
@@ -15,8 +15,9 @@ from vllm.entrypoints.openai.protocol import (
15 ToolCall,
16 )
17 from vllm.entrypoints.openai.tool_parsers.seed_oss_tool_parser import SeedOssToolParser
18 +from vllm.tokenizers import TokenizerLike
19 from vllm.transformers_utils.detokenizer_utils import detokenize_incrementally
19 -from vllm.transformers_utils.tokenizer import AnyTokenizer, get_tokenizer
20 +from vllm.transformers_utils.tokenizer import get_tokenizer
21
22 pytestmark = pytest.mark.cpu_test
23
@@ -256,7 +257,7 @@ def test_streaming_tool_calls_no_tools(seed_oss_tool_parser):
257
258 def stream_delta_message_generator(
259 seed_oss_tool_parser: SeedOssToolParser,
259 - seed_oss_tokenizer: AnyTokenizer,
260 + seed_oss_tokenizer: TokenizerLike,
261 model_output: str,
262 request: ChatCompletionRequest | None = None,
263 ) -> Generator[DeltaMessage, None, None]:
tests/tool_use/test_xlam_tool_parser.py
+3 -2
@@ -13,8 +13,9 @@ from vllm.entrypoints.openai.protocol import (
13 ToolCall,
14 )
15 from vllm.entrypoints.openai.tool_parsers.xlam_tool_parser import xLAMToolParser
16 +from vllm.tokenizers import TokenizerLike
17 from vllm.transformers_utils.detokenizer_utils import detokenize_incrementally
17 -from vllm.transformers_utils.tokenizer import AnyTokenizer, get_tokenizer
18 +from vllm.transformers_utils.tokenizer import get_tokenizer
19
20 pytestmark = pytest.mark.cpu_test
21
@@ -49,7 +50,7 @@ def assert_tool_calls(
50
51 def stream_delta_message_generator(
52 xlam_tool_parser: xLAMToolParser,
52 - xlam_tokenizer: AnyTokenizer,
53 + xlam_tokenizer: TokenizerLike,
54 model_output: str,
55 request: ChatCompletionRequest | None = None,
56 ) -> Generator[DeltaMessage, None, None]:
tests/transformers_utils/test_config.py
+28 -58
@@ -1,62 +1,32 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +"""
4 +This test file includes some cases where it is inappropriate to
5 +only get the `eos_token_id` from the tokenizer as defined by
6 +`vllm.LLMEngine._get_eos_token_id`.
7 +"""
8
9 +from vllm.transformers_utils.config import try_get_generation_config
10 +from vllm.transformers_utils.tokenizer import get_tokenizer
11
5 -import tempfile
6 -from pathlib import Path
7 -from unittest.mock import MagicMock, call, patch
8 -
9 -import pytest
10 -
11 -from vllm.transformers_utils.repo_utils import list_filtered_repo_files
12 -
13 -
14 -@pytest.mark.parametrize(
15 - "allow_patterns,expected_relative_files",
16 - [
17 - (
18 - ["*.json", "correct*.txt"],
19 - ["json_file.json", "subfolder/correct.txt", "correct_2.txt"],
20 - ),
21 - ],
22 -)
23 -def test_list_filtered_repo_files(
24 - allow_patterns: list[str], expected_relative_files: list[str]
25 -):
26 - with tempfile.TemporaryDirectory() as tmp_dir:
27 - # Prep folder and files
28 - path_tmp_dir = Path(tmp_dir)
29 - subfolder = path_tmp_dir / "subfolder"
30 - subfolder.mkdir()
31 - (path_tmp_dir / "json_file.json").touch()
32 - (path_tmp_dir / "correct_2.txt").touch()
33 - (path_tmp_dir / "uncorrect.txt").touch()
34 - (path_tmp_dir / "uncorrect.jpeg").touch()
35 - (subfolder / "correct.txt").touch()
36 - (subfolder / "uncorrect_sub.txt").touch()
37 -
38 - def _glob_path() -> list[str]:
39 - return [
40 - str(file.relative_to(path_tmp_dir))
41 - for file in path_tmp_dir.glob("**/*")
42 - if file.is_file()
43 - ]
44 -
45 - # Patch list_repo_files called by fn
46 - with patch(
47 - "vllm.transformers_utils.repo_utils.list_repo_files",
48 - MagicMock(return_value=_glob_path()),
49 - ) as mock_list_repo_files:
50 - out_files = sorted(
51 - list_filtered_repo_files(
52 - tmp_dir, allow_patterns, "revision", "model", "token"
53 - )
54 - )
55 - assert out_files == sorted(expected_relative_files)
56 - assert mock_list_repo_files.call_count == 1
57 - assert mock_list_repo_files.call_args_list[0] == call(
58 - repo_id=tmp_dir,
59 - revision="revision",
60 - repo_type="model",
61 - token="token",
62 - )
12 +
13 +def test_get_llama3_eos_token():
14 + model_name = "meta-llama/Llama-3.2-1B-Instruct"
15 +
16 + tokenizer = get_tokenizer(model_name)
17 + assert tokenizer.eos_token_id == 128009
18 +
19 + generation_config = try_get_generation_config(model_name, trust_remote_code=False)
20 + assert generation_config is not None
21 + assert generation_config.eos_token_id == [128001, 128008, 128009]
22 +
23 +
24 +def test_get_blip2_eos_token():
25 + model_name = "Salesforce/blip2-opt-2.7b"
26 +
27 + tokenizer = get_tokenizer(model_name)
28 + assert tokenizer.eos_token_id == 2
29 +
30 + generation_config = try_get_generation_config(model_name, trust_remote_code=False)
31 + assert generation_config is not None
32 + assert generation_config.eos_token_id == 50118
tests/transformers_utils/test_processor.py renamed
tests/transformers_utils/test_repo_utils.py new
+62
@@ -0,0 +1,62 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +
4 +
5 +import tempfile
6 +from pathlib import Path
7 +from unittest.mock import MagicMock, call, patch
8 +
9 +import pytest
10 +
11 +from vllm.transformers_utils.repo_utils import list_filtered_repo_files
12 +
13 +
14 +@pytest.mark.parametrize(
15 + "allow_patterns,expected_relative_files",
16 + [
17 + (
18 + ["*.json", "correct*.txt"],
19 + ["json_file.json", "subfolder/correct.txt", "correct_2.txt"],
20 + ),
21 + ],
22 +)
23 +def test_list_filtered_repo_files(
24 + allow_patterns: list[str], expected_relative_files: list[str]
25 +):
26 + with tempfile.TemporaryDirectory() as tmp_dir:
27 + # Prep folder and files
28 + path_tmp_dir = Path(tmp_dir)
29 + subfolder = path_tmp_dir / "subfolder"
30 + subfolder.mkdir()
31 + (path_tmp_dir / "json_file.json").touch()
32 + (path_tmp_dir / "correct_2.txt").touch()
33 + (path_tmp_dir / "uncorrect.txt").touch()
34 + (path_tmp_dir / "uncorrect.jpeg").touch()
35 + (subfolder / "correct.txt").touch()
36 + (subfolder / "uncorrect_sub.txt").touch()
37 +
38 + def _glob_path() -> list[str]:
39 + return [
40 + str(file.relative_to(path_tmp_dir))
41 + for file in path_tmp_dir.glob("**/*")
42 + if file.is_file()
43 + ]
44 +
45 + # Patch list_repo_files called by fn
46 + with patch(
47 + "vllm.transformers_utils.repo_utils.list_repo_files",
48 + MagicMock(return_value=_glob_path()),
49 + ) as mock_list_repo_files:
50 + out_files = sorted(
51 + list_filtered_repo_files(
52 + tmp_dir, allow_patterns, "revision", "model", "token"
53 + )
54 + )
55 + assert out_files == sorted(expected_relative_files)
56 + assert mock_list_repo_files.call_count == 1
57 + assert mock_list_repo_files.call_args_list[0] == call(
58 + repo_id=tmp_dir,
59 + revision="revision",
60 + repo_type="model",
61 + token="token",
62 + )
tests/v1/engine/test_output_processor.py
+2 -2
@@ -18,7 +18,7 @@ from vllm.logprobs import PromptLogprobs, SampleLogprobs
18 from vllm.lora.request import LoRARequest
19 from vllm.outputs import CompletionOutput, RequestOutput
20 from vllm.sampling_params import RequestOutputKind, SamplingParams
21 -from vllm.transformers_utils.tokenizer import AnyTokenizer
21 +from vllm.tokenizers import TokenizerLike
22 from vllm.v1.engine import (
23 EngineCoreEvent,
24 EngineCoreEventType,
@@ -31,7 +31,7 @@ from vllm.v1.metrics.stats import IterationStats, SchedulerStats
31
32
33 def _ref_convert_id_to_token(
34 - tokenizer: AnyTokenizer,
34 + tokenizer: TokenizerLike,
35 token_id: int,
36 ) -> str:
37 """Reference impl of logprobs detokenization.
tools/pre_commit/check_pickle_imports.py
+1 -1
@@ -27,8 +27,8 @@ ALLOWED_FILES = {
27 "vllm/distributed/device_communicators/shm_broadcast.py",
28 "vllm/distributed/device_communicators/shm_object_storage.py",
29 "vllm/utils/hashing.py",
30 + "tests/tokenizers_/test_cached_tokenizer.py",
31 "tests/utils_/test_hashing.py",
31 - "tests/tokenization/test_cached_tokenizer.py",
32 "benchmarks/kernels/graph_machete_bench.py",
33 "benchmarks/kernels/benchmark_lora.py",
34 "benchmarks/kernels/benchmark_machete.py",
tools/pre_commit/mypy.py
+1
@@ -35,6 +35,7 @@ FILES = [
35 "vllm/multimodal",
36 "vllm/platforms",
37 "vllm/plugins",
38 + "vllm/tokenizers",
39 "vllm/transformers_utils",
40 "vllm/triton_utils",
41 "vllm/usage",
vllm/benchmarks/datasets.py
+2 -2
@@ -39,7 +39,7 @@ from vllm.lora.request import LoRARequest
39 from vllm.lora.utils import get_adapter_absolute_path
40 from vllm.multimodal import MultiModalDataDict
41 from vllm.multimodal.image import convert_image_mode
42 -from vllm.transformers_utils.tokenizer import AnyTokenizer
42 +from vllm.tokenizers import TokenizerLike
43 from vllm.utils.import_utils import PlaceholderModule
44
45 try:
@@ -293,7 +293,7 @@ def lora_path_on_disk(lora_path: str) -> str:
293
294
295 # Global cache for LoRA tokenizers.
296 -lora_tokenizer_cache: dict[int, AnyTokenizer] = {}
296 +lora_tokenizer_cache: dict[int, TokenizerLike] = {}
297
298
299 def process_image(image: Any) -> Mapping[str, Any]:
vllm/engine/protocol.py
+2 -2
@@ -13,7 +13,7 @@ from vllm.plugins.io_processors import IOProcessor
13 from vllm.pooling_params import PoolingParams
14 from vllm.sampling_params import SamplingParams
15 from vllm.tasks import SupportedTask
16 -from vllm.transformers_utils.tokenizer import AnyTokenizer
16 +from vllm.tokenizers import TokenizerLike
17 from vllm.v1.engine import EngineCoreRequest
18 from vllm.v1.engine.input_processor import InputProcessor
19
@@ -85,7 +85,7 @@ class EngineClient(ABC):
85 ...
86
87 @abstractmethod
88 - async def get_tokenizer(self) -> AnyTokenizer:
88 + async def get_tokenizer(self) -> TokenizerLike:
89 """Get the tokenizer"""
90 ...
91
vllm/entrypoints/chat_utils.py
+6 -6
@@ -49,9 +49,9 @@ from vllm.logger import init_logger
49 from vllm.model_executor.models import SupportsMultiModal
50 from vllm.multimodal import MULTIMODAL_REGISTRY, MultiModalDataDict, MultiModalUUIDDict
51 from vllm.multimodal.utils import MEDIA_CONNECTOR_REGISTRY, MediaConnector
52 +from vllm.tokenizers import MistralTokenizer, TokenizerLike
53 from vllm.transformers_utils.chat_templates import get_chat_template_fallback_path
54 from vllm.transformers_utils.processor import cached_get_processor
54 -from vllm.transformers_utils.tokenizer import AnyTokenizer, MistralTokenizer
55 from vllm.utils import random_uuid
56 from vllm.utils.func_utils import supports_kw
57
@@ -536,7 +536,7 @@ def resolve_hf_chat_template(
536 def _resolve_chat_template_content_format(
537 chat_template: str | None,
538 tools: list[dict[str, Any]] | None,
539 - tokenizer: AnyTokenizer,
539 + tokenizer: TokenizerLike,
540 *,
541 model_config: ModelConfig,
542 ) -> _ChatTemplateContentFormat:
@@ -593,7 +593,7 @@ def resolve_chat_template_content_format(
593 chat_template: str | None,
594 tools: list[dict[str, Any]] | None,
595 given_format: ChatTemplateContentFormatOption,
596 - tokenizer: AnyTokenizer,
596 + tokenizer: TokenizerLike,
597 *,
598 model_config: ModelConfig,
599 ) -> _ChatTemplateContentFormat:
@@ -627,7 +627,7 @@ class BaseMultiModalItemTracker(ABC, Generic[_T]):
627 maximum per prompt.
628 """
629
630 - def __init__(self, model_config: ModelConfig, tokenizer: AnyTokenizer):
630 + def __init__(self, model_config: ModelConfig, tokenizer: TokenizerLike):
631 super().__init__()
632
633 self._model_config = model_config
@@ -1592,7 +1592,7 @@ def _postprocess_messages(messages: list[ConversationMessage]) -> None:
1592 def parse_chat_messages(
1593 messages: list[ChatCompletionMessageParam],
1594 model_config: ModelConfig,
1595 - tokenizer: AnyTokenizer,
1595 + tokenizer: TokenizerLike,
1596 content_format: _ChatTemplateContentFormat,
1597 ) -> tuple[
1598 list[ConversationMessage],
@@ -1624,7 +1624,7 @@ def parse_chat_messages(
1624 def parse_chat_messages_futures(
1625 messages: list[ChatCompletionMessageParam],
1626 model_config: ModelConfig,
1627 - tokenizer: AnyTokenizer,
1627 + tokenizer: TokenizerLike,
1628 content_format: _ChatTemplateContentFormat,
1629 ) -> tuple[
1630 list[ConversationMessage],
vllm/entrypoints/llm.py
+6 -9
@@ -71,11 +71,8 @@ from vllm.platforms import current_platform
71 from vllm.pooling_params import PoolingParams
72 from vllm.sampling_params import BeamSearchParams, RequestOutputKind, SamplingParams
73 from vllm.tasks import PoolingTask
74 -from vllm.transformers_utils.tokenizer import (
75 - AnyTokenizer,
76 - MistralTokenizer,
77 - get_cached_tokenizer,
78 -)
74 +from vllm.tokenizers import MistralTokenizer, TokenizerLike
75 +from vllm.transformers_utils.tokenizer import get_cached_tokenizer
76 from vllm.usage.usage_lib import UsageContext
77 from vllm.utils.collection_utils import as_iter, is_list_of
78 from vllm.utils.counter import Counter
@@ -350,11 +347,11 @@ class LLM:
347 self.input_processor = self.llm_engine.input_processor
348 self.io_processor = self.llm_engine.io_processor
349
353 - def get_tokenizer(self) -> AnyTokenizer:
350 + def get_tokenizer(self) -> TokenizerLike:
351 return self.llm_engine.get_tokenizer()
352
353 @deprecated("`set_tokenizer` is deprecated and will be removed in v0.13.")
357 - def set_tokenizer(self, tokenizer: AnyTokenizer) -> None:
354 + def set_tokenizer(self, tokenizer: TokenizerLike) -> None:
355 # While CachedTokenizer is dynamic, have no choice but
356 # compare class name. Misjudgment will arise from
357 # user-defined tokenizer started with 'Cached'
@@ -1244,7 +1241,7 @@ class LLM:
1241
1242 def _embedding_score(
1243 self,
1247 - tokenizer: AnyTokenizer,
1244 + tokenizer: TokenizerLike,
1245 text_1: list[str | TextPrompt | TokensPrompt],
1246 text_2: list[str | TextPrompt | TokensPrompt],
1247 truncate_prompt_tokens: int | None = None,
@@ -1276,7 +1273,7 @@ class LLM:
1273
1274 def _cross_encoding_score(
1275 self,
1279 - tokenizer: AnyTokenizer,
1276 + tokenizer: TokenizerLike,
1277 data_1: list[str] | list[ScoreContentPartParam],
1278 data_2: list[str] | list[ScoreContentPartParam],
1279 truncate_prompt_tokens: int | None = None,
vllm/entrypoints/openai/serving_chat.py
+7 -6
@@ -62,8 +62,9 @@ from vllm.logger import init_logger
62 from vllm.logprobs import Logprob
63 from vllm.outputs import CompletionOutput, RequestOutput
64 from vllm.sampling_params import BeamSearchParams, SamplingParams
65 -from vllm.transformers_utils.tokenizer import AnyTokenizer, MistralTokenizer
66 -from vllm.transformers_utils.tokenizers import (
65 +from vllm.tokenizers import TokenizerLike
66 +from vllm.tokenizers.mistral import (
67 + MistralTokenizer,
68 maybe_serialize_tool_calls,
69 truncate_tool_call_ids,
70 validate_request_params,
@@ -530,7 +531,7 @@ class OpenAIServingChat(OpenAIServing):
531 request_id: str,
532 model_name: str,
533 conversation: list[ConversationMessage],
533 - tokenizer: AnyTokenizer,
534 + tokenizer: TokenizerLike,
535 request_metadata: RequestResponseMetadata,
536 ) -> AsyncGenerator[str, None]:
537 created_time = int(time.time())
@@ -1296,7 +1297,7 @@ class OpenAIServingChat(OpenAIServing):
1297 request_id: str,
1298 model_name: str,
1299 conversation: list[ConversationMessage],
1299 - tokenizer: AnyTokenizer,
1300 + tokenizer: TokenizerLike,
1301 request_metadata: RequestResponseMetadata,
1302 ) -> ErrorResponse | ChatCompletionResponse:
1303 created_time = int(time.time())
@@ -1624,7 +1625,7 @@ class OpenAIServingChat(OpenAIServing):
1625 self,
1626 logprobs: dict[int, Logprob],
1627 top_logprobs: int | None,
1627 - tokenizer: AnyTokenizer,
1628 + tokenizer: TokenizerLike,
1629 should_return_as_token_id: bool,
1630 ) -> list[ChatCompletionLogProb]:
1631 return [
@@ -1648,7 +1649,7 @@ class OpenAIServingChat(OpenAIServing):
1649 self,
1650 token_ids: GenericSequence[int],
1651 top_logprobs: GenericSequence[dict[int, Logprob] | None],
1651 - tokenizer: AnyTokenizer,
1652 + tokenizer: TokenizerLike,
1653 num_output_top_logprobs: int | None = None,
1654 return_as_token_id: bool | None = None,
1655 ) -> ChatCompletionLogProbs:
vllm/entrypoints/openai/serving_classification.py
+1 -1
@@ -221,7 +221,7 @@ class ServingClassification(ClassificationMixin):
221
222 def _create_pooling_params(
223 self,
224 - ctx: ClassificationServeContext,
224 + ctx: ServeContext[ClassificationRequest],
225 ) -> PoolingParams | ErrorResponse:
226 pooling_params = super()._create_pooling_params(ctx)
227 if isinstance(pooling_params, ErrorResponse):
vllm/entrypoints/openai/serving_completion.py
+11 -5
@@ -33,7 +33,7 @@ from vllm.logger import init_logger
33 from vllm.logprobs import Logprob
34 from vllm.outputs import RequestOutput
35 from vllm.sampling_params import BeamSearchParams, SamplingParams
36 -from vllm.transformers_utils.tokenizer import AnyTokenizer
36 +from vllm.tokenizers import TokenizerLike
37 from vllm.utils.async_utils import merge_async_iterators
38 from vllm.utils.collection_utils import as_list
39 from vllm.v1.sample.logits_processor import validate_logits_processors_parameters
@@ -326,7 +326,7 @@ class OpenAIServingCompletion(OpenAIServing):
326 created_time: int,
327 model_name: str,
328 num_prompts: int,
329 - tokenizer: AnyTokenizer,
329 + tokenizer: TokenizerLike | None,
330 request_metadata: RequestResponseMetadata,
331 ) -> AsyncGenerator[str, None]:
332 num_choices = 1 if request.n is None else request.n
@@ -511,7 +511,7 @@ class OpenAIServingCompletion(OpenAIServing):
511 request_id: str,
512 created_time: int,
513 model_name: str,
514 - tokenizer: AnyTokenizer,
514 + tokenizer: TokenizerLike | None,
515 request_metadata: RequestResponseMetadata,
516 ) -> CompletionResponse:
517 choices: list[CompletionResponseChoice] = []
@@ -622,7 +622,7 @@ class OpenAIServingCompletion(OpenAIServing):
622 token_ids: GenericSequence[int],
623 top_logprobs: GenericSequence[dict[int, Logprob] | None],
624 num_output_top_logprobs: int,
625 - tokenizer: AnyTokenizer,
625 + tokenizer: TokenizerLike | None,
626 initial_text_offset: int = 0,
627 return_as_token_id: bool | None = None,
628 ) -> CompletionLogProbs:
@@ -642,9 +642,15 @@ class OpenAIServingCompletion(OpenAIServing):
642 for i, token_id in enumerate(token_ids):
643 step_top_logprobs = top_logprobs[i]
644 if step_top_logprobs is None:
645 - token = tokenizer.decode(token_id)
645 if should_return_as_token_id:
646 token = f"token_id:{token_id}"
647 + else:
648 + if tokenizer is None:
649 + raise ValueError(
650 + "Unable to get tokenizer because `skip_tokenizer_init=True`"
651 + )
652 +
653 + token = tokenizer.decode(token_id)
654
655 out_tokens.append(token)
656 out_token_logprobs.append(None)
vllm/entrypoints/openai/serving_engine.py
+42 -46
@@ -7,13 +7,14 @@ import time
7 import traceback
8 from collections.abc import AsyncGenerator, Callable, Iterable, Mapping, Sequence
9 from concurrent.futures import ThreadPoolExecutor
10 +from dataclasses import dataclass, field
11 from http import HTTPStatus
12 from typing import Any, ClassVar, Generic, TypeAlias, TypeVar
13
14 import numpy as np
15 import torch
16 from fastapi import Request
16 -from pydantic import BaseModel, ConfigDict, Field, TypeAdapter
17 +from pydantic import ConfigDict, TypeAdapter
18 from starlette.datastructures import Headers
19 from typing_extensions import TypeIs
20
@@ -96,12 +97,12 @@ from vllm.outputs import CompletionOutput, PoolingRequestOutput, RequestOutput
97 from vllm.pooling_params import PoolingParams
98 from vllm.reasoning import ReasoningParser, ReasoningParserManager
99 from vllm.sampling_params import BeamSearchParams, SamplingParams
100 +from vllm.tokenizers import MistralTokenizer, TokenizerLike
101 from vllm.tracing import (
102 contains_trace_headers,
103 extract_trace_headers,
104 log_tracing_disabled_warning,
105 )
104 -from vllm.transformers_utils.tokenizer import AnyTokenizer, MistralTokenizer
106 from vllm.utils import random_uuid
107 from vllm.utils.async_utils import (
108 AsyncMicrobatchTokenizer,
@@ -184,19 +185,19 @@ def is_embeds_prompt(prompt: RequestPrompt) -> TypeIs[EmbedsPrompt]:
185 RequestT = TypeVar("RequestT", bound=AnyRequest)
186
187
187 -class RequestProcessingMixin(BaseModel):
188 +@dataclass(kw_only=True)
189 +class RequestProcessingMixin:
190 """
191 Mixin for request processing,
192 handling prompt preparation and engine input.
193 """
194
193 - request_prompts: Sequence[RequestPrompt] | None = []
194 - engine_prompts: list[EngineTokensPrompt] | None = []
195 -
196 - model_config = ConfigDict(arbitrary_types_allowed=True)
195 + request_prompts: Sequence[RequestPrompt] | None = field(default_factory=list)
196 + engine_prompts: list[EngineTokensPrompt] | None = field(default_factory=list)
197
198
199 -class ResponseGenerationMixin(BaseModel):
199 +@dataclass(kw_only=True)
200 +class ResponseGenerationMixin:
201 """
202 Mixin for response generation,
203 managing result generators and final batch results.
@@ -205,54 +206,38 @@ class ResponseGenerationMixin(BaseModel):
206 result_generator: (
207 AsyncGenerator[tuple[int, RequestOutput | PoolingRequestOutput], None] | None
208 ) = None
208 - final_res_batch: list[RequestOutput | PoolingRequestOutput] = Field(
209 + final_res_batch: list[RequestOutput | PoolingRequestOutput] = field(
210 default_factory=list
211 )
212
213 model_config = ConfigDict(arbitrary_types_allowed=True)
214
215
215 -class ServeContext(
216 - RequestProcessingMixin,
217 - ResponseGenerationMixin,
218 - BaseModel,
219 - Generic[RequestT],
220 -):
216 +@dataclass(kw_only=True)
217 +class ServeContext(RequestProcessingMixin, ResponseGenerationMixin, Generic[RequestT]):
218 # Shared across all requests
219 request: RequestT
220 raw_request: Request | None = None
221 model_name: str
222 request_id: str
226 - created_time: int = Field(default_factory=lambda: int(time.time()))
223 + created_time: int = field(default_factory=lambda: int(time.time()))
224 lora_request: LoRARequest | None = None
225
226 # Shared across most requests
230 - tokenizer: AnyTokenizer | None = None
231 -
232 - # `protected_namespaces` resolves Pydantic v2's warning
233 - # on conflict with protected namespace "model_"
234 - model_config = ConfigDict(
235 - protected_namespaces=(),
236 - arbitrary_types_allowed=True,
237 - )
227 + tokenizer: TokenizerLike | None = None
228
229
240 -ClassificationServeContext = ServeContext[ClassificationRequest]
230 +@dataclass(kw_only=True)
231 +class ClassificationServeContext(ServeContext[ClassificationRequest]):
232 + pass
233
234
235 +@dataclass(kw_only=True)
236 class EmbeddingServeContext(ServeContext[EmbeddingRequest]):
237 chat_template: str | None = None
238 chat_template_content_format: ChatTemplateContentFormatOption
239
240
248 -# Used to resolve the Pydantic error related to
249 -# forward reference of MultiModalDataDict in TokensPrompt
250 -RequestProcessingMixin.model_rebuild()
251 -ServeContext.model_rebuild()
252 -ClassificationServeContext.model_rebuild()
253 -EmbeddingServeContext.model_rebuild()
254 -
255 -
241 class OpenAIServing:
242 request_id_prefix: ClassVar[str] = """
243 A short string prepended to every request’s ID (e.g. "embd", "classify")
@@ -281,7 +266,7 @@ class OpenAIServing:
266 apply_mistral_chat_template, executor=self._tokenizer_executor
267 )
268
284 - self._async_tokenizer_pool: dict[AnyTokenizer, AsyncMicrobatchTokenizer] = {}
269 + self._async_tokenizer_pool: dict[TokenizerLike, AsyncMicrobatchTokenizer] = {}
270 self.log_error_stack = log_error_stack
271
272 self.input_processor = self.models.input_processor
@@ -291,7 +276,7 @@ class OpenAIServing:
276
277 def _get_tool_parser(
278 self, tool_parser_name: str | None = None, enable_auto_tools: bool = False
294 - ) -> Callable[[AnyTokenizer], ToolParser] | None:
279 + ) -> Callable[[TokenizerLike], ToolParser] | None:
280 """Get the tool parser based on the name."""
281 parser = None
282 if not enable_auto_tools or tool_parser_name is None:
@@ -317,7 +302,7 @@ class OpenAIServing:
302 def _get_reasoning_parser(
303 self,
304 reasoning_parser_name: str,
320 - ) -> Callable[[AnyTokenizer], ReasoningParser] | None:
305 + ) -> Callable[[TokenizerLike], ReasoningParser] | None:
306 """Get the reasoning parser based on the name."""
307 parser = None
308 if not reasoning_parser_name:
@@ -547,7 +532,7 @@ class OpenAIServing:
532 prompt_logprobs=None,
533 )
534
550 - def _get_renderer(self, tokenizer: AnyTokenizer | None) -> BaseRenderer:
535 + def _get_renderer(self, tokenizer: TokenizerLike | None) -> BaseRenderer:
536 """
537 Get a Renderer instance with the provided tokenizer.
538 Uses shared async tokenizer pool for efficiency.
@@ -877,7 +862,7 @@ class OpenAIServing:
862 self,
863 request: AnyRequest,
864 prompt: str,
880 - tokenizer: AnyTokenizer,
865 + tokenizer: TokenizerLike,
866 add_special_tokens: bool,
867 ) -> TextTokensPrompt:
868 async_tokenizer = self._get_async_tokenizer(tokenizer)
@@ -919,7 +904,7 @@ class OpenAIServing:
904 self,
905 request: AnyRequest,
906 prompt_ids: list[int],
922 - tokenizer: AnyTokenizer | None,
907 + tokenizer: TokenizerLike | None,
908 ) -> TextTokensPrompt:
909 truncate_prompt_tokens = getattr(request, "truncate_prompt_tokens", None)
910
@@ -1015,7 +1000,7 @@ class OpenAIServing:
1000 async def _tokenize_prompt_input_async(
1001 self,
1002 request: AnyRequest,
1018 - tokenizer: AnyTokenizer,
1003 + tokenizer: TokenizerLike,
1004 prompt_input: str | list[int],
1005 add_special_tokens: bool = True,
1006 ) -> TextTokensPrompt:
@@ -1034,7 +1019,7 @@ class OpenAIServing:
1019 async def _tokenize_prompt_inputs_async(
1020 self,
1021 request: AnyRequest,
1037 - tokenizer: AnyTokenizer,
1022 + tokenizer: TokenizerLike,
1023 prompt_inputs: Iterable[str | list[int]],
1024 add_special_tokens: bool = True,
1025 ) -> AsyncGenerator[TextTokensPrompt, None]:
@@ -1079,7 +1064,7 @@ class OpenAIServing:
1064 async def _preprocess_chat(
1065 self,
1066 request: ChatLikeRequest | ResponsesRequest,
1082 - tokenizer: AnyTokenizer,
1067 + tokenizer: TokenizerLike | None,
1068 messages: list[ChatCompletionMessageParam],
1069 chat_template: str | None,
1070 chat_template_content_format: ChatTemplateContentFormatOption,
@@ -1088,13 +1073,18 @@ class OpenAIServing:
1073 tool_dicts: list[dict[str, Any]] | None = None,
1074 documents: list[dict[str, str]] | None = None,
1075 chat_template_kwargs: dict[str, Any] | None = None,
1091 - tool_parser: Callable[[AnyTokenizer], ToolParser] | None = None,
1076 + tool_parser: Callable[[TokenizerLike], ToolParser] | None = None,
1077 add_special_tokens: bool = False,
1078 ) -> tuple[
1079 list[ConversationMessage],
1080 Sequence[RequestPrompt],
1081 list[EngineTokensPrompt],
1082 ]:
1083 + if tokenizer is None:
1084 + raise ValueError(
1085 + "Unable to get tokenizer because `skip_tokenizer_init=True`"
1086 + )
1087 +
1088 model_config = self.model_config
1089
1090 resolved_content_format = resolve_chat_template_content_format(
@@ -1370,9 +1360,9 @@ class OpenAIServing:
1360 @staticmethod
1361 def _parse_tool_calls_from_content(
1362 request: ResponsesRequest | ChatCompletionRequest,
1373 - tokenizer: AnyTokenizer,
1363 + tokenizer: TokenizerLike,
1364 enable_auto_tools: bool,
1375 - tool_parser_cls: Callable[[AnyTokenizer], ToolParser] | None,
1365 + tool_parser_cls: Callable[[TokenizerLike], ToolParser] | None,
1366 content: str | None = None,
1367 ) -> tuple[list[FunctionCall] | None, str | None]:
1368 function_calls = list[FunctionCall]()
@@ -1442,7 +1432,7 @@ class OpenAIServing:
1432 def _get_decoded_token(
1433 logprob: Logprob,
1434 token_id: int,
1445 - tokenizer: AnyTokenizer,
1435 + tokenizer: TokenizerLike | None,
1436 return_as_token_id: bool = False,
1437 ) -> str:
1438 if return_as_token_id:
@@ -1450,6 +1440,12 @@ class OpenAIServing:
1440
1441 if logprob.decoded_token is not None:
1442 return logprob.decoded_token
1443 +
1444 + if tokenizer is None:
1445 + raise ValueError(
1446 + "Unable to get tokenizer because `skip_tokenizer_init=True`"
1447 + )
1448 +
1449 return tokenizer.decode(token_id)
1450
1451 def _is_model_supported(self, model_name: str | None) -> bool:
vllm/entrypoints/openai/serving_responses.py
+10 -10
@@ -105,7 +105,7 @@ from vllm.logprobs import Logprob as SampleLogprob
105 from vllm.logprobs import SampleLogprobs
106 from vllm.outputs import CompletionOutput
107 from vllm.sampling_params import SamplingParams, StructuredOutputsParams
108 -from vllm.transformers_utils.tokenizer import AnyTokenizer
108 +from vllm.tokenizers import TokenizerLike
109 from vllm.utils import random_uuid
110
111 logger = init_logger(__name__)
@@ -492,7 +492,7 @@ class OpenAIServingResponses(OpenAIServing):
492 self,
493 request: ResponsesRequest,
494 prev_response: ResponsesResponse | None,
495 - tokenizer: AnyTokenizer,
495 + tokenizer: TokenizerLike,
496 ):
497 if request.tools is None or (
498 request.tool_choice == "none" and self.exclude_tools_when_tool_choice_none
@@ -563,7 +563,7 @@ class OpenAIServingResponses(OpenAIServing):
563 result_generator: AsyncIterator[ConversationContext],
564 context: ConversationContext,
565 model_name: str,
566 - tokenizer: AnyTokenizer,
566 + tokenizer: TokenizerLike,
567 request_metadata: RequestResponseMetadata,
568 created_time: int | None = None,
569 ) -> ErrorResponse | ResponsesResponse:
@@ -675,7 +675,7 @@ class OpenAIServingResponses(OpenAIServing):
675 self,
676 logprobs: dict[int, SampleLogprob],
677 top_logprobs: int,
678 - tokenizer: AnyTokenizer,
678 + tokenizer: TokenizerLike,
679 ) -> list[LogprobTopLogprob]:
680 """Returns the top-k logprobs from the logprobs dictionary."""
681 out = []
@@ -700,7 +700,7 @@ class OpenAIServingResponses(OpenAIServing):
700 self,
701 token_ids: Sequence[int],
702 logprobs: SampleLogprobs | None,
703 - tokenizer: AnyTokenizer,
703 + tokenizer: TokenizerLike,
704 top_logprobs: int | None = None,
705 ) -> list[Logprob]:
706 assert logprobs is not None, "logprobs must be provided"
@@ -736,7 +736,7 @@ class OpenAIServingResponses(OpenAIServing):
736 self,
737 token_ids: Sequence[int],
738 logprobs: SampleLogprobs | None,
739 - tokenizer: AnyTokenizer,
739 + tokenizer: TokenizerLike,
740 top_logprobs: int | None = None,
741 ) -> list[response_text_delta_event.Logprob]:
742 lgs = self._create_response_logprobs(
@@ -763,7 +763,7 @@ class OpenAIServingResponses(OpenAIServing):
763 self,
764 request: ResponsesRequest,
765 final_output: CompletionOutput,
766 - tokenizer: AnyTokenizer,
766 + tokenizer: TokenizerLike,
767 ) -> list[ResponseOutputItem]:
768 if self.reasoning_parser:
769 try:
@@ -1135,7 +1135,7 @@ class OpenAIServingResponses(OpenAIServing):
1135 result_generator: AsyncIterator[ConversationContext | None],
1136 context: ConversationContext,
1137 model_name: str,
1138 - tokenizer: AnyTokenizer,
1138 + tokenizer: TokenizerLike,
1139 request_metadata: RequestResponseMetadata,
1140 created_time: int,
1141 _increment_sequence_number_and_return: Callable[
@@ -1438,7 +1438,7 @@ class OpenAIServingResponses(OpenAIServing):
1438 result_generator: AsyncIterator[ConversationContext | None],
1439 context: ConversationContext,
1440 model_name: str,
1441 - tokenizer: AnyTokenizer,
1441 + tokenizer: TokenizerLike,
1442 request_metadata: RequestResponseMetadata,
1443 created_time: int,
1444 _increment_sequence_number_and_return: Callable[
@@ -1891,7 +1891,7 @@ class OpenAIServingResponses(OpenAIServing):
1891 result_generator: AsyncIterator[ConversationContext | None],
1892 context: ConversationContext,
1893 model_name: str,
1894 - tokenizer: AnyTokenizer,
1894 + tokenizer: TokenizerLike,
1895 request_metadata: RequestResponseMetadata,
1896 created_time: int | None = None,
1897 ) -> AsyncGenerator[StreamingResponsesResponse, None]:
vllm/entrypoints/openai/serving_score.py
+4 -4
@@ -36,7 +36,7 @@ from vllm.inputs.data import TokensPrompt
36 from vllm.logger import init_logger
37 from vllm.lora.request import LoRARequest
38 from vllm.outputs import PoolingRequestOutput, ScoringRequestOutput
39 -from vllm.transformers_utils.tokenizer import AnyTokenizer, MistralTokenizer
39 +from vllm.tokenizers import MistralTokenizer, TokenizerLike
40 from vllm.utils.async_utils import make_async, merge_async_iterators
41
42 logger = init_logger(__name__)
@@ -60,7 +60,7 @@ class ServingScores(OpenAIServing):
60
61 async def _embedding_score(
62 self,
63 - tokenizer: AnyTokenizer,
63 + tokenizer: TokenizerLike,
64 texts_1: list[str],
65 texts_2: list[str],
66 request: RerankRequest | ScoreRequest,
@@ -153,7 +153,7 @@ class ServingScores(OpenAIServing):
153 def _preprocess_score(
154 self,
155 request: RerankRequest | ScoreRequest,
156 - tokenizer: AnyTokenizer,
156 + tokenizer: TokenizerLike,
157 tokenization_kwargs: dict[str, Any],
158 data_1: str | ScoreContentPartParam,
159 data_2: str | ScoreContentPartParam,
@@ -175,7 +175,7 @@ class ServingScores(OpenAIServing):
175
176 async def _cross_encoding_score(
177 self,
178 - tokenizer: AnyTokenizer,
178 + tokenizer: TokenizerLike,
179 data_1: list[str] | list[ScoreContentPartParam],
180 data_2: list[str] | list[ScoreContentPartParam],
181 request: RerankRequest | ScoreRequest,
vllm/entrypoints/openai/serving_tokenization.py
+2 -2
@@ -22,7 +22,7 @@ from vllm.entrypoints.openai.serving_engine import OpenAIServing
22 from vllm.entrypoints.openai.serving_models import OpenAIServingModels
23 from vllm.entrypoints.renderer import RenderConfig
24 from vllm.logger import init_logger
25 -from vllm.transformers_utils.tokenizer import AnyTokenizer
25 +from vllm.tokenizers import TokenizerLike
26
27 logger = init_logger(__name__)
28
@@ -170,7 +170,7 @@ class OpenAIServingTokenization(OpenAIServing):
170
171 @dataclass
172 class TokenizerInfo:
173 - tokenizer: AnyTokenizer
173 + tokenizer: TokenizerLike
174 chat_template: str | None
175
176 def to_dict(self) -> dict[str, Any]:
vllm/entrypoints/openai/tool_parsers/abstract_tool_parser.py
+2 -2
@@ -22,7 +22,7 @@ from vllm.logger import init_logger
22 from vllm.sampling_params import (
23 StructuredOutputsParams,
24 )
25 -from vllm.transformers_utils.tokenizer import AnyTokenizer
25 +from vllm.tokenizers import TokenizerLike
26 from vllm.utils.collection_utils import is_list_of
27 from vllm.utils.import_utils import import_from_path
28
@@ -36,7 +36,7 @@ class ToolParser:
36 derived classes.
37 """
38
39 - def __init__(self, tokenizer: AnyTokenizer):
39 + def __init__(self, tokenizer: TokenizerLike):
40 self.prev_tool_call_arr: list[dict] = []
41 # the index of the tool call that is currently being parsed
42 self.current_tool_id: int = -1
vllm/entrypoints/openai/tool_parsers/deepseekv31_tool_parser.py
+2 -2
@@ -19,13 +19,13 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
19 ToolParser,
20 )
21 from vllm.logger import init_logger
22 -from vllm.transformers_utils.tokenizer import AnyTokenizer
22 +from vllm.tokenizers import TokenizerLike
23
24 logger = init_logger(__name__)
25
26
27 class DeepSeekV31ToolParser(ToolParser):
28 - def __init__(self, tokenizer: AnyTokenizer):
28 + def __init__(self, tokenizer: TokenizerLike):
29 super().__init__(tokenizer)
30
31 self.current_tool_name_sent: bool = False
vllm/entrypoints/openai/tool_parsers/deepseekv3_tool_parser.py
+2 -2
@@ -19,13 +19,13 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
19 ToolParser,
20 )
21 from vllm.logger import init_logger
22 -from vllm.transformers_utils.tokenizer import AnyTokenizer
22 +from vllm.tokenizers import TokenizerLike
23
24 logger = init_logger(__name__)
25
26
27 class DeepSeekV3ToolParser(ToolParser):
28 - def __init__(self, tokenizer: AnyTokenizer):
28 + def __init__(self, tokenizer: TokenizerLike):
29 super().__init__(tokenizer)
30
31 self.current_tool_name_sent: bool = False
vllm/entrypoints/openai/tool_parsers/ernie45_tool_parser.py
+2 -2
@@ -19,13 +19,13 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
19 ToolParser,
20 )
21 from vllm.logger import init_logger
22 -from vllm.transformers_utils.tokenizer import AnyTokenizer
22 +from vllm.tokenizers import TokenizerLike
23
24 logger = init_logger(__name__)
25
26
27 class Ernie45ToolParser(ToolParser):
28 - def __init__(self, tokenizer: AnyTokenizer):
28 + def __init__(self, tokenizer: TokenizerLike):
29 """
30 Ernie thinking model format:
31 abc\n</think>\n\n\n<tool_call>\ndef\n</tool_call>\n
vllm/entrypoints/openai/tool_parsers/glm4_moe_tool_parser.py
+2 -2
@@ -22,13 +22,13 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
22 ToolParser,
23 )
24 from vllm.logger import init_logger
25 -from vllm.transformers_utils.tokenizer import AnyTokenizer
25 +from vllm.tokenizers import TokenizerLike
26
27 logger = init_logger(__name__)
28
29
30 class Glm4MoeModelToolParser(ToolParser):
31 - def __init__(self, tokenizer: AnyTokenizer):
31 + def __init__(self, tokenizer: TokenizerLike):
32 super().__init__(tokenizer)
33 self.current_tool_name_sent = False
34 self.prev_tool_call_arr: list[dict] = []
vllm/entrypoints/openai/tool_parsers/granite_20b_fc_tool_parser.py
+2 -2
@@ -29,7 +29,7 @@ from vllm.entrypoints.openai.tool_parsers.utils import (
29 partial_json_loads,
30 )
31 from vllm.logger import init_logger
32 -from vllm.transformers_utils.tokenizer import AnyTokenizer
32 +from vllm.tokenizers import TokenizerLike
33
34 logger = init_logger(__name__)
35
@@ -44,7 +44,7 @@ class Granite20bFCToolParser(ToolParser):
44 are all set
45 """
46
47 - def __init__(self, tokenizer: AnyTokenizer):
47 + def __init__(self, tokenizer: TokenizerLike):
48 super().__init__(tokenizer)
49
50 self.bot_token = "<function_call>"
vllm/entrypoints/openai/tool_parsers/granite_tool_parser.py
+2 -2
@@ -27,7 +27,7 @@ from vllm.entrypoints.openai.tool_parsers.utils import (
27 partial_json_loads,
28 )
29 from vllm.logger import init_logger
30 -from vllm.transformers_utils.tokenizer import AnyTokenizer
30 +from vllm.tokenizers import TokenizerLike
31
32 logger = init_logger(__name__)
33
@@ -42,7 +42,7 @@ class GraniteToolParser(ToolParser):
42 are all set
43 """
44
45 - def __init__(self, tokenizer: AnyTokenizer):
45 + def __init__(self, tokenizer: TokenizerLike):
46 super().__init__(tokenizer)
47 # for granite 3.0, the token `<|tool_call|>`
48 self.bot_token = "<|tool_call|>"
vllm/entrypoints/openai/tool_parsers/hermes_tool_parser.py
+4 -4
@@ -22,18 +22,18 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
22 ToolParser,
23 )
24 from vllm.logger import init_logger
25 -from vllm.transformers_utils.tokenizer import AnyTokenizer, MistralTokenizer
25 +from vllm.tokenizers import MistralTokenizer, TokenizerLike
26
27 logger = init_logger(__name__)
28
29
30 class Hermes2ProToolParser(ToolParser):
31 - def __init__(self, tokenizer: AnyTokenizer):
31 + def __init__(self, tokenizer: TokenizerLike):
32 super().__init__(tokenizer)
33
34 - if isinstance(self.model_tokenizer, MistralTokenizer):
34 + if isinstance(tokenizer, MistralTokenizer):
35 logger.error("Detected Mistral tokenizer when using a Hermes model")
36 - self.model_tokenizer = self.model_tokenizer.tokenizer
36 + self.model_tokenizer = tokenizer.tokenizer
37
38 self.current_tool_name_sent: bool = False
39 self.prev_tool_call_arr: list[dict] = []
vllm/entrypoints/openai/tool_parsers/hunyuan_a13b_tool_parser.py
+2 -2
@@ -22,14 +22,14 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
22 )
23 from vllm.entrypoints.openai.tool_parsers.utils import consume_space
24 from vllm.logger import init_logger
25 -from vllm.transformers_utils.tokenizer import AnyTokenizer
25 +from vllm.tokenizers import TokenizerLike
26 from vllm.utils import random_uuid
27
28 logger = init_logger(__name__)
29
30
31 class HunyuanA13BToolParser(ToolParser):
32 - def __init__(self, tokenizer: AnyTokenizer):
32 + def __init__(self, tokenizer: TokenizerLike):
33 super().__init__(tokenizer)
34
35 # Initialize state for streaming mode
vllm/entrypoints/openai/tool_parsers/internlm2_tool_parser.py
+2 -2
@@ -22,13 +22,13 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
22 )
23 from vllm.entrypoints.openai.tool_parsers.utils import extract_intermediate_diff
24 from vllm.logger import init_logger
25 -from vllm.transformers_utils.tokenizer import AnyTokenizer
25 +from vllm.tokenizers import TokenizerLike
26
27 logger = init_logger(__name__)
28
29
30 class Internlm2ToolParser(ToolParser):
31 - def __init__(self, tokenizer: AnyTokenizer):
31 + def __init__(self, tokenizer: TokenizerLike):
32 super().__init__(tokenizer)
33 self.position = 0
34
vllm/entrypoints/openai/tool_parsers/jamba_tool_parser.py
+2 -3
@@ -21,14 +21,13 @@ from vllm.entrypoints.openai.protocol import (
21 from vllm.entrypoints.openai.tool_parsers import ToolParser
22 from vllm.entrypoints.openai.tool_parsers.utils import extract_intermediate_diff
23 from vllm.logger import init_logger
24 -from vllm.transformers_utils.tokenizer import AnyTokenizer
25 -from vllm.transformers_utils.tokenizers import MistralTokenizer
24 +from vllm.tokenizers import MistralTokenizer, TokenizerLike
25
26 logger = init_logger(__name__)
27
28
29 class JambaToolParser(ToolParser):
31 - def __init__(self, tokenizer: AnyTokenizer):
30 + def __init__(self, tokenizer: TokenizerLike):
31 super().__init__(tokenizer)
32
33 if isinstance(self.model_tokenizer, MistralTokenizer):
vllm/entrypoints/openai/tool_parsers/kimi_k2_tool_parser.py
+2 -2
@@ -19,13 +19,13 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
19 ToolParser,
20 )
21 from vllm.logger import init_logger
22 -from vllm.transformers_utils.tokenizer import AnyTokenizer
22 +from vllm.tokenizers import TokenizerLike
23
24 logger = init_logger(__name__)
25
26
27 class KimiK2ToolParser(ToolParser):
28 - def __init__(self, tokenizer: AnyTokenizer):
28 + def __init__(self, tokenizer: TokenizerLike):
29 super().__init__(tokenizer)
30 self.current_tool_name_sent: bool = False
31 self.prev_tool_call_arr: list[dict] = []
vllm/entrypoints/openai/tool_parsers/longcat_tool_parser.py
+2 -2
@@ -4,11 +4,11 @@
4 import regex as re
5
6 from vllm.entrypoints.openai.tool_parsers.hermes_tool_parser import Hermes2ProToolParser
7 -from vllm.transformers_utils.tokenizer import AnyTokenizer
7 +from vllm.tokenizers import TokenizerLike
8
9
10 class LongcatFlashToolParser(Hermes2ProToolParser):
11 - def __init__(self, tokenizer: AnyTokenizer):
11 + def __init__(self, tokenizer: TokenizerLike):
12 super().__init__(tokenizer)
13
14 self.tool_call_start_token: str = "<longcat_tool_call>"
vllm/entrypoints/openai/tool_parsers/minimax_m2_tool_parser.py
+2 -2
@@ -21,13 +21,13 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
21 ToolParser,
22 )
23 from vllm.logger import init_logger
24 -from vllm.transformers_utils.tokenizer import AnyTokenizer
24 +from vllm.tokenizers import TokenizerLike
25
26 logger = init_logger(__name__)
27
28
29 class MinimaxM2ToolParser(ToolParser):
30 - def __init__(self, tokenizer: AnyTokenizer):
30 + def __init__(self, tokenizer: TokenizerLike):
31 super().__init__(tokenizer)
32
33 self.prev_tool_call_arr: list[dict] = []
vllm/entrypoints/openai/tool_parsers/minimax_tool_parser.py
+2 -2
@@ -22,13 +22,13 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
22 )
23 from vllm.entrypoints.openai.tool_parsers.utils import extract_intermediate_diff
24 from vllm.logger import init_logger
25 -from vllm.transformers_utils.tokenizer import AnyTokenizer
25 +from vllm.tokenizers import TokenizerLike
26
27 logger = init_logger(__name__)
28
29
30 class MinimaxToolParser(ToolParser):
31 - def __init__(self, tokenizer: AnyTokenizer):
31 + def __init__(self, tokenizer: TokenizerLike):
32 super().__init__(tokenizer)
33
34 # Initialize streaming state for tracking tool call progress
vllm/entrypoints/openai/tool_parsers/mistral_tool_parser.py
+3 -3
@@ -25,7 +25,7 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
25 )
26 from vllm.entrypoints.openai.tool_parsers.utils import extract_intermediate_diff
27 from vllm.logger import init_logger
28 -from vllm.transformers_utils.tokenizer import AnyTokenizer, MistralTokenizer
28 +from vllm.tokenizers import MistralTokenizer, TokenizerLike
29
30 logger = init_logger(__name__)
31
@@ -46,7 +46,7 @@ class MistralToolCall(ToolCall):
46 return id.isalnum() and len(id) == 9
47
48
49 -def _is_fn_name_regex_support(model_tokenizer: AnyTokenizer) -> bool:
49 +def _is_fn_name_regex_support(model_tokenizer: TokenizerLike) -> bool:
50 return (
51 isinstance(model_tokenizer, MistralTokenizer) and model_tokenizer.version >= 11
52 )
@@ -61,7 +61,7 @@ class MistralToolParser(ToolParser):
61 Used when --enable-auto-tool-choice --tool-call-parser mistral are all set
62 """
63
64 - def __init__(self, tokenizer: AnyTokenizer):
64 + def __init__(self, tokenizer: TokenizerLike):
65 super().__init__(tokenizer)
66
67 if not isinstance(self.model_tokenizer, MistralTokenizer):
vllm/entrypoints/openai/tool_parsers/openai_tool_parser.py
+3 -3
@@ -18,15 +18,15 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
18 from vllm.logger import init_logger
19
20 if TYPE_CHECKING:
21 - from vllm.transformers_utils.tokenizer import AnyTokenizer
21 + from vllm.tokenizers import TokenizerLike
22 else:
23 - AnyTokenizer = object
23 + TokenizerLike = object
24
25 logger = init_logger(__name__)
26
27
28 class OpenAIToolParser(ToolParser):
29 - def __init__(self, tokenizer: "AnyTokenizer"):
29 + def __init__(self, tokenizer: "TokenizerLike"):
30 super().__init__(tokenizer)
31
32 def extract_tool_calls(
vllm/entrypoints/openai/tool_parsers/qwen3coder_tool_parser.py
+2 -2
@@ -22,13 +22,13 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
22 ToolParser,
23 )
24 from vllm.logger import init_logger
25 -from vllm.transformers_utils.tokenizer import AnyTokenizer
25 +from vllm.tokenizers import TokenizerLike
26
27 logger = init_logger(__name__)
28
29
30 class Qwen3CoderToolParser(ToolParser):
31 - def __init__(self, tokenizer: AnyTokenizer):
31 + def __init__(self, tokenizer: TokenizerLike):
32 super().__init__(tokenizer)
33
34 self.current_tool_name_sent: bool = False
vllm/entrypoints/openai/tool_parsers/qwen3xml_tool_parser.py
+2 -2
@@ -23,7 +23,7 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
23 ToolParser,
24 )
25 from vllm.logger import init_logger
26 -from vllm.transformers_utils.tokenizer import AnyTokenizer
26 +from vllm.tokenizers import TokenizerLike
27
28 logger = init_logger(__name__)
29
@@ -1165,7 +1165,7 @@ class StreamingXMLToolCallParser:
1165
1166
1167 class Qwen3XMLToolParser(ToolParser):
1168 - def __init__(self, tokenizer: AnyTokenizer):
1168 + def __init__(self, tokenizer: TokenizerLike):
1169 super().__init__(tokenizer)
1170 self.parser = StreamingXMLToolCallParser()
1171
vllm/entrypoints/openai/tool_parsers/seed_oss_tool_parser.py
+2 -2
@@ -25,7 +25,7 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
25 ToolParser,
26 )
27 from vllm.logger import init_logger
28 -from vllm.transformers_utils.tokenizer import AnyTokenizer
28 +from vllm.tokenizers import TokenizerLike
29
30 logger = init_logger(__name__)
31
@@ -34,7 +34,7 @@ class SeedOssToolParser(ToolParser):
34 TOOL_CALL_START = "<seed:tool_call>"
35 TOOL_CALL_END = "</seed:tool_call>"
36
37 - def __init__(self, tokenizer: AnyTokenizer):
37 + def __init__(self, tokenizer: TokenizerLike):
38 super().__init__(tokenizer)
39
40 # --- streaming state ---
vllm/entrypoints/openai/tool_parsers/step3_tool_parser.py
+2 -2
@@ -21,7 +21,7 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
21 ToolParser,
22 )
23 from vllm.logger import init_logger
24 -from vllm.transformers_utils.tokenizer import AnyTokenizer
24 +from vllm.tokenizers import TokenizerLike
25 from vllm.utils import random_uuid
26
27 logger = init_logger(__name__)
@@ -41,7 +41,7 @@ class Step3ToolParser(ToolParser):
41 TOOL_SEP = "<|tool_sep|>"
42 SPECIAL_TOKENS = [TOOL_CALLS_BEGIN, TOOL_CALLS_END, TOOL_CALL_BEGIN, TOOL_CALL_END]
43
44 - def __init__(self, tokenizer: AnyTokenizer):
44 + def __init__(self, tokenizer: TokenizerLike):
45 super().__init__(tokenizer)
46 self.position = 0
47 # Explicit state flags for robust streaming
vllm/entrypoints/openai/tool_parsers/xlam_tool_parser.py
+2 -2
@@ -21,14 +21,14 @@ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
21 ToolParser,
22 )
23 from vllm.logger import init_logger
24 -from vllm.transformers_utils.tokenizer import AnyTokenizer
24 +from vllm.tokenizers import TokenizerLike
25 from vllm.utils import random_uuid
26
27 logger = init_logger(__name__)
28
29
30 class xLAMToolParser(ToolParser):
31 - def __init__(self, tokenizer: AnyTokenizer):
31 + def __init__(self, tokenizer: TokenizerLike):
32 super().__init__(tokenizer)
33
34 # Initialize state for streaming mode
vllm/entrypoints/renderer.py
+5 -5
@@ -16,7 +16,7 @@ from vllm.inputs.data import EmbedsPrompt as EngineEmbedsPrompt
16 from vllm.inputs.data import TextPrompt as EngineTextPrompt
17 from vllm.inputs.data import TokensPrompt as EngineTokensPrompt
18 from vllm.inputs.parse import get_prompt_components, parse_raw_prompts
19 -from vllm.transformers_utils.tokenizer import AnyTokenizer
19 +from vllm.tokenizers import TokenizerLike
20 from vllm.utils.async_utils import AsyncMicrobatchTokenizer
21
22
@@ -85,7 +85,7 @@ class BaseRenderer(ABC):
85 def __init__(
86 self,
87 model_config: ModelConfig,
88 - tokenizer: AnyTokenizer | None = None,
88 + tokenizer: TokenizerLike | None = None,
89 ):
90 super().__init__()
91 self.model_config = model_config
@@ -200,8 +200,8 @@ class CompletionRenderer(BaseRenderer):
200 def __init__(
201 self,
202 model_config: ModelConfig,
203 - tokenizer: AnyTokenizer | None = None,
204 - async_tokenizer_pool: dict[AnyTokenizer, AsyncMicrobatchTokenizer]
203 + tokenizer: TokenizerLike | None = None,
204 + async_tokenizer_pool: dict[TokenizerLike, AsyncMicrobatchTokenizer]
205 | None = None,
206 ):
207 super().__init__(model_config, tokenizer)
@@ -373,7 +373,7 @@ class CompletionRenderer(BaseRenderer):
373 return async_tokenizer
374
375 tokenizer = self.tokenizer
376 - if self.tokenizer is None:
376 + if tokenizer is None:
377 raise ValueError("No tokenizer available for text input processing")
378
379 if self.async_tokenizer_pool is None:
vllm/entrypoints/score_utils.py
+8 -10
@@ -19,11 +19,7 @@ from vllm.inputs import TokensPrompt
19 from vllm.model_executor.models.interfaces import supports_score_template
20 from vllm.multimodal.inputs import MultiModalDataDict
21 from vllm.outputs import PoolingRequestOutput
22 -from vllm.transformers_utils.tokenizer import (
23 - AnyTokenizer,
24 - PreTrainedTokenizer,
25 - PreTrainedTokenizerFast,
26 -)
22 +from vllm.transformers_utils.tokenizer import TokenizerLike
23
24 ScoreContentPartParam: TypeAlias = (
25 ChatCompletionContentPartImageParam | ChatCompletionContentPartImageEmbedsParam
@@ -45,7 +41,7 @@ class ScoreMultiModalParam(TypedDict, total=False):
41
42
43 def _cosine_similarity(
48 - tokenizer: PreTrainedTokenizer | PreTrainedTokenizerFast,
44 + tokenizer: TokenizerLike,
45 embed_1: list[PoolingRequestOutput],
46 embed_2: list[PoolingRequestOutput],
47 ) -> list[PoolingRequestOutput]:
@@ -93,7 +89,7 @@ def parse_score_data(
89 data_1: str | ScoreContentPartParam,
90 data_2: str | ScoreContentPartParam,
91 model_config: ModelConfig,
96 - tokenizer: AnyTokenizer,
92 + tokenizer: TokenizerLike,
93 ) -> tuple[str, str, MultiModalDataDict | None]:
94 mm_tracker = MultiModalItemTracker(model_config, tokenizer)
95
@@ -118,12 +114,14 @@ def _parse_score_content(
114 mm_tracker: BaseMultiModalItemTracker,
115 ) -> _ContentPart | None:
116 if isinstance(data, str):
121 - data = ChatCompletionContentPartTextParam(type="text", text=data)
117 + part = ChatCompletionContentPartTextParam(type="text", text=data)
118 + else:
119 + part = data
120
121 mm_parser = mm_tracker.create_parser()
122
123 parse_res = _parse_chat_message_content_part(
126 - data,
124 + part,
125 mm_parser,
126 wrap_dicts=False,
127 interleave_strings=False,
@@ -181,7 +179,7 @@ def post_process_tokens(
179
180 def get_score_prompt(
181 model_config: ModelConfig,
184 - tokenizer: AnyTokenizer,
182 + tokenizer: TokenizerLike,
183 tokenization_kwargs: dict[str, Any],
184 data_1: str | ScoreContentPartParam,
185 data_2: str | ScoreContentPartParam,
vllm/entrypoints/utils.py
+1 -1
@@ -30,7 +30,7 @@ from vllm.entrypoints.openai.protocol import (
30 from vllm.entrypoints.openai.serving_models import LoRAModulePath
31 from vllm.logger import init_logger
32 from vllm.platforms import current_platform
33 -from vllm.transformers_utils.tokenizers import MistralTokenizer
33 +from vllm.tokenizers import MistralTokenizer
34 from vllm.utils.argparse_utils import FlexibleArgumentParser
35
36 logger = init_logger(__name__)
vllm/inputs/preprocess.py
+5 -5
@@ -17,7 +17,7 @@ from vllm.multimodal.inputs import (
17 MultiModalUUIDDict,
18 )
19 from vllm.multimodal.processing import BaseMultiModalProcessor
20 -from vllm.transformers_utils.tokenizer import AnyTokenizer
20 +from vllm.tokenizers import TokenizerLike
21 from vllm.utils.jsontree import json_iter_leaves
22 from vllm.v1.metrics.stats import MultiModalCacheStats
23
@@ -46,7 +46,7 @@ class InputPreprocessor:
46 def __init__(
47 self,
48 model_config: ModelConfig,
49 - tokenizer: AnyTokenizer | None,
49 + tokenizer: TokenizerLike | None,
50 mm_registry: MultiModalRegistry = MULTIMODAL_REGISTRY,
51 mm_processor_cache: BaseMultiModalProcessorCache | None = None,
52 ) -> None:
@@ -59,7 +59,7 @@ class InputPreprocessor:
59
60 self.mm_cache_stats = MultiModalCacheStats() if mm_processor_cache else None
61
62 - def get_tokenizer(self) -> AnyTokenizer:
62 + def get_tokenizer(self) -> TokenizerLike:
63 if self.tokenizer is None:
64 raise ValueError(
65 "You cannot pass text prompts when `skip_tokenizer_init` is True"
@@ -228,11 +228,11 @@ class InputPreprocessor:
228
229 return tokenizer.encode(prompt, **tokenization_kwargs)
230
231 - def _get_mm_tokenizer(self) -> AnyTokenizer:
231 + def _get_mm_tokenizer(self) -> TokenizerLike:
232 # PrithviGeoSpatialMAE needs to be initialized without a tokenizer
233 # while using also multi-modal input
234 if not self.tokenizer:
235 - return cast(AnyTokenizer, object()) # Dummy
235 + return cast(TokenizerLike, object()) # Dummy
236
237 tokenizer = self.get_tokenizer()
238 return tokenizer
vllm/logits_process.py
+2 -2
@@ -5,7 +5,7 @@ from typing import TypeAlias
5
6 import torch
7
8 -from vllm.transformers_utils.tokenizer import AnyTokenizer
8 +from vllm.tokenizers import TokenizerLike
9
10 LogitsProcessor: TypeAlias = (
11 Callable[[list[int], torch.Tensor], torch.Tensor]
@@ -19,7 +19,7 @@ to sample from."""
19
20
21 def get_bad_words_logits_processors(
22 - bad_words: list[str], tokenizer: AnyTokenizer
22 + bad_words: list[str], tokenizer: TokenizerLike
23 ) -> list[LogitsProcessor]:
24 bad_words_ids: list[list[int]] = list()
25
vllm/model_executor/models/h2ovl.py
+2 -2
@@ -28,7 +28,7 @@ from vllm.multimodal.processing import (
28 PromptUpdate,
29 PromptUpdateDetails,
30 )
31 -from vllm.transformers_utils.tokenizer import AnyTokenizer
31 +from vllm.tokenizers import TokenizerLike
32
33 from .intern_vit import InternVisionModel
34 from .internvl import (
@@ -241,7 +241,7 @@ class H2OVLProcessor(BaseInternVLProcessor):
241 def __init__(
242 self,
243 config: PretrainedConfig,
244 - tokenizer: AnyTokenizer,
244 + tokenizer: TokenizerLike,
245 *,
246 min_dynamic_patch: int | None = None,
247 max_dynamic_patch: int | None = None,
vllm/model_executor/models/internvl.py
+3 -3
@@ -50,7 +50,7 @@ from vllm.multimodal.processing import (
50 )
51 from vllm.multimodal.profiling import BaseDummyInputsBuilder
52 from vllm.sequence import IntermediateTensors
53 -from vllm.transformers_utils.tokenizer import AnyTokenizer
53 +from vllm.tokenizers import TokenizerLike
54 from vllm.utils.tensor_schema import TensorSchema, TensorShape
55 from vllm.utils.torch_utils import set_default_torch_num_threads
56
@@ -347,7 +347,7 @@ class BaseInternVLProcessor(ABC):
347 def __init__(
348 self,
349 config: PretrainedConfig,
350 - tokenizer: AnyTokenizer,
350 + tokenizer: TokenizerLike,
351 *,
352 min_dynamic_patch: int | None = None,
353 max_dynamic_patch: int | None = None,
@@ -561,7 +561,7 @@ class InternVLProcessor(BaseInternVLProcessor):
561 def __init__(
562 self,
563 config: PretrainedConfig,
564 - tokenizer: AnyTokenizer,
564 + tokenizer: TokenizerLike,
565 *,
566 min_dynamic_patch: int | None = None,
567 max_dynamic_patch: int | None = None,
vllm/model_executor/models/nano_nemotron_vl.py
+5 -5
@@ -73,9 +73,9 @@ from vllm.multimodal.processing import (
73 )
74 from vllm.multimodal.profiling import BaseDummyInputsBuilder
75 from vllm.sequence import IntermediateTensors
76 +from vllm.tokenizers import TokenizerLike
77 from vllm.transformers_utils.configs.radio import RadioConfig
78 from vllm.transformers_utils.tokenizer import (
78 - AnyTokenizer,
79 cached_tokenizer_from_config,
80 encode_tokens,
81 )
@@ -284,7 +284,7 @@ class BaseNanoNemotronVLProcessor(ABC):
284 def __init__(
285 self,
286 config: PretrainedConfig,
287 - tokenizer: AnyTokenizer,
287 + tokenizer: TokenizerLike,
288 *args,
289 max_num_tiles: int | None = None,
290 **kwargs,
@@ -434,7 +434,7 @@ class NanoNemotronVLProcessor(BaseNanoNemotronVLProcessor):
434 def __init__(
435 self,
436 config: PretrainedConfig,
437 - tokenizer: AnyTokenizer,
437 + tokenizer: TokenizerLike,
438 *,
439 max_num_tiles: int | None = None,
440 min_dynamic_patch: int | None = None,
@@ -645,7 +645,7 @@ class NanoNemotronVLProcessor(BaseNanoNemotronVLProcessor):
645 tokens_per_frame: list[int],
646 frames_indices: list[int],
647 frame_duration_ms: int,
648 - tokenizer: AnyTokenizer,
648 + tokenizer: TokenizerLike,
649 img_start_token_ids: list[int],
650 img_end_token_ids: list[int],
651 img_context_token_ids: list[int],
@@ -670,7 +670,7 @@ class NanoNemotronVLProcessor(BaseNanoNemotronVLProcessor):
670 tokens_per_frame (list[int]): number of tokens per frame
671 frames_indices (list[int]): frame indices
672 frame_duration_ms (int): duration of each frame in milliseconds
673 - tokenizer (AnyTokenizer): tokenizer to use for tokenizing frame separators
673 + tokenizer (TokenizerLike): tokenizer to use for tokenizing frame separators
674 img_start_token_ids (list[int]): pre-tokenized IMG_START tokens
675 img_end_token_ids (list[int]): pre-tokenized IMG_END tokens
676 img_context_token_ids (list[int]): pre-tokenized IMG_CONTEXT tokens
vllm/model_executor/models/nemotron_vl.py
+2 -2
@@ -34,8 +34,8 @@ from vllm.multimodal import MULTIMODAL_REGISTRY
34 from vllm.multimodal.image import convert_image_mode
35 from vllm.multimodal.processing import PromptUpdateDetails
36 from vllm.sequence import IntermediateTensors
37 +from vllm.tokenizers import TokenizerLike
38 from vllm.transformers_utils.processor import cached_image_processor_from_config
38 -from vllm.transformers_utils.tokenizer import AnyTokenizer
39
40 from .interfaces import (
41 MultiModalEmbeddings,
@@ -203,7 +203,7 @@ class NemotronVLProcessor(InternVLProcessor):
203 def __init__(
204 self,
205 config: PretrainedConfig,
206 - tokenizer: AnyTokenizer,
206 + tokenizer: TokenizerLike,
207 image_processor: BaseImageProcessorFast,
208 *,
209 min_dynamic_patch: int | None = None,
vllm/model_executor/models/opencua.py
+2 -2
@@ -31,7 +31,7 @@ from vllm.multimodal.processing import (
31 PromptReplacement,
32 PromptUpdate,
33 )
34 -from vllm.transformers_utils.tokenizer import AnyTokenizer
34 +from vllm.tokenizers import TokenizerLike
35
36 from .qwen2_5_vl import (
37 Qwen2_5_VisionTransformer as OpenCUAVisionTransformer,
@@ -79,7 +79,7 @@ class OpenCUAProcessor(Qwen2VLProcessor):
79 def __init__(
80 self,
81 vision_config: dict,
82 - tokenizer: AnyTokenizer,
82 + tokenizer: TokenizerLike,
83 **kwargs,
84 ):
85 image_processor = Qwen2VLImageProcessor(**vision_config)
vllm/model_executor/models/pixtral.py
+2 -4
@@ -59,10 +59,8 @@ from vllm.multimodal.processing import (
59 from vllm.multimodal.profiling import BaseDummyInputsBuilder, ProcessorInputs
60 from vllm.platforms import current_platform
61 from vllm.sequence import IntermediateTensors
62 -from vllm.transformers_utils.tokenizer import (
63 - MistralTokenizer,
64 - cached_tokenizer_from_config,
65 -)
62 +from vllm.tokenizers import MistralTokenizer
63 +from vllm.transformers_utils.tokenizer import cached_tokenizer_from_config
64 from vllm.utils.tensor_schema import TensorSchema, TensorShape
65
66 from .interfaces import MultiModalEmbeddings, SupportsMultiModal, SupportsPP
vllm/model_executor/models/qwen2_vl.py
+2 -2
@@ -91,7 +91,7 @@ from vllm.multimodal.processing import (
91 )
92 from vllm.multimodal.profiling import BaseDummyInputsBuilder
93 from vllm.sequence import IntermediateTensors
94 -from vllm.transformers_utils.tokenizer import AnyTokenizer
94 +from vllm.tokenizers import TokenizerLike
95 from vllm.utils.tensor_schema import TensorSchema, TensorShape
96
97 from .interfaces import (
@@ -1533,7 +1533,7 @@ class Tarsier2Processor(Qwen2VLProcessor):
1533 def __init__(
1534 self,
1535 vision_config: dict,
1536 - tokenizer: AnyTokenizer,
1536 + tokenizer: TokenizerLike,
1537 **kwargs,
1538 ):
1539 self.image_processor = Tarsier2ImageProcessor(**vision_config)
vllm/model_executor/models/skyworkr1v.py
+2 -2
@@ -47,7 +47,7 @@ from vllm.multimodal.processing import (
47 )
48 from vllm.multimodal.profiling import BaseDummyInputsBuilder
49 from vllm.sequence import IntermediateTensors
50 -from vllm.transformers_utils.tokenizer import AnyTokenizer
50 +from vllm.tokenizers import TokenizerLike
51 from vllm.utils.tensor_schema import TensorSchema, TensorShape
52
53 from .interfaces import MultiModalEmbeddings, SupportsMultiModal, SupportsPP
@@ -282,7 +282,7 @@ class SkyworkR1VProcessor:
282 def __init__(
283 self,
284 config: PretrainedConfig,
285 - tokenizer: AnyTokenizer,
285 + tokenizer: TokenizerLike,
286 *,
287 min_dynamic_patch: int | None = None,
288 max_dynamic_patch: int | None = None,
vllm/model_executor/models/step3_vl.py
+2 -2
@@ -43,8 +43,8 @@ from vllm.multimodal.processing import (
43 )
44 from vllm.multimodal.profiling import BaseDummyInputsBuilder
45 from vllm.sequence import IntermediateTensors
46 +from vllm.tokenizers import TokenizerLike
47 from vllm.transformers_utils.configs import Step3VisionEncoderConfig
47 -from vllm.transformers_utils.tokenizer import AnyTokenizer
48 from vllm.utils.tensor_schema import TensorSchema, TensorShape
49
50 from .interfaces import MultiModalEmbeddings, SupportsMultiModal, SupportsPP
@@ -321,7 +321,7 @@ class Step3VLProcessor:
321 def __init__(
322 self,
323 config: PretrainedConfig,
324 - tokenizer: AnyTokenizer,
324 + tokenizer: TokenizerLike,
325 ) -> None:
326 super().__init__()
327
vllm/model_executor/models/voxtral.py
+2 -4
@@ -51,10 +51,8 @@ from vllm.multimodal.processing import (
51 )
52 from vllm.multimodal.profiling import BaseDummyInputsBuilder, ProcessorInputs
53 from vllm.sequence import IntermediateTensors
54 -from vllm.transformers_utils.tokenizer import (
55 - MistralTokenizer,
56 - cached_tokenizer_from_config,
57 -)
54 +from vllm.tokenizers import MistralTokenizer
55 +from vllm.transformers_utils.tokenizer import cached_tokenizer_from_config
56
57 from .interfaces import SupportsLoRA, SupportsMultiModal, SupportsTranscription
58 from .utils import init_vllm_registered_model, maybe_prefix
vllm/multimodal/processing.py
+22 -21
@@ -23,8 +23,9 @@ import torch
23 from typing_extensions import TypeVar, assert_never
24
25 from vllm.logger import init_logger
26 +from vllm.tokenizers import TokenizerLike
27 from vllm.transformers_utils.processor import cached_processor_from_config
27 -from vllm.transformers_utils.tokenizer import AnyTokenizer, decode_tokens, encode_tokens
28 +from vllm.transformers_utils.tokenizer import decode_tokens, encode_tokens
29 from vllm.utils.collection_utils import flatten_2d_lists, full_groupby
30 from vllm.utils.func_utils import get_allowed_kwarg_only_overrides
31 from vllm.utils.jsontree import JSONTree, json_map_leaves
@@ -76,7 +77,7 @@ PromptSeq: TypeAlias = str | list[int]
77
78 @lru_cache(maxsize=2048)
79 def _cached_encode(
79 - tokenizer: AnyTokenizer,
80 + tokenizer: TokenizerLike,
81 text: str,
82 *,
83 add_special_tokens: bool | None = None,
@@ -86,7 +87,7 @@ def _cached_encode(
87
88 @lru_cache(maxsize=2048)
89 def _cached_decode(
89 - tokenizer: AnyTokenizer,
90 + tokenizer: TokenizerLike,
91 token_ids: tuple[int, ...],
92 *,
93 skip_special_tokens: bool | None = None,
@@ -96,14 +97,14 @@ def _cached_decode(
97 )
98
99
99 -def _seq2text(tokenizer: AnyTokenizer, seq: PromptSeq) -> str:
100 +def _seq2text(tokenizer: TokenizerLike, seq: PromptSeq) -> str:
101 if isinstance(seq, str):
102 return seq
103
104 return _cached_decode(tokenizer, tuple(seq))
105
106
106 -def _seq2tokens(tokenizer: AnyTokenizer, seq: PromptSeq) -> list[int]:
107 +def _seq2tokens(tokenizer: TokenizerLike, seq: PromptSeq) -> list[int]:
108 if isinstance(seq, str):
109 return _cached_encode(tokenizer, seq, add_special_tokens=False)
110
@@ -113,7 +114,7 @@ def _seq2tokens(tokenizer: AnyTokenizer, seq: PromptSeq) -> list[int]:
114 class _GetMatchIndex(Protocol):
115 def __call__(
116 self,
116 - tokenizer: AnyTokenizer,
117 + tokenizer: TokenizerLike,
118 prompt: PromptSeq,
119 start_idx: int = 0,
120 ) -> int | None: ...
@@ -143,7 +144,7 @@ class PromptIndexTargets:
144 """
145
146 def get_match_index(
146 - tokenizer: AnyTokenizer,
147 + tokenizer: TokenizerLike,
148 prompt: PromptSeq,
149 start_idx: int = 0,
150 ) -> int | None:
@@ -199,7 +200,7 @@ class PromptUpdateDetails(Generic[_S]):
200 full: _S
201 """The full content."""
202
202 - is_embed: Callable[[AnyTokenizer, PromptSeq], torch.Tensor] | None = None
203 + is_embed: Callable[[TokenizerLike, PromptSeq], torch.Tensor] | None = None
204 """
205 Given [`full`][vllm.multimodal.processing.PromptUpdateDetails.full],
206 return a boolean mask of shape `(len(full),)` indicating which positions
@@ -220,7 +221,7 @@ class PromptUpdateDetails(Generic[_S]):
221 seq: _S,
222 embed_text: str,
223 ) -> "PromptUpdateDetails[_S]":
223 - def is_embed(tokenizer: AnyTokenizer, full: PromptSeq) -> torch.Tensor:
224 + def is_embed(tokenizer: TokenizerLike, full: PromptSeq) -> torch.Tensor:
225 embed_token_ids = encode_tokens(tokenizer, embed_text)
226 token_ids = _seq2tokens(tokenizer, full)
227
@@ -236,7 +237,7 @@ class PromptUpdateDetails(Generic[_S]):
237 seq: _S,
238 embed_token_id: int,
239 ) -> "PromptUpdateDetails[_S]":
239 - def is_embed(tokenizer: AnyTokenizer, full: PromptSeq) -> torch.Tensor:
240 + def is_embed(tokenizer: TokenizerLike, full: PromptSeq) -> torch.Tensor:
241 token_ids = _seq2tokens(tokenizer, full)
242
243 return torch.tensor(token_ids) == embed_token_id
@@ -522,7 +523,7 @@ class ResolvedPromptUpdate:
523 def iter_token_matches(
524 self,
525 prompt: list[int],
525 - tokenizer: AnyTokenizer,
526 + tokenizer: TokenizerLike,
527 *,
528 start_idx: int = 0,
529 ) -> Generator[PromptTargetMatch]:
@@ -544,7 +545,7 @@ class ResolvedPromptUpdate:
545 def iter_text_matches(
546 self,
547 prompt: str,
547 - tokenizer: AnyTokenizer,
548 + tokenizer: TokenizerLike,
549 *,
550 start_idx: int = 0,
551 ) -> Generator[PromptTargetMatch]:
@@ -566,7 +567,7 @@ class ResolvedPromptUpdate:
567 def iter_matches(
568 self,
569 prompt: list[int] | str,
569 - tokenizer: AnyTokenizer,
570 + tokenizer: TokenizerLike,
571 *,
572 start_idx: int = 0,
573 ) -> Generator[PromptTargetMatch]:
@@ -675,7 +676,7 @@ _MatchToApply = tuple[tuple[str, int], tuple[PromptTargetMatch, int]]
676 def _find_matches(
677 prompt: _S,
678 mm_prompt_updates: "MultiModalPromptUpdates",
678 - tokenizer: AnyTokenizer,
679 + tokenizer: TokenizerLike,
680 *,
681 prev_end_idx: int = 0,
682 current_result: "MultiModalPromptUpdatesApplyResult",
@@ -740,7 +741,7 @@ def _all_items_found(
741 def _apply_matches(
742 prompt: _S,
743 mm_prompt_updates: "MultiModalPromptUpdates",
743 - tokenizer: AnyTokenizer,
744 + tokenizer: TokenizerLike,
745 ) -> tuple[list[_S], "MultiModalPromptUpdatesApplyResult"]:
746 mm_item_counts = {m: len(items) for m, items in mm_prompt_updates.items()}
747
@@ -806,7 +807,7 @@ def _apply_matches(
807 def apply_token_matches(
808 prompt: list[int],
809 mm_prompt_updates: "MultiModalPromptUpdates",
809 - tokenizer: AnyTokenizer,
810 + tokenizer: TokenizerLike,
811 ) -> tuple[list[int], "MultiModalPromptUpdatesApplyResult"]:
812 """
813 Apply the updates in `mm_prompt_updates` to `prompt`.
@@ -823,7 +824,7 @@ def apply_token_matches(
824 def apply_text_matches(
825 prompt: str,
826 mm_prompt_updates: "MultiModalPromptUpdates",
826 - tokenizer: AnyTokenizer,
827 + tokenizer: TokenizerLike,
828 ) -> tuple[str, "MultiModalPromptUpdatesApplyResult"]:
829 """
830 Apply the updates in `mm_prompt_updates` to `prompt`.
@@ -840,7 +841,7 @@ def apply_text_matches(
841 def _iter_placeholders(
842 prompt: list[int],
843 mm_prompt_updates: "MultiModalPromptUpdates",
843 - tokenizer: AnyTokenizer,
844 + tokenizer: TokenizerLike,
845 ) -> Iterable[PlaceholderFeaturesInfo]:
846 """
847 Yield each set of placeholder tokens found in `prompt`.
@@ -909,7 +910,7 @@ def _iter_placeholders(
910 def find_mm_placeholders(
911 prompt: list[int],
912 mm_prompt_updates: "MultiModalPromptUpdates",
912 - tokenizer: AnyTokenizer,
913 + tokenizer: TokenizerLike,
914 ) -> Mapping[str, list[PlaceholderFeaturesInfo]]:
915 it = _iter_placeholders(prompt, mm_prompt_updates, tokenizer)
916 return dict(full_groupby_modality(it))
@@ -930,7 +931,7 @@ class InputProcessingContext:
931 model_config: ModelConfig
932 """The configuration of the model."""
933
933 - tokenizer: AnyTokenizer
934 + tokenizer: TokenizerLike
935 """The tokenizer used to tokenize the inputs."""
936
937 @overload
@@ -1146,7 +1147,7 @@ class BaseProcessingInfo:
1147 def model_id(self) -> str:
1148 return self.ctx.model_config.model
1149
1149 - def get_tokenizer(self) -> AnyTokenizer:
1150 + def get_tokenizer(self) -> TokenizerLike:
1151 return self.ctx.tokenizer
1152
1153 def get_hf_config(self) -> PretrainedConfig:
vllm/multimodal/registry.py
+9 -5
@@ -6,7 +6,8 @@ from typing import TYPE_CHECKING, Generic, Protocol, TypeVar, cast
6
7 from vllm.config.multimodal import BaseDummyOptions
8 from vllm.logger import init_logger
9 -from vllm.transformers_utils.tokenizer import AnyTokenizer, cached_tokenizer_from_config
9 +from vllm.tokenizers import TokenizerLike
10 +from vllm.transformers_utils.tokenizer import cached_tokenizer_from_config
11
12 from .cache import BaseMultiModalProcessorCache
13 from .processing import (
@@ -231,17 +232,20 @@ class MultiModalRegistry:
232 def _create_processing_ctx(
233 self,
234 model_config: "ModelConfig",
234 - tokenizer: AnyTokenizer | None = None,
235 + tokenizer: TokenizerLike | None = None,
236 ) -> InputProcessingContext:
236 - if tokenizer is None and not model_config.skip_tokenizer_init:
237 + if model_config.skip_tokenizer_init:
238 + tokenizer = cast(TokenizerLike, object())
239 + elif tokenizer is None:
240 tokenizer = cached_tokenizer_from_config(model_config)
241 +
242 return InputProcessingContext(model_config, tokenizer)
243
244 def _create_processing_info(
245 self,
246 model_config: "ModelConfig",
247 *,
244 - tokenizer: AnyTokenizer | None = None,
248 + tokenizer: TokenizerLike | None = None,
249 ) -> BaseProcessingInfo:
250 model_cls = self._get_model_cls(model_config)
251 factories = model_cls._processor_factory
@@ -252,7 +256,7 @@ class MultiModalRegistry:
256 self,
257 model_config: "ModelConfig",
258 *,
255 - tokenizer: AnyTokenizer | None = None,
259 + tokenizer: TokenizerLike | None = None,
260 cache: BaseMultiModalProcessorCache | None = None,
261 ) -> BaseMultiModalProcessor[BaseProcessingInfo]:
262 """
vllm/reasoning/abs_reasoning_parsers.py
+3 -3
@@ -19,12 +19,12 @@ if TYPE_CHECKING:
19 DeltaMessage,
20 ResponsesRequest,
21 )
22 - from vllm.transformers_utils.tokenizer import AnyTokenizer
22 + from vllm.tokenizers import TokenizerLike
23 else:
24 ChatCompletionRequest = Any
25 DeltaMessage = Any
26 ResponsesRequest = Any
27 - AnyTokenizer = Any
27 + TokenizerLike = Any
28
29 logger = init_logger(__name__)
30
@@ -37,7 +37,7 @@ class ReasoningParser:
37 It is used to extract reasoning content from the model output.
38 """
39
40 - def __init__(self, tokenizer: AnyTokenizer, *args, **kwargs):
40 + def __init__(self, tokenizer: TokenizerLike, *args, **kwargs):
41 self.model_tokenizer = tokenizer
42
43 @cached_property
vllm/reasoning/basic_parsers.py
+2 -2
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Any
7
8 from vllm.entrypoints.openai.protocol import DeltaMessage
9 from vllm.reasoning.abs_reasoning_parsers import ReasoningParser
10 -from vllm.transformers_utils.tokenizer import AnyTokenizer
10 +from vllm.tokenizers import TokenizerLike
11
12 if TYPE_CHECKING:
13 from vllm.entrypoints.openai.protocol import (
@@ -43,7 +43,7 @@ class BaseThinkingReasoningParser(ReasoningParser):
43 """The token that ends reasoning content."""
44 raise NotImplementedError
45
46 - def __init__(self, tokenizer: AnyTokenizer, *args, **kwargs):
46 + def __init__(self, tokenizer: TokenizerLike, *args, **kwargs):
47 super().__init__(tokenizer, *args, **kwargs)
48
49 if not self.model_tokenizer:
vllm/reasoning/minimax_m2_reasoning_parser.py
+2 -2
@@ -11,7 +11,7 @@ from vllm.entrypoints.openai.protocol import (
11 from vllm.logger import init_logger
12 from vllm.reasoning.abs_reasoning_parsers import ReasoningParser
13 from vllm.reasoning.basic_parsers import BaseThinkingReasoningParser
14 -from vllm.transformers_utils.tokenizer import AnyTokenizer
14 +from vllm.tokenizers import TokenizerLike
15
16 logger = init_logger(__name__)
17
@@ -37,7 +37,7 @@ class MiniMaxM2AppendThinkReasoningParser(ReasoningParser):
37 Reasoning parser for MiniMax M2 model.
38 """
39
40 - def __init__(self, tokenizer: AnyTokenizer, *args, **kwargs):
40 + def __init__(self, tokenizer: TokenizerLike, *args, **kwargs):
41 super().__init__(tokenizer, *args, **kwargs)
42 self.end_token_id = self.vocab.get("</think>")
43
vllm/reasoning/mistral_reasoning_parser.py
+1 -1
@@ -6,7 +6,7 @@ from functools import cached_property
6 from vllm.logger import init_logger
7 from vllm.reasoning import ReasoningParser
8 from vllm.reasoning.deepseek_r1_reasoning_parser import DeepSeekR1ReasoningParser
9 -from vllm.transformers_utils.tokenizers.mistral import MistralTokenizer
9 +from vllm.tokenizers import MistralTokenizer
10
11 logger = init_logger(__name__)
12
vllm/reasoning/olmo3_reasoning_parser.py
+2 -2
@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING
9 import regex as re
10
11 if TYPE_CHECKING:
12 - from vllm.transformers_utils.tokenizer import AnyTokenizer
12 + from vllm.tokenizers import TokenizerLike
13
14 from vllm.entrypoints.openai.protocol import (
15 ChatCompletionRequest,
@@ -220,7 +220,7 @@ class Olmo3ReasoningParser(ReasoningParser):
220 token is missing from generation.
221 """
222
223 - def __init__(self, tokenizer: "AnyTokenizer", *args, **kwargs):
223 + def __init__(self, tokenizer: "TokenizerLike", *args, **kwargs):
224 super().__init__(tokenizer, *args, **kwargs)
225
226 self.think_start = r"<think>"
vllm/sampling_params.py
+2 -2
@@ -13,7 +13,7 @@ from pydantic.dataclasses import dataclass
13
14 from vllm.logger import init_logger
15 from vllm.logits_process import LogitsProcessor
16 -from vllm.transformers_utils.tokenizer import AnyTokenizer
16 +from vllm.tokenizers import TokenizerLike
17 from vllm.v1.serial_utils import PydanticMsgspecMixin
18
19 logger = init_logger(__name__)
@@ -477,7 +477,7 @@ class SamplingParams(
477 eos_ids.update(self.stop_token_ids)
478 self.stop_token_ids = list(eos_ids)
479
480 - def update_from_tokenizer(self, tokenizer: AnyTokenizer) -> None:
480 + def update_from_tokenizer(self, tokenizer: TokenizerLike) -> None:
481 if not self.bad_words:
482 return
483 self._bad_words_token_ids = []
vllm/tokenizers/__init__.py new
+8
@@ -0,0 +1,8 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +
4 +from .mistral import MistralTokenizer
5 +from .protocol import TokenizerLike
6 +from .registry import TokenizerRegistry
7 +
8 +__all__ = ["TokenizerLike", "MistralTokenizer", "TokenizerRegistry"]
vllm/tokenizers/mistral.py renamed
+7 -22
@@ -4,7 +4,8 @@
4 from typing import TYPE_CHECKING, Any, cast
5
6 from vllm.logger import init_logger
7 -from vllm.transformers_utils.tokenizer_base import TokenizerBase
7 +
8 +from .protocol import TokenizerLike
9
10 if TYPE_CHECKING:
11 from mistral_common.protocol.instruct.request import (
@@ -163,7 +164,7 @@ def _tekken_token_to_id(tokenizer: "Tekkenizer", t: str | bytes) -> int:
164 return tokenizer.unk_id
165
166
166 -class MistralTokenizer(TokenizerBase):
167 +class MistralTokenizer(TokenizerLike):
168 def __init__(self, tokenizer: "TransformersMistralTokenizer") -> None:
169 from mistral_common.protocol.instruct.validator import ValidationMode
170 from mistral_common.tokens.tokenizers.sentencepiece import (
@@ -270,14 +271,6 @@ class MistralTokenizer(TokenizerBase):
271 def eos_token_id(self) -> int:
272 return self.tokenizer.eos_id
273
273 - @property
274 - def sep_token(self) -> str:
275 - raise NotImplementedError()
276 -
277 - @property
278 - def pad_token(self) -> str:
279 - return self.transformers_tokenizer.pad_token
280 -
274 @property
275 def is_fast(self) -> bool:
276 return True
@@ -292,11 +285,14 @@ class MistralTokenizer(TokenizerBase):
285
286 @property
287 def truncation_side(self) -> str:
295 - raise NotImplementedError()
288 + return self.transformers_tokenizer.truncation_side
289
290 def _is_special_token_id(self, token_id: int) -> bool:
291 return token_id in self._special_token_ids_set
292
293 + def __hash__(self) -> int:
294 + return hash(id(self))
295 +
296 def __len__(self) -> int:
297 return self.vocab_size
298
@@ -341,17 +337,6 @@ class MistralTokenizer(TokenizerBase):
337 # Mistral tokenizers have no added vocabulary
338 return {}
339
344 - def encode_one(
345 - self,
346 - text: str,
347 - truncation: bool = False,
348 - max_length: int | None = None,
349 - ) -> list[int]:
350 - # Mistral Tokenizers should not add special tokens
351 - return self.transformers_tokenizer.encode(
352 - text, add_special_tokens=False, truncation=truncation, max_length=max_length
353 - )
354 -
340 def encode(
341 self,
342 text: str,
vllm/tokenizers/protocol.py new
+105
@@ -0,0 +1,105 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +
4 +from typing import TYPE_CHECKING, Any, Protocol
5 +
6 +from typing_extensions import Self
7 +
8 +if TYPE_CHECKING:
9 + from vllm.entrypoints.chat_utils import ChatCompletionMessageParam
10 +
11 +
12 +class TokenizerLike(Protocol):
13 + @classmethod
14 + def from_pretrained(
15 + cls,
16 + pretrained_model_name_or_path: str,
17 + /,
18 + *,
19 + revision: str | None = None,
20 + ) -> Self:
21 + raise NotImplementedError
22 +
23 + @property
24 + def all_special_tokens(self) -> list[str]:
25 + raise NotImplementedError
26 +
27 + @property
28 + def all_special_ids(self) -> list[int]:
29 + raise NotImplementedError
30 +
31 + @property
32 + def bos_token_id(self) -> int:
33 + raise NotImplementedError
34 +
35 + @property
36 + def eos_token_id(self) -> int:
37 + raise NotImplementedError
38 +
39 + @property
40 + def is_fast(self) -> bool:
41 + raise NotImplementedError
42 +
43 + @property
44 + def vocab_size(self) -> int:
45 + raise NotImplementedError
46 +
47 + @property
48 + def max_token_id(self) -> int:
49 + raise NotImplementedError
50 +
51 + @property
52 + def truncation_side(self) -> str:
53 + raise NotImplementedError
54 +
55 + def __hash__(self) -> int:
56 + return hash(id(self))
57 +
58 + def __len__(self) -> int:
59 + return self.vocab_size
60 +
61 + def __call__(
62 + self,
63 + text: str | list[str] | list[int],
64 + text_pair: str | None = None,
65 + add_special_tokens: bool = False,
66 + truncation: bool = False,
67 + max_length: int | None = None,
68 + ):
69 + raise NotImplementedError
70 +
71 + def get_vocab(self) -> dict[str, int]:
72 + raise NotImplementedError
73 +
74 + def get_added_vocab(self) -> dict[str, int]:
75 + raise NotImplementedError
76 +
77 + def encode(
78 + self,
79 + text: str,
80 + truncation: bool | None = None,
81 + max_length: int | None = None,
82 + add_special_tokens: bool | None = None,
83 + ) -> list[int]:
84 + raise NotImplementedError
85 +
86 + def apply_chat_template(
87 + self,
88 + messages: list["ChatCompletionMessageParam"],
89 + tools: list[dict[str, Any]] | None = None,
90 + **kwargs,
91 + ) -> list[int]:
92 + raise NotImplementedError
93 +
94 + def convert_tokens_to_string(self, tokens: list[str]) -> str:
95 + raise NotImplementedError
96 +
97 + def decode(self, ids: list[int] | int, skip_special_tokens: bool = True) -> str:
98 + raise NotImplementedError
99 +
100 + def convert_ids_to_tokens(
101 + self,
102 + ids: list[int],
103 + skip_special_tokens: bool = True,
104 + ) -> list[str]:
105 + raise NotImplementedError
vllm/tokenizers/registry.py new
+28
@@ -0,0 +1,28 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +import importlib
4 +
5 +from .protocol import TokenizerLike
6 +
7 +
8 +class TokenizerRegistry:
9 + # Tokenizer name -> (tokenizer module, tokenizer class)
10 + REGISTRY: dict[str, tuple[str, str]] = {}
11 +
12 + @staticmethod
13 + def register(name: str, module: str, class_name: str) -> None:
14 + TokenizerRegistry.REGISTRY[name] = (module, class_name)
15 +
16 + @staticmethod
17 + def get_tokenizer(
18 + tokenizer_name: str,
19 + *args,
20 + **kwargs,
21 + ) -> "TokenizerLike":
22 + tokenizer_cls = TokenizerRegistry.REGISTRY.get(tokenizer_name)
23 + if tokenizer_cls is None:
24 + raise ValueError(f"Tokenizer {tokenizer_name} not found.")
25 +
26 + tokenizer_module = importlib.import_module(tokenizer_cls[0])
27 + class_ = getattr(tokenizer_module, tokenizer_cls[1])
28 + return class_.from_pretrained(*args, **kwargs)
vllm/transformers_utils/config.py
+4 -3
@@ -26,8 +26,9 @@ from transformers.utils import CONFIG_NAME as HF_CONFIG_NAME
26
27 from vllm import envs
28 from vllm.logger import init_logger
29 -from vllm.transformers_utils.config_parser_base import ConfigParserBase
30 -from vllm.transformers_utils.repo_utils import (
29 +
30 +from .config_parser_base import ConfigParserBase
31 +from .repo_utils import (
32 _get_hf_token,
33 file_or_path_exists,
34 get_hf_file_to_dict,
@@ -35,7 +36,7 @@ from vllm.transformers_utils.repo_utils import (
36 try_get_local_file,
37 with_retry,
38 )
38 -from vllm.transformers_utils.utils import (
39 +from .utils import (
40 check_gguf_file,
41 is_gguf,
42 is_remote_gguf,
vllm/transformers_utils/detokenizer_utils.py
+5 -5
@@ -2,7 +2,7 @@
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
5 -from .tokenizer import AnyTokenizer
5 +from vllm.tokenizers import TokenizerLike
6
7
8 def _replace_none_with_empty(tokens: list[str | None]):
@@ -12,7 +12,7 @@ def _replace_none_with_empty(tokens: list[str | None]):
12
13
14 def _convert_tokens_to_string_with_added_encoders(
15 - tokenizer: AnyTokenizer,
15 + tokenizer: TokenizerLike,
16 output_tokens: list[str],
17 skip_special_tokens: bool,
18 spaces_between_special_tokens: bool,
@@ -57,7 +57,7 @@ INITIAL_INCREMENTAL_DETOKENIZATION_OFFSET = 5
57
58
59 def convert_prompt_ids_to_tokens(
60 - tokenizer: AnyTokenizer,
60 + tokenizer: TokenizerLike,
61 prompt_ids: list[int],
62 skip_special_tokens: bool = False,
63 ) -> tuple[list[str], int, int]:
@@ -81,7 +81,7 @@ def convert_prompt_ids_to_tokens(
81
82
83 def convert_ids_list_to_tokens(
84 - tokenizer: AnyTokenizer,
84 + tokenizer: TokenizerLike,
85 token_ids: list[int],
86 ) -> list[str]:
87 """Detokenize the input ids individually.
@@ -108,7 +108,7 @@ def convert_ids_list_to_tokens(
108 # https://github.com/huggingface/text-generation-inference/blob/v0.9.4/server/text_generation_server/models/model.py#L62C9-L62C15
109 # under Apache 2.0 license
110 def detokenize_incrementally(
111 - tokenizer: AnyTokenizer,
111 + tokenizer: TokenizerLike,
112 all_input_ids: list[int],
113 prev_tokens: list[str] | None,
114 prefix_offset: int,
vllm/transformers_utils/gguf_utils.py
+2 -1
@@ -9,7 +9,8 @@ from gguf.constants import Keys, VisionProjectorType
9 from transformers import Gemma3Config, PretrainedConfig, SiglipVisionConfig
10
11 from vllm.logger import init_logger
12 -from vllm.transformers_utils.repo_utils import list_filtered_repo_files
12 +
13 +from .repo_utils import list_filtered_repo_files
14
15 logger = init_logger(__name__)
16
vllm/transformers_utils/tokenizer.py
+33 -27
@@ -5,41 +5,48 @@ import contextlib
5 import copy
6 import importlib.util
7 import os
8 +import warnings
9 from functools import lru_cache
10 from pathlib import Path
10 -from typing import TYPE_CHECKING, Any, TypeAlias
11 +from typing import TYPE_CHECKING, Any
12
13 import huggingface_hub
13 -from transformers import AutoTokenizer, PreTrainedTokenizer, PreTrainedTokenizerFast
14 +from transformers import AutoTokenizer, PreTrainedTokenizerBase
15 from typing_extensions import assert_never
16
17 from vllm import envs
18 from vllm.logger import init_logger
18 -from vllm.transformers_utils.config import get_sentence_transformer_tokenizer_config
19 -from vllm.transformers_utils.gguf_utils import get_gguf_file_path_from_hf
20 -from vllm.transformers_utils.repo_utils import list_filtered_repo_files
21 -from vllm.transformers_utils.tokenizers import MistralTokenizer
22 -from vllm.transformers_utils.utils import (
23 - check_gguf_file,
24 - is_gguf,
25 - is_remote_gguf,
26 - split_remote_gguf,
27 -)
19 +from vllm.tokenizers import MistralTokenizer, TokenizerLike, TokenizerRegistry
20 +
21 +from .config import get_sentence_transformer_tokenizer_config
22 +from .gguf_utils import get_gguf_file_path_from_hf
23 +from .repo_utils import list_filtered_repo_files
24 +from .utils import check_gguf_file, is_gguf, is_remote_gguf, split_remote_gguf
25
26 if TYPE_CHECKING:
27 from vllm.config import ModelConfig
31 - from vllm.transformers_utils.tokenizer_base import TokenizerBase
32 -else:
33 - ModelConfig = Any
34 - TokenizerBase = Any
28 +
29
30 logger = init_logger(__name__)
31
38 -AnyTokenizer: TypeAlias = PreTrainedTokenizer | PreTrainedTokenizerFast | TokenizerBase
32 +
33 +def __getattr__(name: str):
34 + if name == "AnyTokenizer":
35 + warnings.warn(
36 + "`vllm.transformers_utils.tokenizer.AnyTokenizer` has been moved to "
37 + "`vllm.tokenizers.TokenizerLike`. "
38 + "The old name will be removed in v0.13.",
39 + DeprecationWarning,
40 + stacklevel=2,
41 + )
42 +
43 + return TokenizerLike
44 +
45 + raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
46
47
48 def decode_tokens(
42 - tokenizer: AnyTokenizer,
49 + tokenizer: TokenizerLike,
50 token_ids: list[int],
51 *,
52 skip_special_tokens: bool | None = None,
@@ -58,7 +65,7 @@ def decode_tokens(
65
66
67 def encode_tokens(
61 - tokenizer: AnyTokenizer,
68 + tokenizer: TokenizerLike,
69 text: str,
70 *,
71 truncation: bool | None = None,
@@ -86,7 +93,7 @@ def encode_tokens(
93 return tokenizer.encode(text, **kw_args)
94
95
89 -def get_cached_tokenizer(tokenizer: AnyTokenizer) -> AnyTokenizer:
96 +def get_cached_tokenizer(tokenizer: TokenizerLike) -> TokenizerLike:
97 """
98 By default, transformers will recompute multiple tokenizer properties
99 each time they are called, leading to a significant slowdown.
@@ -144,7 +151,7 @@ def get_tokenizer(
151 revision: str | None = None,
152 download_dir: str | None = None,
153 **kwargs,
147 -) -> AnyTokenizer:
154 +) -> TokenizerLike:
155 """Gets a tokenizer for the given model name via HuggingFace or ModelScope."""
156 if envs.VLLM_USE_MODELSCOPE:
157 # download model from ModelScope hub,
@@ -206,15 +213,13 @@ def get_tokenizer(
213 if len(files_list) > 0:
214 tokenizer_mode = "mistral"
215
209 - tokenizer: AnyTokenizer
216 + tokenizer: TokenizerLike
217 if tokenizer_mode == "mistral":
218 logger.debug_once(f"Loading MistralTokenizer from {tokenizer_name}")
219 tokenizer = MistralTokenizer.from_pretrained(
220 str(tokenizer_name), revision=revision
221 )
222 elif tokenizer_mode == "custom":
216 - from vllm.transformers_utils.tokenizer_base import TokenizerRegistry
217 -
223 logger.debug_once(f"Loading CustomTokenizer from {tokenizer_name}")
224 tokenizer = TokenizerRegistry.get_tokenizer(
225 str(tokenizer_name),
@@ -260,12 +265,13 @@ def get_tokenizer(
265 if isinstance(encoder_config, dict) and encoder_config.get(
266 "do_lower_case", False
267 ):
268 + assert isinstance(tokenizer, PreTrainedTokenizerBase)
269 special_tokens_map = {
270 k: v.lower() for k, v in tokenizer.special_tokens_map.items()
271 }
272 tokenizer.add_special_tokens(special_tokens_map)
273
268 - if not isinstance(tokenizer, PreTrainedTokenizerFast):
274 + if not tokenizer.is_fast:
275 logger.warning(
276 "Using a slow tokenizer. This might cause a significant "
277 "slowdown. Consider using a fast tokenizer instead."
@@ -279,7 +285,7 @@ cached_get_tokenizer = lru_cache(get_tokenizer)
285
286
287 def cached_tokenizer_from_config(
282 - model_config: ModelConfig,
288 + model_config: "ModelConfig",
289 **kwargs: Any,
290 ):
291 return cached_get_tokenizer(
@@ -291,7 +297,7 @@ def cached_tokenizer_from_config(
297 )
298
299
294 -def init_tokenizer_from_configs(model_config: ModelConfig):
300 +def init_tokenizer_from_configs(model_config: "ModelConfig"):
301 runner_type = model_config.runner_type
302 if runner_type == "generate" or runner_type == "draft":
303 truncation_side = "left"
vllm/transformers_utils/tokenizer_base.py
+23 -140
@@ -1,150 +1,33 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 -import importlib
5 -from abc import ABC, abstractmethod
6 -from typing import TYPE_CHECKING, Any
4 +import warnings
5
8 -if TYPE_CHECKING:
9 - from vllm.entrypoints.chat_utils import ChatCompletionMessageParam
6
7 +def __getattr__(name: str):
8 + if name == "TokenizerBase":
9 + from vllm.tokenizers import TokenizerLike
10
12 -class TokenizerBase(ABC):
13 - @property
14 - @abstractmethod
15 - def all_special_tokens(self) -> list[str]:
16 - raise NotImplementedError()
11 + warnings.warn(
12 + "`vllm.transformers_utils.tokenizer_base.TokenizerBase` has been "
13 + "moved to `vllm.tokenizers.TokenizerLike`. "
14 + "The old name will be removed in v0.13.",
15 + DeprecationWarning,
16 + stacklevel=2,
17 + )
18
18 - @property
19 - @abstractmethod
20 - def all_special_ids(self) -> list[int]:
21 - raise NotImplementedError()
19 + return TokenizerLike
20 + if name == "TokenizerRegistry":
21 + from vllm.tokenizers import TokenizerRegistry
22
23 - @property
24 - @abstractmethod
25 - def bos_token_id(self) -> int:
26 - raise NotImplementedError()
23 + warnings.warn(
24 + "`vllm.transformers_utils.tokenizer_base.TokenizerRegistry` has been "
25 + "moved to `vllm.tokenizers.TokenizerRegistry`. "
26 + "The old name will be removed in v0.13.",
27 + DeprecationWarning,
28 + stacklevel=2,
29 + )
30
28 - @property
29 - @abstractmethod
30 - def eos_token_id(self) -> int:
31 - raise NotImplementedError()
31 + return TokenizerRegistry
32
33 - @property
34 - @abstractmethod
35 - def sep_token(self) -> str:
36 - raise NotImplementedError()
37 -
38 - @property
39 - @abstractmethod
40 - def pad_token(self) -> str:
41 - raise NotImplementedError()
42 -
43 - @property
44 - @abstractmethod
45 - def is_fast(self) -> bool:
46 - raise NotImplementedError()
47 -
48 - @property
49 - @abstractmethod
50 - def vocab_size(self) -> int:
51 - raise NotImplementedError()
52 -
53 - @property
54 - @abstractmethod
55 - def max_token_id(self) -> int:
56 - raise NotImplementedError()
57 -
58 - @property
59 - @abstractmethod
60 - def truncation_side(self) -> str:
61 - raise NotImplementedError()
62 -
63 - def __len__(self) -> int:
64 - return self.vocab_size
65 -
66 - @abstractmethod
67 - def __call__(
68 - self,
69 - text: str | list[str] | list[int],
70 - text_pair: str | None = None,
71 - add_special_tokens: bool = False,
72 - truncation: bool = False,
73 - max_length: int | None = None,
74 - ):
75 - raise NotImplementedError()
76 -
77 - @abstractmethod
78 - def get_vocab(self) -> dict[str, int]:
79 - raise NotImplementedError()
80 -
81 - @abstractmethod
82 - def get_added_vocab(self) -> dict[str, int]:
83 - raise NotImplementedError()
84 -
85 - @abstractmethod
86 - def encode_one(
87 - self,
88 - text: str,
89 - truncation: bool = False,
90 - max_length: int | None = None,
91 - ) -> list[int]:
92 - raise NotImplementedError()
93 -
94 - @abstractmethod
95 - def encode(
96 - self,
97 - text: str,
98 - truncation: bool | None = None,
99 - max_length: int | None = None,
100 - add_special_tokens: bool | None = None,
101 - ) -> list[int]:
102 - raise NotImplementedError()
103 -
104 - @abstractmethod
105 - def apply_chat_template(
106 - self,
107 - messages: list["ChatCompletionMessageParam"],
108 - tools: list[dict[str, Any]] | None = None,
109 - **kwargs,
110 - ) -> list[int]:
111 - raise NotImplementedError()
112 -
113 - @abstractmethod
114 - def convert_tokens_to_string(self, tokens: list[str]) -> str:
115 - raise NotImplementedError()
116 -
117 - @abstractmethod
118 - def decode(self, ids: list[int] | int, skip_special_tokens: bool = True) -> str:
119 - raise NotImplementedError()
120 -
121 - @abstractmethod
122 - def convert_ids_to_tokens(
123 - self,
124 - ids: list[int],
125 - skip_special_tokens: bool = True,
126 - ) -> list[str]:
127 - raise NotImplementedError()
128 -
129 -
130 -class TokenizerRegistry:
131 - # Tokenizer name -> (tokenizer module, tokenizer class)
132 - REGISTRY: dict[str, tuple[str, str]] = {}
133 -
134 - @staticmethod
135 - def register(name: str, module: str, class_name: str) -> None:
136 - TokenizerRegistry.REGISTRY[name] = (module, class_name)
137 -
138 - @staticmethod
139 - def get_tokenizer(
140 - tokenizer_name: str,
141 - *args,
142 - **kwargs,
143 - ) -> TokenizerBase:
144 - tokenizer_cls = TokenizerRegistry.REGISTRY.get(tokenizer_name)
145 - if tokenizer_cls is None:
146 - raise ValueError(f"Tokenizer {tokenizer_name} not found.")
147 -
148 - tokenizer_module = importlib.import_module(tokenizer_cls[0])
149 - class_ = getattr(tokenizer_module, tokenizer_cls[1])
150 - return class_.from_pretrained(*args, **kwargs)
33 + raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
vllm/transformers_utils/tokenizers/__init__.py deleted
-16
@@ -1,16 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -
4 -from .mistral import (
5 - MistralTokenizer,
6 - maybe_serialize_tool_calls,
7 - truncate_tool_call_ids,
8 - validate_request_params,
9 -)
10 -
11 -__all__ = [
12 - "MistralTokenizer",
13 - "maybe_serialize_tool_calls",
14 - "truncate_tool_call_ids",
15 - "validate_request_params",
16 -]
vllm/v1/engine/async_llm.py
+9 -7
@@ -26,9 +26,10 @@ from vllm.plugins.io_processors import get_io_processor
26 from vllm.pooling_params import PoolingParams
27 from vllm.sampling_params import SamplingParams
28 from vllm.tasks import SupportedTask
29 +from vllm.tokenizers import TokenizerLike
30 from vllm.tracing import init_tracer
31 from vllm.transformers_utils.config import maybe_register_config_serialize_by_value
31 -from vllm.transformers_utils.tokenizer import AnyTokenizer, init_tokenizer_from_configs
32 +from vllm.transformers_utils.tokenizer import init_tokenizer_from_configs
33 from vllm.usage.usage_lib import UsageContext
34 from vllm.utils.async_utils import cancel_task_threadsafe
35 from vllm.utils.collection_utils import as_list
@@ -120,9 +121,10 @@ class AsyncLLM(EngineClient):
121 )
122
123 # OutputProcessor (converts EngineCoreOutputs --> RequestOutput).
123 - stream_interval = self.vllm_config.scheduler_config.stream_interval
124 self.output_processor = OutputProcessor(
125 - self.tokenizer, log_stats=self.log_stats, stream_interval=stream_interval
125 + self.tokenizer,
126 + log_stats=self.log_stats,
127 + stream_interval=self.vllm_config.scheduler_config.stream_interval,
128 )
129 endpoint = self.observability_config.otlp_traces_endpoint
130 if endpoint is not None:
@@ -703,17 +705,17 @@ class AsyncLLM(EngineClient):
705 raise EngineGenerateError() from e
706
707 @property
706 - def tokenizer(self) -> AnyTokenizer | None:
708 + def tokenizer(self) -> TokenizerLike | None:
709 return self.input_processor.tokenizer
710
711 @tokenizer.setter
710 - def tokenizer(self, tokenizer: AnyTokenizer | None) -> None:
712 + def tokenizer(self, tokenizer: TokenizerLike | None) -> None:
713 self.input_processor.tokenizer = tokenizer
714
713 - async def get_tokenizer(self) -> AnyTokenizer:
715 + async def get_tokenizer(self) -> TokenizerLike:
716 if self.tokenizer is None:
717 raise ValueError(
716 - "Unable to get tokenizer because skip_tokenizer_init is True"
718 + "Unable to get tokenizer because `skip_tokenizer_init=True`"
719 )
720
721 return self.tokenizer
vllm/v1/engine/detokenizer.py
+3 -3
@@ -10,7 +10,7 @@ from transformers import PreTrainedTokenizerFast
10
11 from vllm.logger import init_logger
12 from vllm.transformers_utils.detokenizer_utils import (
13 - AnyTokenizer,
13 + TokenizerLike,
14 convert_prompt_ids_to_tokens,
15 detokenize_incrementally,
16 )
@@ -45,7 +45,7 @@ class IncrementalDetokenizer:
45 @classmethod
46 def from_new_request(
47 cls,
48 - tokenizer: AnyTokenizer | None,
48 + tokenizer: TokenizerLike | None,
49 request: EngineCoreRequest,
50 ) -> "IncrementalDetokenizer":
51 assert request.sampling_params is not None
@@ -256,7 +256,7 @@ class FastIncrementalDetokenizer(BaseIncrementalDetokenizer):
256
257
258 class SlowIncrementalDetokenizer(BaseIncrementalDetokenizer):
259 - def __init__(self, tokenizer: AnyTokenizer, request: EngineCoreRequest):
259 + def __init__(self, tokenizer: TokenizerLike, request: EngineCoreRequest):
260 super().__init__(request)
261
262 self.tokenizer = tokenizer
vllm/v1/engine/input_processor.py
+4 -5
@@ -19,8 +19,7 @@ from vllm.multimodal.processing import EncDecMultiModalProcessor
19 from vllm.multimodal.utils import argsort_mm_positions
20 from vllm.pooling_params import PoolingParams
21 from vllm.sampling_params import SamplingParams
22 -from vllm.transformers_utils.tokenizer import AnyTokenizer
23 -from vllm.transformers_utils.tokenizers.mistral import MistralTokenizer
22 +from vllm.tokenizers import MistralTokenizer, TokenizerLike
23 from vllm.utils import length_from_prompt_token_ids_or_embeds
24 from vllm.v1.engine import EngineCoreRequest
25 from vllm.v1.metrics.stats import MultiModalCacheStats
@@ -40,7 +39,7 @@ class InputProcessor:
39 def __init__(
40 self,
41 vllm_config: VllmConfig,
43 - tokenizer: AnyTokenizer | None,
42 + tokenizer: TokenizerLike | None,
43 mm_registry: MultiModalRegistry = MULTIMODAL_REGISTRY,
44 ) -> None:
45 self.vllm_config = vllm_config
@@ -62,11 +61,11 @@ class InputProcessor:
61 )
62
63 @property
65 - def tokenizer(self) -> AnyTokenizer | None:
64 + def tokenizer(self) -> TokenizerLike | None:
65 return self.input_preprocessor.tokenizer
66
67 @tokenizer.setter
69 - def tokenizer(self, tokenizer: AnyTokenizer | None) -> None:
68 + def tokenizer(self, tokenizer: TokenizerLike | None) -> None:
69 self.input_preprocessor.tokenizer = tokenizer
70
71 def _validate_logprobs(
vllm/v1/engine/llm_engine.py
+9 -7
@@ -23,8 +23,9 @@ from vllm.plugins.io_processors import get_io_processor
23 from vllm.pooling_params import PoolingParams
24 from vllm.sampling_params import SamplingParams
25 from vllm.tasks import SupportedTask
26 +from vllm.tokenizers import TokenizerLike
27 from vllm.tracing import init_tracer
27 -from vllm.transformers_utils.tokenizer import AnyTokenizer, init_tokenizer_from_configs
28 +from vllm.transformers_utils.tokenizer import init_tokenizer_from_configs
29 from vllm.usage.usage_lib import UsageContext
30 from vllm.v1.engine import EngineCoreRequest
31 from vllm.v1.engine.core_client import EngineCoreClient
@@ -95,9 +96,10 @@ class LLMEngine:
96 )
97
98 # OutputProcessor (convert EngineCoreOutputs --> RequestOutput).
98 - stream_interval = self.vllm_config.scheduler_config.stream_interval
99 self.output_processor = OutputProcessor(
100 - self.tokenizer, log_stats=self.log_stats, stream_interval=stream_interval
100 + self.tokenizer,
101 + log_stats=self.log_stats,
102 + stream_interval=self.vllm_config.scheduler_config.stream_interval,
103 )
104 endpoint = self.observability_config.otlp_traces_endpoint
105 if endpoint is not None:
@@ -350,17 +352,17 @@ class LLMEngine:
352 return get_metrics_snapshot()
353
354 @property
353 - def tokenizer(self) -> AnyTokenizer | None:
355 + def tokenizer(self) -> TokenizerLike | None:
356 return self.input_processor.tokenizer
357
358 @tokenizer.setter
357 - def tokenizer(self, tokenizer: AnyTokenizer | None) -> None:
359 + def tokenizer(self, tokenizer: TokenizerLike | None) -> None:
360 self.input_processor.tokenizer = tokenizer
361
360 - def get_tokenizer(self) -> AnyTokenizer:
362 + def get_tokenizer(self) -> TokenizerLike:
363 if self.tokenizer is None:
364 raise ValueError(
363 - "Unable to get tokenizer because skip_tokenizer_init is True"
365 + "Unable to get tokenizer because `skip_tokenizer_init=True`"
366 )
367
368 return self.tokenizer
vllm/v1/engine/logprobs.py
+3 -3
@@ -13,7 +13,7 @@ from vllm.logprobs import (
13 create_sample_logprobs,
14 )
15 from vllm.transformers_utils.detokenizer_utils import (
16 - AnyTokenizer,
16 + TokenizerLike,
17 convert_ids_list_to_tokens,
18 )
19 from vllm.v1.engine import EngineCoreOutput, EngineCoreRequest
@@ -28,7 +28,7 @@ NONES = itertools.repeat(None)
28 class LogprobsProcessor:
29 # Tokenizer for this request,
30 # None if detokenization is disabled.
31 - tokenizer: AnyTokenizer | None
31 + tokenizer: TokenizerLike | None
32
33 # Logprobs for this request
34 logprobs: SampleLogprobs | None
@@ -40,7 +40,7 @@ class LogprobsProcessor:
40 @classmethod
41 def from_new_request(
42 cls,
43 - tokenizer: AnyTokenizer | None,
43 + tokenizer: TokenizerLike | None,
44 request: EngineCoreRequest,
45 ) -> "LogprobsProcessor":
46 sampling_params = request.sampling_params
vllm/v1/engine/output_processor.py
+6 -3
@@ -15,8 +15,8 @@ from vllm.outputs import (
15 RequestOutput,
16 )
17 from vllm.sampling_params import RequestOutputKind
18 +from vllm.tokenizers import TokenizerLike
19 from vllm.tracing import SpanAttributes, SpanKind, Tracer, extract_trace_context
19 -from vllm.transformers_utils.tokenizer import AnyTokenizer
20 from vllm.utils import length_from_prompt_token_ids_or_embeds
21 from vllm.v1.engine import EngineCoreOutput, EngineCoreRequest, FinishReason
22 from vllm.v1.engine.detokenizer import IncrementalDetokenizer
@@ -139,7 +139,7 @@ class RequestState:
139 @classmethod
140 def from_new_request(
141 cls,
142 - tokenizer: AnyTokenizer,
142 + tokenizer: TokenizerLike | None,
143 request: EngineCoreRequest,
144 prompt: str | None,
145 parent_req: ParentRequest | None,
@@ -341,7 +341,10 @@ class OutputProcessor:
341 """Process EngineCoreOutputs into RequestOutputs."""
342
343 def __init__(
344 - self, tokenizer: AnyTokenizer, log_stats: bool, stream_interval: int = 1
344 + self,
345 + tokenizer: TokenizerLike | None,
346 + log_stats: bool,
347 + stream_interval: int = 1,
348 ):
349 self.log_stats = log_stats
350 self.tokenizer = tokenizer
vllm/v1/structured_output/backend_types.py
+3 -3
@@ -10,10 +10,10 @@ if TYPE_CHECKING:
10 import torch
11
12 from vllm.config import VllmConfig
13 - from vllm.transformers_utils.tokenizer import AnyTokenizer
13 + from vllm.tokenizers import TokenizerLike
14 else:
15 VllmConfig = object
16 - AnyTokenizer = object
16 + TokenizerLike = object
17
18
19 class StructuredOutputOptions(enum.Enum):
@@ -100,7 +100,7 @@ class StructuredOutputBackend(ABC):
100 """Engine-level backend for structured output requests."""
101
102 vllm_config: VllmConfig
103 - tokenizer: AnyTokenizer
103 + tokenizer: TokenizerLike
104 vocab_size: int
105
106 @abstractmethod
vllm/v1/structured_output/backend_xgrammar.py
+1 -1
@@ -10,7 +10,7 @@ import torch
10 import vllm.envs
11 from vllm.logger import init_logger
12 from vllm.sampling_params import SamplingParams
13 -from vllm.transformers_utils.tokenizers.mistral import MistralTokenizer
13 +from vllm.tokenizers import MistralTokenizer
14 from vllm.utils.import_utils import LazyLoader
15 from vllm.v1.structured_output.backend_types import (
16 StructuredOutputBackend,
vllm/v1/structured_output/utils.py
+5 -5
@@ -24,7 +24,7 @@ if TYPE_CHECKING:
24 import transformers.models.gpt2.tokenization_gpt2 as tokenization_gpt2
25 import xgrammar as xgr
26
27 - from vllm.transformers_utils.tokenizer import AnyTokenizer
27 + from vllm.tokenizers import TokenizerLike
28 from vllm.v1.worker.gpu_input_batch import InputBatch
29 else:
30 xgr = LazyLoader("xgr", globals(), "xgrammar")
@@ -36,7 +36,7 @@ else:
36 "transformers.models.gpt2.tokenization_gpt2",
37 )
38
39 - AnyTokenizer = object
39 + TokenizerLike = object
40 SchedulerOutput = object
41 InputBatch = object
42
@@ -195,7 +195,7 @@ re_replacement_seq = re.compile(r"^.{0,6}�+.{0,6}$")
195
196
197 def _reduced_vocabulary(
198 - tokenizer: AnyTokenizer,
198 + tokenizer: TokenizerLike,
199 eos_token_id: int,
200 ) -> dict[bytes, list[int]]:
201 """Create a map from vocabulary tokens to lists of equivalent token ids.
@@ -222,7 +222,7 @@ def _reduced_vocabulary(
222 vocabulary: dict[bytes, list[int]] = {}
223 empty_token_ids: list[int] = []
224 for token, token_idx in tokenizer.get_vocab().items():
225 - if token in tokenizer.all_special_tokens: # type: ignore
225 + if token in tokenizer.all_special_tokens:
226 continue
227
228 token_str = convert_token_to_string(token)
@@ -261,7 +261,7 @@ def _reduced_vocabulary(
261 return vocabulary
262
263
264 -def get_outlines_vocabulary(tokenizer: AnyTokenizer) -> oc.Vocabulary:
264 +def get_outlines_vocabulary(tokenizer: TokenizerLike) -> oc.Vocabulary:
265 """Get the `Vocabulary` object for a given tokenizer."""
266 if hasattr(tokenizer, "_outlines_vocabulary"):
267 return tokenizer._outlines_vocabulary # type: ignore