[perf] skip add_special_tokens=False kwarg on chat-template tokenize for slow tokenizers (#25953)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khoa Pham
2026-05-21 22:45:54 -07:00
committed by GitHub
co-authored by Claude Opus 4.7
parent acb8310183
commit f829cafa3e
@@ -181,6 +181,18 @@ class OpenAIServingChat(OpenAIServingBase):
# Per-request response parser for custom decoding (set by _encode_messages)
self._response_parser: Optional[ResponseParserProtocol] = None
# Probe whether ``encode("")`` returns specials. If it does, we must
# keep ``add_special_tokens=False`` at the chat-template encode site
# to avoid double BOS; otherwise the kwarg is a no-op and dropping it
# lets slow tokenizers (e.g. Kimi's TikTokenTokenizer) stay on the
# fast internal path.
try:
self._tokenizer_auto_adds_specials = (
len(self.tokenizer_manager.tokenizer.encode("")) > 0
)
except Exception:
self._tokenizer_auto_adds_specials = True
def _handle_last_assistant_message(
self,
messages: List[Dict[str, Any]],
@@ -729,15 +741,28 @@ class OpenAIServingChat(OpenAIServingBase):
if request.chat_template_kwargs:
extra_template_kwargs.update(request.chat_template_kwargs)
# Split apply_chat_template(tokenize=True) into render + encode so we
# can skip add_special_tokens=False on tokenizers that don't auto-add
# specials (Kimi-like, OpenAI-chat analogue of #25265). Chat
# templates already include role/special tokens, so the encode must
# avoid double BOS on tokenizers that would add it.
encode_kwargs = (
{"add_special_tokens": False}
if self._tokenizer_auto_adds_specials
else {}
)
try:
prompt_ids = self.tokenizer_manager.tokenizer.apply_chat_template(
rendered_prompt = self.tokenizer_manager.tokenizer.apply_chat_template(
openai_compatible_messages,
tokenize=True,
tokenize=False,
add_generation_prompt=True,
tools=tools,
return_dict=False,
**extra_template_kwargs,
)
prompt_ids = self.tokenizer_manager.tokenizer.encode(
rendered_prompt, **encode_kwargs
)
except Exception as e:
# If the first attempt fails, try with flat function-only format.
# Some templates (e.g. Mistral) expect tools without the OpenAI wrapper.
@@ -747,13 +772,18 @@ class OpenAIServingChat(OpenAIServingBase):
else None
)
try:
prompt_ids = self.tokenizer_manager.tokenizer.apply_chat_template(
openai_compatible_messages,
tokenize=True,
add_generation_prompt=True,
tools=tools,
return_dict=False,
**extra_template_kwargs,
rendered_prompt = (
self.tokenizer_manager.tokenizer.apply_chat_template(
openai_compatible_messages,
tokenize=False,
add_generation_prompt=True,
tools=tools,
return_dict=False,
**extra_template_kwargs,
)
)
prompt_ids = self.tokenizer_manager.tokenizer.encode(
rendered_prompt, **encode_kwargs
)
except jinja2.TemplateError as template_error:
# Template errors (e.g., from raise_exception in Jinja templates)