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 14, 05:30 UTC
fix: allow HuggingFace standard chat template params via **kwargs (#27622)
Signed-off-by: wangln19 <wanglinian@dev.wanglinian.msh-dev.svc.cluster.local> Signed-off-by: wangln19 <96399074+wangln19@users.noreply.github.com> Co-authored-by: wangln19 <wanglinian@dev.wanglinian.msh-dev.svc.cluster.local> Co-authored-by: Cyrus Leung <cyrus.tl.leung@gmail.com>
wangln19 committed
Oct 28, 2025 at 21:12 UTC
446912d1cb94247815ee9a62a4f2f18628358a84
2 files changed
+57
-1
tests/entrypoints/test_chat_utils.py
+33
@@ -1882,6 +1882,39 @@ def test_resolve_hf_chat_template_kwargs(sample_json_schema, model, expected_kwa
1882
)
1883
assert set(resolved_chat_template_kwargs.keys()) == expected_kwargs
1884
1885
+ # Additional test: Verify HF base parameters work with **kwargs tokenizers
1886
+ # This validates the fix for tokenizers like Kimi K2 that use **kwargs
1887
+ # to receive standard HuggingFace parameters instead of declaring them explicitly
1888
+ from vllm.entrypoints.chat_utils import _get_hf_base_chat_template_params
1889
+
1890
+ hf_base_params = _get_hf_base_chat_template_params()
1891
+ # Verify common HF parameters are in the base class
1892
+ assert {"add_generation_prompt", "tools", "continue_final_message"}.issubset(
1893
+ hf_base_params
1894
+ ), f"Expected HF base params not found in {hf_base_params}"
1895
+
1896
+ # Test with a mock tokenizer that uses **kwargs (like Kimi K2)
1897
+ class MockTokenizerWithKwargs:
1898
+ def apply_chat_template(self, conversation, **kwargs):
1899
+ return "mocked_output"
1900
+
1901
+ mock_tokenizer = MockTokenizerWithKwargs()
1902
+ mock_kwargs = {
1903
+ "add_generation_prompt": True,
1904
+ "tools": tools,
1905
+ "continue_final_message": False,
1906
+ "unknown_param": "should_be_filtered",
1907
+ }
1908
+ resolved_mock = resolve_chat_template_kwargs(
1909
+ mock_tokenizer, chat_template, mock_kwargs, raise_on_unexpected=False
1910
+ )
1911
+ # HF base params should pass through even with **kwargs tokenizer
1912
+ assert "add_generation_prompt" in resolved_mock
1913
+ assert "tools" in resolved_mock
1914
+ assert "continue_final_message" in resolved_mock
1915
+ # Unknown params should be filtered out
1916
+ assert "unknown_param" not in resolved_mock
1917
+
1918
1919
# NOTE: Qwen2-Audio default chat template is specially defined inside
1920
# processor class instead of using `tokenizer_config.json`
vllm/entrypoints/chat_utils.py
+24
-1
@@ -2,6 +2,7 @@
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
import asyncio
5
+import inspect
6
import json
7
from abc import ABC, abstractmethod
8
from collections import Counter, defaultdict, deque
@@ -1515,6 +1516,24 @@ def _resolve_chat_template_kwargs(
1516
_cached_resolve_chat_template_kwargs = lru_cache(_resolve_chat_template_kwargs)
1517
1518
1519
+@lru_cache
1520
+def _get_hf_base_chat_template_params() -> frozenset[str]:
1521
+ # Get standard parameters from HuggingFace's base tokenizer class.
1522
+ # This dynamically extracts parameters from PreTrainedTokenizer's
1523
+ # apply_chat_template method, ensuring compatibility with tokenizers
1524
+ # that use **kwargs to receive standard parameters.
1525
+
1526
+ # Read signature from HF's base class - the single source of truth
1527
+ base_sig = inspect.signature(PreTrainedTokenizer.apply_chat_template)
1528
+ # Exclude VAR_KEYWORD (**kwargs) and VAR_POSITIONAL (*args) placeholders
1529
+ return frozenset(
1530
+ p.name
1531
+ for p in base_sig.parameters.values()
1532
+ if p.kind
1533
+ not in (inspect.Parameter.VAR_KEYWORD, inspect.Parameter.VAR_POSITIONAL)
1534
+ )
1535
+
1536
+
1537
def resolve_chat_template_kwargs(
1538
tokenizer: PreTrainedTokenizer | PreTrainedTokenizerFast,
1539
chat_template: str,
@@ -1538,7 +1557,11 @@ def resolve_chat_template_kwargs(
1557
if supports_kw(tokenizer.apply_chat_template, k, allow_var_kwargs=False)
1558
}
1559
template_vars = _cached_resolve_chat_template_kwargs(chat_template)
1541
- accept_vars = (fn_kw | template_vars) - unexpected_vars
1560
+
1561
+ # Allow standard HF parameters even if tokenizer uses **kwargs to receive them
1562
+ hf_base_params = _get_hf_base_chat_template_params()
1563
+
1564
+ accept_vars = (fn_kw | template_vars | hf_base_params) - unexpected_vars
1565
return {k: v for k, v in chat_template_kwargs.items() if k in accept_vars}
1566
1567