From 0ad5652a523d7bfe191a08b97ca45ead585b1897 Mon Sep 17 00:00:00 2001 From: Pratham Shirbhate Date: Tue, 1 Sep 2026 23:47:54 +0530 Subject: [PATCH] [Bugfix][Frontend] Restore the chat template content format mismatch warning (#54622) Signed-off-by: Pratham Shirbhate Co-authored-by: Cyrus Leung --- .../chat_completion/test_serving_chat.py | 2 + vllm/renderers/hf.py | 82 +++++++++++-------- 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/tests/entrypoints/openai/chat_completion/test_serving_chat.py b/tests/entrypoints/openai/chat_completion/test_serving_chat.py index b7b02efd12..f750830296 100644 --- a/tests/entrypoints/openai/chat_completion/test_serving_chat.py +++ b/tests/entrypoints/openai/chat_completion/test_serving_chat.py @@ -539,6 +539,8 @@ class MockModelConfig: trust_remote_code = False tokenizer_mode = "auto" max_model_len = 100 + revision = None + code_revision = None tokenizer_revision = None multimodal_config = MultiModalConfig() hf_config = MockHFConfig() diff --git a/vllm/renderers/hf.py b/vllm/renderers/hf.py index 54625af820..16906bb1da 100644 --- a/vllm/renderers/hf.py +++ b/vllm/renderers/hf.py @@ -509,6 +509,22 @@ def _consolidate_system_messages( return [merged, *non_system] +_CONTENT_FORMATS_MAXSIZE = 32 +_CONTENT_FORMATS = dict[ + tuple[str | None, bool, str, str | None, str | None, bool], + "ChatTemplateContentFormat", +]() +""" +Used in `_resolve_chat_template_content_format` to avoid resolving and parsing +the chat template on every request. + +`lru_cache` cannot be used because `tools` is a list and `ModelConfig` defines +`__eq__` without `__hash__`, so the key holds the fields `resolve_chat_template` +selects the template by. Only the presence of `tools` is part of it: it decides +whether the processor template is tried, and its contents never reach the AST. +""" + + def _resolve_chat_template_content_format( chat_template: str | None, tools: list[dict[str, Any]] | None, @@ -516,6 +532,17 @@ def _resolve_chat_template_content_format( *, model_config: ModelConfig, ) -> ChatTemplateContentFormat: + cache_key = ( + chat_template, + tools is None, + tokenizer.name_or_path, + model_config.revision, + model_config.code_revision, + model_config.trust_remote_code, + ) + if (cached_format := _CONTENT_FORMATS.get(cache_key)) is not None: + return cached_format + resolved_chat_template = resolve_chat_template( tokenizer, chat_template=chat_template, @@ -535,33 +562,14 @@ def _resolve_chat_template_content_format( else _detect_content_format(jinja_text, default="string") ) + # Requests may carry their own chat template, so bound the cache. + if len(_CONTENT_FORMATS) >= _CONTENT_FORMATS_MAXSIZE: + _CONTENT_FORMATS.clear() + _CONTENT_FORMATS[cache_key] = detected_format + return detected_format -@lru_cache -def _log_chat_template_content_format( - chat_template: str | None, # For caching purposes - given_format: ChatTemplateContentFormatOption, - detected_format: ChatTemplateContentFormatOption, -): - logger.info( - "Detected the chat template content format to be '%s'. " - "You can set `--chat-template-content-format` to override this.", - detected_format, - ) - - if given_format != "auto" and given_format != detected_format: - logger.warning( - "You specified `--chat-template-content-format %s` " - "which is different from the detected format '%s'. " - "If our automatic detection is incorrect, please consider " - "opening a GitHub issue so that we can improve it: " - "https://github.com/vllm-project/vllm/issues/new/choose", - given_format, - detected_format, - ) - - def resolve_chat_template_content_format( chat_template: str | None, tools: list[dict[str, Any]] | None, @@ -570,9 +578,6 @@ def resolve_chat_template_content_format( *, model_config: ModelConfig, ) -> ChatTemplateContentFormat: - if given_format != "auto": - return given_format - detected_format = _resolve_chat_template_content_format( chat_template, tools, @@ -580,13 +585,24 @@ def resolve_chat_template_content_format( model_config=model_config, ) - _log_chat_template_content_format( - chat_template, - given_format=given_format, - detected_format=detected_format, - ) + if given_format == "auto": + logger.info_once( + "Detected the chat template content format to be '%s'. " + "You can set `--chat-template-content-format` to override this.", + detected_format, + ) + elif given_format != detected_format: + logger.warning_once( + "You specified `--chat-template-content-format %s` " + "which is different from the detected format '%s'. " + "If our automatic detection is incorrect, please consider " + "opening a GitHub issue so that we can improve it: " + "https://github.com/vllm-project/vllm/issues/new/choose", + given_format, + detected_format, + ) - return detected_format + return detected_format if given_format == "auto" else given_format # adapted from https://github.com/huggingface/transformers/blob/v4.56.2/src/transformers/utils/chat_template_utils.py#L398-L412