Repository navigation
Conversation
…system message apply_chat_template always prepended a new system message for `tools=`, so a request's own system prompt rendered after the tool block instead of before it. Attach the tools to the leading system message when there is one, as the checkpoint encoder does. DeepSeek-V4.1 gets the same fix. Signed-off-by: Zhaowei Gu <83746079+zw-g@users.noreply.github.com>
Contributor
Author
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.
Dev Engineer Review
DeepSeek-V4 and V4.1 now attach request-level
toolsto a copied leadingsystemmessage. They preserve the caller’s dictionary and retain synthetic-message behavior when no leadingsystemmessage exists. No public API declarations changed.QA Engineer Review
Modified tests cover tool attachment, system-message ordering, input immutability, and prevention of an extra system block. Reported results are
48 passed, 42 skipped; skipped tests require a local DeepSeek checkpoint. Coverage is sufficient. No test-list changes were reported.Per-File QA Perspective
tensorrt_llm/tokenizer/deepseek_v4/tokenizer.py: Verify leadingsystemhandling and synthetic-message fallback.tensorrt_llm/tokenizer/deepseek_v41/tokenizer.py: Verify the equivalent V4.1 behavior.tests/unittest/llmapi/test_deepseek_v4_tokenizer.py: Covers request-level tools, output ordering, and input immutability. No test-list entry was reported.tests/unittest/llmapi/test_deepseek_v41_tokenizer.py: Covers tool attachment, single-system-message rendering, and input immutability. No test-list entry was reported.Description
Fixes #17021.
DeepseekV4Tokenizer.apply_chat_templatehandles the OpenAItoolsargument with an unconditionalmessages.insert(0, {"role": "system", "tools": tools}). The renderer'ssystembranch emitscontentand then"\n\n" + <tool block>, so when the request already has a system message:\n\nright after BOS);The DeepSeek reference format attaches the tools to the existing system message (the vendor fixtures do the same:
messages[0]["tools"] = case["tools"]). This affects every/v1/chat/completionsrequest that carries both a system message andtools, which is the normal serving path (async_apply_chat_template(tools=...)->tokenizer.apply_chat_template(messages, tools=tools)). Measured with a system prompt + one tool + one user turn:DeepseekV41Tokenizer.apply_chat_template(added after the issue was filed) has the same insert and renders two<|System|>blocks with the tool block first:The change, the same in both files: when
messages[0]is a system message, the request tools are attached to a copy of it ({**messages[0], "tools": tools}, so the caller's dict is not modified); otherwise the synthetic system message is inserted as before. This is the fix suggested in the issue, and it matches how vLLM and SGLang attach request tools for these models. The closed #17036 took the same approach for V4 only.Behaviour notes:
developermessage, render byte-identically to before.messages[0]is considered, as in the issue's suggested fix and the vendor fixtures.messages[0]already carries its owntoolsandtools=is also passed, the request tools take its place; previously two tool blocks were rendered. The OpenAI server does not attach message-level tools for these models.deepseek_v32/tokenizer.pyinserts a synthetic system message the same way, but it is a separate model and encoder, so it is left out of this PR.Test Coverage
New regression tests, which fail on
mainand pass with this change:tests/unittest/llmapi/test_deepseek_v4_tokenizer.py::test_deepseek_v4_chat_template_attaches_request_tools_to_leading_system_messagetests/unittest/llmapi/test_deepseek_v41_tokenizer.py::test_tools_argument_is_attached_to_an_existing_leading_system_messageEach one asserts that passing
tools=with a leading system message renders the same prompt as attaching those tools to that system message directly. It also checks the start of the prompt (V4) or that there is exactly one<|System|>(V4.1), and that the caller's message dict is not mutated. The existing tests for the no-system-message path pass unchanged.Run locally on a CPU-only machine:
The 42 skips are the checkpoint differential / vendor golden-fixture tests, which need a local DeepSeek checkpoint.
pre-commit run --fileson the four changed files passes.PR Checklist
Please review the following before submitting your PR:
PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.
PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.
Test cases are provided for new code paths (see test instructions)
If PR introduces API changes, an appropriate PR label is added - either
api-compatibleorapi-breaking. Forapi-breaking, includeBREAKINGin the PR title.Any new dependencies have been scanned for license and vulnerabilities
CODEOWNERS updated if ownership changes
Documentation updated as needed
Update tava architecture diagram if there is a significant design change in PR.
The reviewers assigned automatically/manually are appropriate for the PR.
Please check this after reviewing the above items as appropriate for this PR.
GitHub Bot Help
To see a list of available CI bot commands, please comment
/bot help.