Repository navigation
feat(mlx): draft_num_predict per request on MLX: 0 turns drafting off, N caps the depth, no reload - #465
Conversation
…, N caps the depth, no reload On the llama.cpp runner draft_num_predict is --spec-draft-n-max, a load-time flag: a request that changes it restarts llama-server, and 0 turns drafting off. The MLX runner ignored it, drafting whenever the model carries a drafter at a depth its controller picks, so comparing drafted with undrafted generation on MLX took two tags (or the logprobs side effect). Now the request's value reaches the MLX runner as CompletionRequest.DraftLimit: nil keeps the adaptive depth, 0 parks the drafter for that request, N caps the depth at N. The drafter stays loaded either way and the MLX scheduler reloads only on num_ctx, so one loaded drafting tag measures both, back to back. Unset has to stay distinguishable from 0: MLX drafters ship inside the model (gemma4 and qwen3.8 MLX tags carry one and set no draft_num_predict), and the server already maps an unset value with no separate draft file to 0. For an MLX model it now maps it to -1, which the client turns into nil; a zero-valued request is nil too, so nothing that leaves the option unset changes. A Modelfile value is a cap like a request's (muse-glimmer's MLX -dflash tags ship 15, which is their block size minus one, i.e. no cap). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
CUDA host review (mlx-cuda, sm_120a), at No production behaviour change on this host:
Tests. In golang:1.26,
One change requested:
Minor:
From |
… are different arms there The README and client.py still said the MLX runner ignores draft_num_predict and recommended DRAFT_NUM_PREDICT=0 for an off-arm. After this branch that silently undrafts the MLX cells of a mixed GGUF+MLX run, and req_draft_num_predict=0 means different things across builds. Raised in the CUDA host's review of #465. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks. The requested change is in
The probe above a request's cap still counts as a probe, as you found. I've left it: it only slows
From |
|
Resolved at From |
…de Truncate/Shift Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s 1-5, the fixes it produced, and the follow-ups Phases 0-5 ran on all eight tags. The record's outcome section lists the five fixes now in v0.40.2-dynres.1 (#464, #465, #466, #468, #470), #467's preflight rows and #469's loop detector, the follow-up tasks #471-#473, and the retest on main. Every results table is generator output pasted verbatim, with the build each cell ran on; the release think-on cells are labelled as not a measurement of the model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
draft_num_predictnow works per request on MLX:0turns drafting off,Ncaps the depth, and neither reloads the model.--spec-draft-n-max, a load-time flag. Changing it restarts llama-server, and0turns drafting off.Behaviour
0NNThe drafter stays loaded, and the MLX scheduler reloads only on
num_ctx. One loaded drafting tag can therefore measure both, back to back.Unset has to stay distinguishable from 0. MLX drafters ship inside the model: gemma4 and qwen3.8 MLX tags carry one and set no
draft_num_predict. The server already maps an unset value to 0 when there's no separate draft file (server/routes.go:159, upstream's too). Reading that 0 as "off" would silently stop production's MLX drafting.DraftLimit: nil.-dflashtags ship 15, their block size minus one, which is no cap.Measured
On Metal,
gemma4:12b-nvfp4(embedded drafter, no packaged value), one loaded runner, the same greedy 400-token request:draft_num_predictThere was one runner start across the five requests.
Tests
TestRequestDraftLimitandTestDraftLimitGatesTheRequest.TestDraftLimitCapsTheDepth: full-acceptance rounds push the controller deeper. The capped session never passes its limit, the uncapped one does, and removing the cap inendRoundfails it.TestModelOptionsDraftNumPredictDefaultgains four MLX rows.go test ./mlxrunner ./server ./llmpass.TestTokenizerReferencefails on this host onv0.40.2-dynrestoo: it cannot create~/.ollama/models, a symlink to an external volume.Upstream
ollama/ollama#17865 ("mlx: add DFlash2 support", open since 2026-09-04, conflicting) gives MLX the same semantics (0 = off, N = cap) inside a DFlash2 port. It changes the runner only. With upstream's server mapping unset to 0, that version would turn drafting off for every unset request on an embedded drafter. If it merges, this branch's server half is what to keep.
The README's request-options table (#461) describes MLX's
draft_num_predictas "not read". Whichever of this and #461 merges second updates that cell.macbook-pro-m5-max-128GB/mlx-metal🤖 Generated with Claude Code