DeepSeek-V4-Flash on DGX Spark · part 5
[Local LLM] Depth-1 MTP on V4-Flash: +9% on agent turns, −4% on prose — route speculative decode by workload
❯ cat --toc
- The short version
- The setup
- The one-line result: the sign follows the workload
- Why the sign flips: decode here is verify-bound
- The limiter isn't draft quality — it's a margin gate
- Why not draft more than one token?
- How to route it: on for code/agent, route chat elsewhere
- Takeaways
- Where the time went
- Reusable diagnostics
- The general principle
- Conclusion: the checklist
TL;DR
Speculative decoding gets sold as a free speedup. On a bandwidth-bound GB10 it's actually a workload-dependent trade that can go negative. Depth-1 MTP (ds4 PR #371, "depth-1 continuous") drafts exactly one token ahead and verifies it. It's lossless — byte-identical output; the draft only changes speed, never the tokens. But the speedup has a sign, and the sign depends on what you generate: agent/tool turns +9.4%, code +6.5%, technical text +4.4% — and free prose −3.6%, Chinese chat −3.7%. The mechanism: decode here is verify-bound — one verify pass is ~108ms, a draft is ~4ms, so a drafted token that's accepted is nearly free, and one that's rejected is a verify you paid for and threw away. Predictable output (code, JSON, tool calls) gets accepted; open text doesn't. So MTP-1 isn't a global "faster" switch — turn it on for code/agent, and either eat the small cost on chat or route chat to the non-thinking deepseek-chat path from Part 2.
The short version
Speculative decoding is a helper that tries to finish your sentence. If it guesses right, you got two words out for the price of one; if it guesses wrong, you wasted the guess and have to say the word yourself anyway. Whether that's a net win depends entirely on how guessable your sentence is.
That's the whole story of this post. On my GB10, checking a guess (the "verify" step) costs ~108ms; making the guess (the "draft") costs ~4ms. So the guess is almost free — the expensive part is checking it. When the model is writing code, JSON, or tool calls — output where the next token is highly predictable — the guess is usually right, and you bank a nearly-free extra token per expensive check. That's the +6 to +9%. When it's writing free prose or chatting in Chinese — output where the next token is genuinely open — the guess is more often wrong, so you paid the small draft cost for a token you throw away. That's the −4%.
So depth-1 MTP is not a "make it faster" toggle. It's a trade whose sign flips with the workload. Enable it for the structured stuff, and for everyday chat either accept the small tax or send that traffic down a different path.
The setup
Depth-1 MTP (ds4 PR #371, "depth-1 continuous") is the modest version of speculative decode: one drafted token, one verify. It's the always-on default a lot of people leave enabled without checking. I checked. The answer is that it wins — but only on some workloads, and the ones it loses on are exactly the ones you'd reach for it on if you were guessing blind.
All numbers below are my own measurements on a single 128GB GB10 running the ds4 CUDA build, and the output is lossless — byte-identical with and without the draft, verified. The draft changes how fast the tokens come out, never which tokens they are.
The one-line result: the sign follows the workload

| Workload | MTP-1 vs no draft |
|---|---|
| Agent / tool-use | +9.4% |
| Code | +6.5% |
| Technical text | +4.4% |
| Free prose | −3.6% |
| Chinese chat | −3.7% |
Same model, same box, same flag — the only thing that changed between rows is what I asked it to generate. Structured, predictable output gets faster; open-ended output gets slower. The spread from best to worst is 13 points, and it straddles zero. That last part is what makes this interesting: there is no single true "MTP-1 speedup" number for this model. The honest answer to "how much faster is speculative decode?" is "on what?"
Why the sign flips: decode here is verify-bound

Depth-1 spec decode does two things per step: draft one token ahead (~4ms), then run one verify pass (~108ms) that either accepts or rejects it. The verify dominates by ~27×. That asymmetry is the entire mechanism.
- Draft accepted: the verify pass commits two tokens (the base token plus the drafted one) instead of one. You got a second token for essentially the same 108ms. Net win.
- Draft rejected: the verify pass commits one token, and the 4ms you spent drafting is gone. Net loss — small, because 4ms is small, but a loss.
So the sign of the speedup is just the sign of (free tokens from accepts) minus (wasted drafts from rejects). And whether a draft gets accepted is a property of the workload: when the next token is highly predictable — the closing brace after a block, the argument name in a known tool schema, the next keyword in boilerplate — the draft nails it and you bank the free token. When the next token is genuinely open — the next word in a sentence, the next turn in a chat — the draft is a coin flip, rejects pile up, and the wasted 4ms drafts outweigh the wins.
That's why the ranking is exactly agent > code > technical text > prose > chat: it's a predictability ranking. The speedup didn't rank the workloads; the acceptance rate did, and the acceptance rate is just how guessable the text is.
The limiter isn't draft quality — it's a margin gate
Here's the part that surprised me. Across 231 speculative cycles I logged, the average committed τ (tokens per cycle) was ≈1.54 — so on average each cycle banks about half an extra token. You might read a soft number like 1.54 as "the drafter is only so-so." It isn't. When a cycle actually runs its verify, ~97% of drafts are accepted. The draft quality is excellent.
What holds τ down is that a margin gate skips the verify entirely on ~44% of cycles — when the model's own confidence margin is too thin to bother speculating, it declines to draft-and-verify and just decodes normally. So the ceiling on MTP-1 here isn't "the drafter guesses wrong" (it almost never does, once it commits); it's "the drafter only plays the hand when it's confident, and it folds 44% of the time." That's a conservative design — it's why the losses on prose are only −3.6% and not −15%: the gate refuses most of the bad bets before they cost a verify.
It also means there isn't much headroom to tune on depth-1. You can't make a 97%-accept drafter much better. The lever that would move τ is drafting more tokens per verify — a bigger, separate bet, which I get into below.
Why not draft more than one token?
The natural next thought is "if one nearly-free drafted token helps, draft five and amortize the 108ms verify across all five." It's a real option, and a bigger bet. The catch is that a multi-token block only pays if the whole block survives verification: one rejected token collapses the amortization, and the probability that all N survive falls off fast as the text gets less predictable. A block draft is really a bet that the model's next several tokens are all guessable — which is a much stronger claim than "the next one is," and it gets shakier the longer the block. That's its own investigation with its own tradeoffs (and its own post).
Depth-1 is the floor: the smallest possible bet, so it's the one most likely to clear the acceptance bar — and on predictable workloads it clears it 97% of the time. This post is about making that floor pay, which turns out to be entirely a routing question.
How to route it: on for code/agent, route chat elsewhere
The practical takeaway is that "speculative decode: on/off" is the wrong granularity. Route it:
- Code, agent, tool-use → MTP-1 on. These are your +4 to +9% workloads, and they're also the ones where latency matters most — an agent turn is a chain of tool calls, each one a round trip you're waiting on. This is the free money.
- Everyday chat / creative → don't pay the −4%. Two options. Accept it — 3.6% is small and you may not want two serving paths. Or route that traffic to the non-thinking
deepseek-chatpath from Part 2, which is a better fit for casual turns anyway and sidesteps the wasted-draft cost entirely.
The meta-point: a speculative decoder is a bet on predictability, and you already know which of your workloads are predictable. You don't have to measure per request — code and tool calls are structured, chat and prose aren't. Set the flag by workload class, not globally.
Takeaways
Where the time went
Not in the tuning — depth-1 MTP is one flag. It went into not stopping at the average. A single blended "MTP-1 is +2%" number would have been true and useless; it hides a +9.4% and a −3.7% that cancel. The time went into slicing the benchmark by workload until the sign flip showed up, because the sign flip is the whole finding. An average speedup across mixed workloads is a number that describes no real workload you actually run.
Reusable diagnostics
When a speculative-decode result is small and positive, don't trust the average — split it by how predictable the output is and look for a sign flip. The tell for "this is verify-bound and acceptance-gated" is the ratio of verify cost to draft cost (here ~108ms vs ~4ms = 27×) together with the accept rate on committed cycles (~97%). If verify dwarfs draft and committed drafts almost always accept, your limiter is the gate that decides whether to speculate, not the drafter's quality — and your speedup will track workload predictability, not any flag you can tune.
The general principle
Speculative decoding is not a global "faster" switch — it's a workload-dependent trade whose sign follows the acceptance rate. Depth-1 wins where acceptance is high and loses where it's low, by roughly the same small margin. Enable it where your output is predictable, and know it's costing you a little where it isn't.
Conclusion: the checklist
- Turn MTP-1 on for code, agent, and tool-use. +4 to +9% on exactly the latency-sensitive workloads, lossless.
- Don't turn it on globally. Free prose and chat pay −4%; the speedup's sign follows how predictable the output is.
- Route chat elsewhere. Either eat the small cost or send casual turns to the non-thinking deepseek-chat path (Part 2).
- Don't try to tune depth-1. Committed drafts already accept ~97%; the limiter is a margin gate that folds 44% of cycles, not draft quality.
- Don't reach straight for a bigger block to "do better." Drafting more tokens per verify is a much stronger bet on predictability, and the compounding rejection risk is real — measure it before assuming it wins.
Also in this series: Part 2 — Running a 15 tok/s 284B as your daily agent brain: the settings that make it bearable · Part 4 — My 284B agent quietly stopped reusing its KV cache: the ds4 evict storm · Upstream: ds4 PR #371
FAQ
- Is depth-1 MTP speculative decoding lossless?
- Yes — byte-identical. The draft (MTP-1 drafts one token ahead, ds4 PR #371) only changes how fast tokens come out, never which tokens they are. I verified the output is identical with and without the draft. Speculative decode is a speed optimization, not a quality one; if it changed the output it would be a bug.
- Why does MTP-1 speed up code but slow down free prose on a GB10?
- Because decode here is verify-bound: one verify pass is ~108ms and a draft is ~4ms, so a drafted token that gets accepted is nearly free and one that gets rejected is a verify you paid for and threw away. Code, JSON and tool calls are predictable, so drafts get accepted (+6.5% code, +9.4% agent). Free prose and chat are open-ended, so drafts get rejected more often and you eat the wasted-draft cost (−3.6% prose, −3.7% Chinese chat).
- Should I enable speculative decoding globally on DeepSeek-V4-Flash?
- No. It is a workload-dependent trade, not a global faster switch. Turn MTP-1 on for code, agent and tool-use workloads where it wins +4 to +9%. For everyday chat and creative writing either accept the small −4% cost or route that traffic to the non-thinking deepseek-chat path (see Part 2). Set the flag by workload class, not once globally.
- Can you tune depth-1 MTP to go faster?
- Not much. Once a cycle commits, ~97% of drafts are accepted — the drafter is already excellent. What holds the average speedup down is a margin gate that skips speculating entirely on ~44% of cycles when the model's confidence is thin. So the limiter isn't draft quality you can improve; it's a conservative gate that folds most of the bad bets before they cost a verify. The only lever that would move it is drafting more than one token per verify — a bigger, separate bet with its own tradeoffs.
Read next
- 2026-07-05[Local LLM] My 284B agent quietly stopped reusing its KV cache — the ds4 evict storm that re-paid prefill every turn
A month after wiring DeepSeek-V4-Flash into a daily agent, it felt slow again. Two log lines explained it: the disk-KV cache was evicting live prefixes (hits=0), and tool-call turns never saved a checkpoint — so common=268 out of 14209 and every turn re-paid full prefill. The fix: 256G KV budget + PR #489.
- 2026-06-12[Local LLM] Weights win: a 284B crushed to 2-bit still beats the small model that fits
DeepSeek-V4-Flash (284B) only fits a 128GB box at asymmetric Q2 (~80GB). Sounds like suicide quantization — but it's surgical: only the layers that barely affect quality get cut. As a daily agent it ran 280 turns with zero degradation. Big enough weights survive 2-bit.
- 2026-06-12[Local LLM] Running a 15 tok/s 284B as your daily agent brain — the settings that make it bearable
A 284B model at 15 tok/s, wired into a daily agent. Two sets of settings make it comfortable — server-side and agent-framework-side. --no-mmap cuts cold start to 57s, the KV disk cache halves prefill, and one missing context_length will crash the whole session.
- 2026-06-12[Local LLM] My first Q2 model looked broken on a 128GB box — the real culprit was a parser that couldn't read DSML, not the quantization
DeepSeek-V4-Flash is 284B. I got it onto a single 128GB GB10 with antirez's ds4 engine and an asymmetric Q2 GGUF at 15.6 tok/s. The fun part: the broken tool calls weren't the 2-bit quant's fault. The runtime just couldn't parse DSML.
Don't miss the next one
Subscribe, and you won't.
One-click unsubscribe anytime.