Repository navigation
Add a hard reasoning-token budget and DeepSeek V4.1 sampling ranges - #167
Merged
Merged
Conversation
DeepSeek V4.1 declared no sampling ranges, so every requested sampling value was replaced by the recipe default. Requests can now use top_p in [0.95, 1] (the V4.1-Flash card recommends 0.95 or 1.0 and its benchmarks use 0.95) and repetition_penalty in [1, 1.1]. Defaults are unchanged, so requests that set nothing behave as before. Ranges are package metadata: they take effect in packages exported after this change. Validation: the DeepSeek V4.1 declaration test passes with the new expectation. No package export or GPU run yet. Design-Signed-Off-By: yatesdr; design-review=1c01
A request's thinking budget only selected a reasoning effort; reasoning itself was unbounded, and unknown budget fields were ignored. Reasoning models can loop in their reasoning (DeepSeek V4.1 Flash repeats short openers in 10-19% of multi-turn agent turns on every engine), and a hard cap is the documented mitigation. thinking_token_budget (Chat Completions, Responses, Messages) caps the reasoning tokens a request may generate. The first pass runs with the budget as its output limit. If the output parser reports that reasoning is still unambiguously open when the pass ends, the contract's single-token reasoning close is emitted through the normal output path (stop matching, grammar, streaming, usage) and the request continues from history plus the close with the remaining output limit, reusing the preemption park and readmission path. If reasoning already ended, the parser is still deciding (a tool opener), or a grammar disallows the close, the request continues without injection. EOS, stops, errors and cancellation never continue. Requests whose output starts in content are accepted with no cut. On a format that cannot honour a hard cap, thinking_token_budget is rejected, while Messages thinking.budget_tokens keeps its documented advisory meaning (it sets the effort only); on formats that can, it also sets the cap. Raw Completions reject the field. The forced token has no logprob entry. Requests without a budget take the existing paths unchanged. [server] thinking_token_budget sets an operator default for requests that set none; it flows from the Flare configuration through flare serve, is validated at startup with the same check requests use, and is advertised in the flare metadata of /v1/models. Metric: reasoning_budget_cuts_total. Validation: upstream CI's helios command (runtime-package,server, with the prepared templates) 1204 passed, 0 failed; flare CLI tests match main (the same pre-existing hub-test hang and environment failures); focused Python CLI tests pass. Tests cover decoding and validation on every protocol, exact cut counts at the output-limit edges, preemption through the cut, close or EOS as the N-th token, multi-token speculative completion at the pass limit, tool calls (including a pass ending on an undecided tool opener, with and without a grammar), streaming on Chat and Messages, and the configuration path. Independent reviews and a whole-branch simplicity pass; findings addressed. Not yet run: real-model checks and a fixed-seed comparison without a budget against the previous build. Design-Signed-Off-By: yatesdr; design-review=1c01
The [server] thinking_token_budget default was added to the server
options ignition builds for both debug-serve and package export, so
every export failed in the native exporter ("unrecognized field name
thinking_token_budget"; the package's serving contract has no such
field), even with the budget unset. The budget is a serving setting:
it is now added only on the debug-serve path, and flare serve reads it
from the configuration as before. Export options are unchanged from
before the budget.
Validation: a new test parses the export server options into the
package's ServingContract with the budget unset and set; it fails
without this change and passes with it. Serving-default tests and the
CLI tests that run without preparation dependencies pass (106); CI's
helios command passes. A DeepSeek V4.1 Flash export failed at "Export
native package" before this change.
Design-Signed-Off-By: yatesdr; design-review=1c01
yatesdr
force-pushed
the
flare-reasoning-budget
branch
from
November 2, 2026 14:18
993b985 to
7cb2751
Compare
jayinsine
added a commit
to jayinsine/spark-local-inference
that referenced
this pull request
Nov 4, 2026
…ages Since NVIDIA#167, DeepSeek V4.1 declares a top-p range of [0.95, 1]. Vocabulary-parallel sampling supports only unfiltered target distributions: its softmax marks a row invalid when top-p is not 1, min-p is not 0, or top-k is active. A package exported with --vocabulary-parallel-sampling after NVIDIA#167 therefore admits top_p 0.95, every speculative round of that request fails verification, and the request ends with HTTP 500 "prepared model reported device error 6" (INVALID_SPECULATION). The same package serves top_p 0.95 with --mtp-draft-tokens 0, and packages exported before NVIDIA#167 clamp top-p to 1. SamplingDefaults.unfiltered() returns the policy without top-k, top-p, and min-p ranges and rejects defaults that enable those filters. DeepSeek V4.1's PreparationConfig packages that policy when vocabulary-parallel sampling is enabled and validates it on construction. As for any absent range, requests are clamped to the default (top-p 1), which keeps the documented requirement that these filters stay disabled for this option. Other ranges, including repetition_penalty [1, 1.1], are unchanged, and packages exported without the option keep the top-p range. The preparation and API documents describe the packaged policy. Validation: - New tests cover the unfiltered policy (non-filter ranges kept for top-k -1 and 0, enabled filter defaults rejected) and the DeepSeek export adapter with and without --vocabulary-parallel-sampling. The adapter test fails without the bootstrap change. - tests/preparation/test_frontend_metadata.py, tests/recipes/test_declarations.py, tests/cli/test_planning.py, tests/cli/test_speculative_graph_budget.py, tests/recipes/test_deepseek41_frontend.py, tests/preparation/test_native_recipe_contract.py and tests/preparation/test_runtime_package.py, with Heliopause built with the qualification feature: 296 passed, 37 skipped, 11 failed. The same 11 fail on cc696a6 without this change: five need the Kimi K3 checkpoint, two are the deepseek41 and muse_spark default-sampling expectations, two are runtime collective-ladder cases, and three are graph-budget cases. - GPU: exported a derivative of the qualified DeepSeek-V4.1-Flash-1017 revision at TP4 on four RTX PRO 6000 Blackwell GPUs (C32, MTP 7, --vocabulary-parallel-sampling, NVFP4 draft head, FP8 Markov head; NVIDIA#154 applied locally so the C32 export fits) and served it with flare run. flare inspect shows no top-p range and keeps the repetition-penalty range; a package exported from 902c88e shows top-p [0.95, 1]. Chat requests with top_p 0.95 at C1 and C8 and one streamed request all returned 200 with 3.4-3.8 accepted drafts per verification round, where the 902c88e package returned device error 6. Functional API checks passed 34/34 and decode throughput was unchanged. Limitations: on these packages a request for top_p below 1 receives top-p 1, as before NVIDIA#167, rather than a filtered distribution. Top-p support in vocabulary-parallel verification would change its sampling kernels and is not attempted here. Only single-host TP4 was exercised. Design-Signed-Off-By: Claude Opus 5.5 (agent for Josh Cartu); design-review=a38f Signed-off-by: Josh Cartu <j@mail99.me>
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.
What
Adds a hard reasoning-token budget and declares DeepSeek V4.1 sampling ranges for
top_pandrepetition_penalty, so clients can apply the controls that suppress reasoning repetition.Why
DeepSeek V4.1 Flash repeats short reasoning openers ("let me go, let me write" ×N) in 10–19% of later turns of multi-turn agent conversations. We measured this on Flare, on vLLM with the same checkpoint and on DeepSeek's own API, and Flare's per-token probabilities match vLLM's on the repeated text within vLLM's own run-to-run noise, so it is model behaviour, not an engine defect. Flare could not apply any client-side mitigation: a thinking budget only selected an effort level, unknown budget fields were ignored, and with no declared ranges every requested
top_por penalty was replaced by the recipe default.Changes
DeepSeek V4.1 ranges (
ignition/recipes/deepseek41/recipe.py):top_p[0.95, 1] (the V4.1-Flash card recommends 0.95 or 1.0; its benchmarks use 0.95) andrepetition_penalty[1, 1.1] (measured below). Defaults are unchanged. Takes effect in packages exported after this change.Hard reasoning budget.
thinking_token_budgeton Chat Completions, Responses and Messages caps generated reasoning tokens. The first pass runs with the budget as its output limit; if the output parser reports reasoning still open, the contract's single-token reasoning close is emitted through the normal output path (stops, grammar, streaming, usage) and the request continues from history plus the close, reusing the preemption park and readmission path. No injection when reasoning already ended, the parser is still deciding (a tool opener), or a grammar disallows the close. EOS, stops, errors and cancellation never continue. Output starting in content is accepted with no cut. On formats that cannot honour a hard cap,thinking_token_budgetis rejected while Messagesthinking.budget_tokenskeeps its documented advisory meaning. The forced token has no logprob entry. Metric:reasoning_budget_cuts_total.Operator default:
[server] thinking_token_budget, validated at startup with the same check requests use and advertised in/v1/models.Export fix (follow-up commit): the operator default is a serving setting and is no longer added to the server options used for package export (it had made every export fail with "unrecognized field name thinking_token_budget"). A test now parses the export server options into the package's serving contract, with the budget unset and set.
Requests without a budget take the existing paths unchanged.
Testing
Unit (CI's Linux commands, on current main including #162): helios passed with 0 failed; flare CLI tests match main. Tests cover decoding and validation on every protocol, exact cut counts at the output-limit edges, preemption through the cut, close or EOS as the N-th token, multi-token speculative completion at the pass limit, tool calls including a pass ending on an undecided tool opener (with and without a grammar), streaming on Chat and Messages, and the configuration path.
Real model: DeepSeek V4.1 Flash 1017, TP4 on an SM120 host (4× RTX PRO 6000), MTP 5 unless noted.
Repeat rates on a multi-turn agent workload (fresh seed per request, 599 later-turn and 120 single-turn answers per arm):
repetition_penalty1.05 is the effective mitigation for multi-turn repeats; 1.1 started to hurt output validity, hence the upper bound. Quality was measured by proxies (valid tool calls and answers, grounding of tool arguments), not task accuracy.Notes
repetition_penaltyrange is based on our measurements rather than the model card.