Repository navigation
Conversation
…l calls
DeepSeek model output carries tool arguments as DSML parameters. The engine's
arg_structural_chars gate (">") drops every delta that contains no tag
boundary, and _dsml_arg_converter only re-serialises the whole parameter list,
so a long string="true" value (which contains no ">") used to be buffered
until its closing tag arrived. The client then received no bytes for the whole
generation: a 15k-character Write payload kept the stream silent for 130-220
seconds, past any client read timeout, while the engine kept decoding.
Wire an arg_value_extender into the DeepSeek V3.2, V4 and V4.1 configs so the
open parameter value is serialised incrementally as it is generated. Only a
trailing partial tag is held back, and the engine falls back to the full
converter once the closing tag arrives (or when the value is not streamable,
e.g. string="false" numbers, where open_value_streams stays False).
Signed-off-by: xlshaoscu <xlshaoscu@foxmail.com>
|
👋 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. 🚀 |
…V4.1
DeepSeek V4 and V4.1 stream tool arguments as DSML parameters and configure
arg_structural_chars = {'>'}. ParserEngine._compute_arg_delta() drops every
delta that shares no character with that set, so a long string="true" value
(file body, heredoc, ...) is buffered until its closing tag arrives. The
client then receives no bytes for the whole generation - a 15k-character
payload kept the stream silent for 130-220 seconds, past any client read
timeout, while the engine kept decoding normally.
For the deepseek_v4 / deepseek_v41 parser engines only, let value-body deltas
through while still holding back a trailing partial tag. Conversion, prefix
and diff bookkeeping stay in upstream code.
Verified offline against the engine's own converter/prefix logic: the same
3 KB value produced 4 argument deltas with a 2168-character silent gap before
the patch and 273 deltas with a max 88-character gap after it, prefix-safe.
Upstream fix: vllm-project/vllm#64196
Signed-off-by: xlshaoscu <xlshaoscu@foxmail.com>
…V4.1
DeepSeek V4 and V4.1 stream tool arguments as DSML parameters and configure
arg_structural_chars = {'>'}. ParserEngine._compute_arg_delta() drops every
delta that shares no character with that set, so a long string="true" value
(file body, heredoc, ...) is buffered until its closing tag arrives. The
client then receives no bytes for the whole generation - a 15k-character
payload kept the stream silent for 130-220 seconds, past any client read
timeout, while the engine kept decoding normally.
For the deepseek_v4 / deepseek_v41 parser engines only, let value-body deltas
through while still holding back a trailing partial tag. Conversion, prefix
and diff bookkeeping stay in upstream code.
Verified offline against the engine's own converter/prefix logic: the same
3 KB value produced 4 argument deltas with a 2168-character silent gap before
the patch and 273 deltas with a max 88-character gap after it, prefix-safe.
Upstream fix: vllm-project/vllm#64196
Signed-off-by: xlshaoscu <xlshaoscu@foxmail.com>
|
This pull request has merge conflicts that must be resolved before it can be |
Overview
DeepSeek models emit tool-call arguments as DSML parameters. With
arg_structural_chars = frozenset(">"),ParserEngine._compute_arg_delta()drops every delta that contains no tag boundary, and_dsml_arg_converteronly re-serialises the whole parameter list. A longstring="true"value contains no'>'at all, so it is buffered until its closing tag arrives: the client receives zero bytes for the entire generation. A 15k-characterWritepayload keeps the stream silent for 130–220 s, far past any client read timeout, while the engine keeps decoding normally.This PR wires an
arg_value_extenderinto the DeepSeek V3.2 / V4 / V4.1 configs so the open parameter value streams while it is generated.Claims
string="false"numbers/objects, keys whose schema type is notstring) — they still go through the full converter.Validation
tests/parser/engine/test_deepseek_long_arg_streaming.py, parametrised overdeepseek_v4/deepseek_v41/deepseek_v32. It asserts the value arrives in many fragments, that no fragment carries most of it, and that a value containing</ a partial closing-tag prefix is not corrupted._compute_arg_delta(real_dsml_arg_converter+_safe_arg_prefix+ the new extender) over a 3 KB value: 4 argument deltas with a 2168-char silent gap before, 273 deltas with a max 88-char gap after; prefix-safe and parse-equal for all three dialects.Details
_compute_arg_delta()returnsNonewhenarg_structural_chars.isdisjoint(raw_delta). DSML only guarantees a'>'at tag ends, so every delta of a value body is suppressed._safe_arg_prefix()is already able to stream an unterminated trailing string, but it is only reached when a delta survives that gate.make_param_value_extender(param_start, param_close, extra_stop_tags)returns an extender that re-serialises only the value tail, using the samejson.dumpsescaping as_dsml_arg_converter(json.dumps(visible)[1:-1]). A trailing partial tag is held back via the existingpartial_tag_overlaphelper; when the closing tag (or another tag) appears, the extender returnsNoneand the engine clears it and falls back to the full converter.<|DSML| parameter), so it rebuilds the extender from its own constants instead of inheriting V4's; V3.2 reuses the V4 parameter format with a different outer wrapper.open_value_streamspermits, i.e. the trailing value the schema types as a string. Object/array arguments keep the current behaviour, and a value whose key is not declared as a string in the tool schema is also unchanged.Pull Request Checklist
I used vLLM's
/pr-checklistskill. (Mandatory for agents, optional for humans). — not available in this authoring environment; please treat this as unchecked.AI assistance was used during the creation of this PR.
Design Fit: reuses the existing
arg_value_extender/open_value_streamsmachinery already used by gemma4 and glm47_moe; parser-local change, no engine changes.Testing and Validation: adds parser-level streaming tests for all three dialects; CI run still required (see Validation).
Code Quality and Style: no new dependencies, reuses
partial_tag_overlap, docstrings explain the root cause and the fallback contract.Pull Request Contents: summary, root cause, trade-offs and limitations are documented above.