Skip to content

perf(function_call): skip DeepSeek V3 regex scans until the JSON fence closes - #1716

Merged
shihaobai merged 1 commit into
ModelTC:mainfrom
dogeONE-bit:perf/deepseekv3-fence-guard
Nov 12, 2026
Merged

shihaobai merged 1 commit into
ModelTC:mainfrom
dogeONE-bit:perf/deepseekv3-fence-guard

Conversation

@dogeONE-bit

Copy link
Copy Markdown
Contributor

deepseek_v3 still selects DeepSeekV3Detector. #1698 skips the V3.1, V3.2 and V4 scans until an end tag is in the buffer. The V3 pattern is different: it matches when a closing fence follows the json code block, and that fence arrives before the tool-call end token. The function name is emitted on the fence, so waiting for the end tag would change when the name and arguments are sent. This waits for the fence instead.

Every delta ran that DOTALL regex over the whole accumulated text. A normal JSON argument contains no raw newline followed by a fence, because newlines inside strings are escaped, so the pattern cannot match until the format's own closing fence. The scan now runs only once that fence is present. The check is a find that starts after the json header, so a failed check means the regex would not have matched. Returned calls and parser state stay the same.

If the argument text itself contains a newline followed by a fence, the pattern can match and the scan is not skipped. A 15 KB argument with that fence 2 KB in stays on the regex, about 0.74-0.92 s on both versions.

Parser time for one streamed call. Special tokens arrive whole and the argument is split into 4-character deltas, which is how a long write_file is streamed. Median of 5 fresh processes, one warmup in each, OMP_NUM_THREADS=1, CPython 3.12.16, Xeon Platinum 8352Y. The sha256 of the returned calls matches on every case.

case before after
write_file, 4 KB 60.7 ms 3.46 ms
write_file, 15 KB 813 ms 26.7 ms
write_file, 32 KB 3.85 s 111 ms
short get_weather 0.085 ms 0.072 ms
plain text, no tool call 0.48 ms 0.48 ms

unit_tests/server/test_deepseek_tool_parser_stream.py: 7 passed on this change and on main. The three new V3 tests cover a long argument in 4-character deltas, a closing fence split across deltas, and a fence kept inside a JSON string.

AI assistance (Cursor) was used for this change.

…e closes

The streaming parser ran its DOTALL regex over the whole buffer on every
delta. A JSON argument cannot match until a closing fence follows the json
header, so the scan now waits for that. Output is unchanged.

AI assistance (Cursor) was used for this change.

Co-authored-by: Cursor <cursoragent@cursor.com>
@shihaobai
shihaobai merged commit bc21c93 into ModelTC:main Nov 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants