Improve preset creation harness - #4078
Open
peterschmidt85 wants to merge 1 commit into
Open
Conversation
peterschmidt85
force-pushed
the
preset-harness
branch
from
August 4, 2026 17:11
0a262bc to
8564c43
Compare
peterschmidt85
force-pushed
the
preset-harness
branch
2 times, most recently
from
August 4, 2026 17:50
1faba33 to
1430813
Compare
A preset claims to be a verified serving configuration, but three of the properties that decide what "verified" means were optional or defaulted, so two creations with the same configuration could produce very different artifacts. - `max_ttft` and `min_context_length` are now required. Without a latency bound, maximising throughput has a degenerate optimum; without a context floor, one creation served 64K where another served 1M under identical constraints. - `concurrency` is now required rather than defaulting to 8. - `trials` in the configuration, `trials_num` in the constraints the agent reads, since it is the number of trials rather than a ceiling. - `baseline: true` makes the first trial a reference point rather than an optimization attempt. - `input_tokens`/`output_tokens` pin the benchmark workload so trials and the final service are comparable; both default to 1024. - rename the config's `context_length` to `min_context_length`, since it is a requirement, and keep `context_length` for the measured value. Per-user speed is now the steady decode rate, `1/TPOT`, as the serving literature defines it. Dividing aggregate throughput by concurrency folded in time to first token and read about 9% low. Both display paths now use the same definition; they previously disagreed. The trial record gains `learned`, required for every trial, and `failed` for a benchmark that broke a constraint. A failed trial keeps its benchmark, since that is what the next trial learns from, and is excluded from best-trial selection. `findings.md` is removed. It asked the agent to enumerate what it had not tried, which is unbounded and produced an arbitrary subset presented as complete. What a trial taught now lives on the trial record. Trials themselves are measured more honestly: - record the largest context each trial handles, found by sending real requests - run the final benchmark inside the service replica, directly against the engine, so it is comparable with the trial benchmarks - require that a benchmark not reuse the previous one's prompts, which had been inflating later trials through the engine's prefix cache - record final service attempts in `verifications.jsonl` and mirror them out, so the CLI reads the phase instead of inferring it from a spent trial budget Also fixes a real bug: session constraints were read from the agent workspace, which is deleted when a session finishes, so a verified preset could never show what it was created against. `dstack preset` output is reworked: `ps`-style filtering, CONSTRAINTS and BENCHMARK columns, and one sparkline glyph per trial. The constraints are dimmed so the measurement leads, and a trial that broke a constraint is marked with a yellow bar. Maintainer notes written as `<!--!...-->` are stripped from the rendered agent prompt. The `endpoints` to `presets` rename in #4058 deleted two docs pages without adding redirects, so `/docs/concepts/endpoints/` and `/docs/reference/cli/dstack/endpoint/` returned 404. Both now redirect to their `preset` equivalents. `shared_prefix_tokens` is documented on the concepts page. It existed only in the generated schema reference, so the property that decides the benchmark's prefix cache hit rate was invisible to anyone reading the concept. A run where no trial met the constraints showed neither hardware nor a number, because both were read from the best trial and a failed one cannot become best. Such a run now shows its fastest failed benchmark, dimmed and marked `*` so it does not read as a result where styling is absent. That is the answer such a run produced: `ttft=4.3s` against a 675ms bound is why a card is unusable. The listing always shows `prefix`, including `prefix=0%`. It decides how much of each request the engine serves from its prefix cache, so two rows are only comparable when it matches. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
peterschmidt85
force-pushed
the
preset-harness
branch
from
August 4, 2026 18:55
1430813 to
b608942
Compare
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.
dstack preset createnow requiresmax_ttft,min_context_lengthandconcurrency. They were optional or defaulted, so two creations from the same configuration could produce very different presets: one run served 64K where another served 1M, and a trial whose p50 TTFT was 22.7s against a 10s cap was recorded as a normal trial and was eligible for promotion. This PR also pins the benchmark workload withinput_tokensandoutput_tokens, so trials and the final service measure the same thing, and records what each trial taught on the trial record.dstack presetshows the constraints a preset was created against next to what was measured, with one sparkline glyph per trial:Main changes:
max_ttft,min_context_lengthandconcurrencyare now required. Without a latency bound, maximising throughput has a degenerate optimum, and without a context floor two runs under identical constraints are not comparable.input_tokensandoutput_tokenspin the benchmark workload, so trials and the final service measure the same thing. Both default to 1024.baseline: truemakes the first trial a reference point rather than an optimization attempt, so an improvement percentage means something.learned, required for every trial including a failed one, andfailedfor a benchmark that broke a constraint. A failed trial keeps its benchmark, since that is what the next trial learns from, and is excluded from best-trial selection.findings.mdis removed. It asked the agent to enumerate what it had not tried, which is unbounded, so the agent produced an arbitrary subset and presented it as complete. What a trial taught now lives on the trial record.prefix, includingprefix=0%. It decides how much of each requestthe engine serves from its prefix cache, so two rows are only comparable when it matches.
read from the best trial and a failed trial cannot become best. It now shows its fastest failed
benchmark, dimmed and marked
*so it does not read as a result where styling is absent.dstack presetgainsps-style filtering with-a,-n,--baseand--repo, theCONSTRAINTSandBENCHMARKcolumns above, and one glyph per trial: yellow where a trial broke a constraint, a red dot where it produced no benchmark. Pass-vto also seectx>=andttft<=.Behavior changes:
1/TPOT, as the serving literature defines it. Dividing aggregate throughput by concurrency folds in time to first token and read about 9% low. The preset row and the session row previously disagreed on the same run.Breaking changes:
max_trialsis nowtrialsin the configuration, andtrials_numin the constraints the agent reads, since it is the number of trials rather than a ceiling.context_lengthin the configuration is nowmin_context_length, since it is a requirement.context_lengthkeeps the measured value in the saved preset.max_ttft,min_context_lengthandconcurrencyno longer have defaults.Existing configurations fail with
extra fields not permitted. Presets are experimental, so no aliases were added.Internal changes:
verifications.jsonl, so the CLI reads the phase instead of inferring it from a spent trial budget. That inference was wrong for every run that stopped early.shared_prefix_tokensis documented on the concepts page. It existed only in the generatedschema reference, so the property that decides the benchmark's prefix cache hit rate was
invisible to anyone reading the concept.
endpointstopresetsrename in [Feature] Presets #4058 deleteddocs/concepts/endpoints.mdanddocs/reference/cli/dstack/endpoint.mdwithout adding redirects, so both URLs returned404. They now redirect to their
presetequivalents.<!--!...-->are stripped from the rendered agent prompt, so the prompt can carry TODOs without the agent seeing them.What the agent found for that configuration
The baseline trial measured 157 tok/s/user. The best that held up was trial 4 at 309, roughly 2x the baseline, at the full 1M context and inside the 675ms bound.
The agent arrived at SGLang with EAGLE speculative decoding, the
dsv4attention backend, theflashinfer_mxfp4MoE runner and an fp8 KV cache, none of which was suggested to it:Two things in that row come from this PR. Trial 3 benchmarked highest at 319 but ran out of memory prefilling 1M tokens as a service, so verification rejected it and trial 4 was promoted instead. Trial 5 is the yellow glyph: it benchmarked at 289 but broke a constraint, so it keeps its benchmark for the next trial to learn from and is excluded from selection. The session reads interrupted because it was stopped after 5 of the 10 trials.
The Presets concept page is updated to match, including a roadmap of what is not supported yet: changing code, multi-node and P/D disaggregation,
--previous, and concurrency ranges.Rebased onto Pydantic v2 (#4077).
AI assistance: written with Claude Code.