Repository navigation
[Perf] openai: Tokenize dsv4 / dsv41 / dsv32 prompts with parallel_prompt_encode - #45410
Closed
kano-zheng wants to merge 1 commit into
Closed
kano-zheng wants to merge 1 commit into
kano-zheng wants to merge 1 commit into
Conversation
…ompt_encode The native DeepSeek encoders render the whole conversation to one string and tokenized it with a single tokenizer.encode call on the HTTP event loop, while the Jinja path already goes through parallel_prompt_encode. Route the dsv4, dsv41 and dsv32 branches through the same helper. Below SGLANG_PARALLEL_PROMPT_ENCODE_MIN_CHARS it still calls tokenizer.encode. A 947K-token DeepSeek-V4.1 agent prompt: 1.92 s -> 0.21 s, identical ids. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Hi @kano-zheng, may I know if there is a specific reason why this PR got closed? Thanks |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
parallel_prompt_encode(enabled by default viaSGLANG_PARALLEL_PROMPT_ENCODE) only covers the Jinja chat-templatepath in
OpenAIServingChat. The three native encoders render the whole conversation to one string and then callself.tokenizer_manager.tokenizer.encode(real_input)in a single call, on the HTTP event loop. With DeepSeek-V4.1-Flashserving coding agents (Claude Code / Codex / opencode), prompts routinely reach several hundred thousand tokens, so that
one call is the largest single cost before the request reaches the scheduler, and it delays every other request handled
by that frontend process (first tokens and streamed chunks alike).
Measured in the 2026-10-20 nightly image (
lmsysorg/sglangnightly-dev-20261020-ab580b2e) with thedeepseek-ai/DeepSeek-V4.1-Flash-1017tokenizer, on a real agent-shaped prompt rendered byencoding_dsv41(system + tools + 990 tool-call / tool-result turns):
tokenizer.encodeparallel_prompt_encodeparallel_prompt_encode's plan accepts the DeepSeek V4 tokenizer (no lstrip / rstrip / single_word added tokens, notemplate post-processor), so the cuts at added tokens apply unchanged; its intra-gap cuts are only enabled for the
GLM / Llama-3 Split regex, so a single huge message without added tokens still takes the single-call path, which is the
existing, correct fallback.
In production we run the same approach as an out-of-tree patch; its in-process shadow check (re-encoding one request
in ten with the original single call and comparing ids) recorded about 3,100 comparisons on two serving nodes over
roughly eight hours of agent traffic, with no mismatch.
Modifications
serving_chat.py: the dsv4, dsv41 and dsv32 branches of_process_messagescallparallel_prompt_encode(self.tokenizer_manager.tokenizer, real_input)instead ofself.tokenizer_manager.tokenizer.encode(real_input). Noencode_kwargsare passed, matching the previous call.Below
SGLANG_PARALLEL_PROMPT_ENCODE_MIN_CHARS(32,768 chars) the helper callstokenizer.encodeexactly as before.test_serving_chat.py:test_native_encoders_tokenize_through_parallel_prompt_encodepins that all three nativeencoders route through the helper and use its ids.
This is complementary to the open event-loop work (#39716, #41031, #44502): those move prompt preparation off the loop,
this makes the tokenization itself ~9x cheaper wherever it runs. #42187 (segment cache) would further skip unchanged
segments; it also targets the Jinja path.
Accuracy Tests
The helper's contract (ids identical to the single encode) is already pinned by
test_parallel_prompt_encode.py.For this tokenizer specifically: 0 mismatches over 5,906 comparisons (~1.1 G chars) of
encoding_dsv41-rendered agentconversations and adversarial text (CJK, emoji, partial added-token strings, whitespace next to added tokens), with cut
points forced every ~40 chars; plus the production shadow check above (~3,100 comparisons, 0 mismatches).
Benchmarking and Profiling
See the table above (single prompt, CPU only, same machine and process).
Checklist
test_serving_chat.py: 160 passed (applied on nightly-dev-20261020-ab580b2e; the diff is against maineb4b167and applies with line offsets only).
🤖 Generated with Claude Code
CI States
Latest PR Test (Base): ❌ Run #39450261392
Latest PR Test (Extra): ❌ Run #39450261171
Latest PR Test (AMD ROCm 10): ❌ Run #39450261263