Repository navigation
Conversation
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in PRs do not trigger a full CI run by default. Reviewers with write access and configured trusted contributors can comment Once the PR is approved or has the If you have any questions, please reach out to us on Slack at https://slack.vllm.ai. Agent GuidelinesIMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban. 🚀 |
23b7ac5 to
f23d49e
Compare
|
Joined the developer Slack and posted in #pr-reviews for this fix (#54337). DCO and format checks are green. Once a maintainer adds the |
Agent clients send assistant messages with content=null and tool_calls. Chat templates that render content emit a literal None into the prompt, which degrades multi-turn agent sessions over many tool turns. Coerce null content to an empty string in _postprocess_messages, next to the existing tool-call arguments normalization. Fixes vllm-project#54337 Signed-off-by: lllakshit <llakshitmathur239@gmail.com>
f23d49e to
676e879
Compare
| # Agent clients send assistant messages with content=null and | ||
| # tool_calls. Templates that render {{ content }} emit a literal | ||
| # "None" into the context, which degrades multi-turn generation. | ||
| message["content"] = "" |
There was a problem hiding this comment.
To be honest, I'm not entirely sure whether this fix is correct or whether it should be a general change. I feel that setting content to None would be more appropriate than setting it to "".
There was a problem hiding this comment.
Thanks for taking a look - leaving content as None is what triggers the bug.
Jinja chat templates that render {{ content }} stringify Python None to the literal text None. That is the prompt pollution reported in #54337 (especially over many tool-calling turns).
Empty string is intentional here because:
- OpenAI-style clients already send assistant turns as
content: null+tool_calls; the model-facing prompt should treat that as "no text", not the token/Nonestring. - This stays scoped to assistant messages that also have
tool_calls, so we do not change general null-content handling elsewhere.
Happy to adjust if you prefer deleting the key instead of an empty string, but keeping None would not fix the reported template behavior.
|
This pull request has merge conflicts that must be resolved before it can be |
Summary
content: nullandtool_callsto use an empty string before chat templating.{{ content }}from injecting the literal stringNoneinto the prompt.test_chat_utils.py.Problem
OpenAI agent clients (OpenAI SDK, pi, etc.) commonly send assistant turns as
content: nullplustool_calls. When those messages reachapply_chat_template, templates that unconditionally render assistant content emitNoneas text. Over many tool-calling turns in an agent session, this silently degrades generation into repetition loops and looks like a model quality issue rather than a preprocessing bug.Reported in #54337 with reproduction on GLM chat templates; the fix is protocol-layer and model-agnostic.
Fix
Extend
_postprocess_messagesinvllm/entrypoints/chat_utils.pyto coercecontent=Noneto""for assistant messages that includetool_calls, alongside the existing tool-call argument normalization.Test plan
_postprocess_messageslocally (null content becomes"", arguments still parsed)pytest tests/entrypoints/unit_tests/test_chat_utils.py::test_postprocess_messages_null_content_with_tool_calls -qpytest tests/entrypoints/unit_tests/test_chat_utils.py::test_postprocess_messages_null_arguments_string -qFixes #54337