vLLM Speculative Decoding 最容易被誤解成「小模型先寫,大模型少算幾次」;其實大模型仍會驗證候選 token。那為什麼還可能更快?2026 年 9 月 12 日,圍繞 vLLM 在 AMD GPU 上的技術報告,Hacker News 討論串已有 143 points、54 則留言,讀者追問的正是這個問題,以及資料中心 GPU 的結果能否套到消費卡。
這篇不給一個脫離硬體的「必開」答案,而是帶你用 Qwen3-8B+DFlash 建立同條件 A/B:固定模型 revision、prompt 形狀、輸出長度、sampling、batching 上限、流量條件與版本,再比較吞吐、TTFT、TPOT、acceptance、VRAM 和失敗率。下文引用的成績會明確標成原報告作者公開測量;實作段則是可搬到你自己相容 GPU 的驗收流程,不把不同硬體的結果寫成 AlphaLab 重現。
先記住這條判斷式:Speculative Decoding 淨收益 = 省下的逐 token target 解碼時間 − draft、批次驗證、排程與記憶體代價。Acceptance rate 只決定第一項的一部分,不是最終答案。
先說結論:先量 workload,再決定要不要開
⚡ 三句話版:
一、Target 不是跳過驗證,而是一次評估一小段候選,嘗試把多個序列步驟攤在一次 forward pass。
二、Acceptance 高仍可能變慢;真正要看的是 throughput/TPOT、TTFT、VRAM、錯誤與任務品質。
三、先從小 N 開始掃描;若高併發、低接受 workload 或額外 draft 權重吃掉服務容量,就對那條流量關閉。
- 值得優先試:decode 佔比高、中低 QPS、互動式長輸出,而且相容的 draft/MTP 已有現成 checkpoint。
- 先不要上線:連 baseline 都還沒固定、VRAM 沒有餘裕,或只看一個官方倍數就準備改 production。
- 完成定義:同一工作負載連跑至少三次,以中位數通過你的 SLO;同時保留 acceptance、VRAM 與錯誤資料,才能解釋結果。
本文說的「浪費 VRAM」是條件式的機會成本:額外 draft state 壓縮了 KV cache 或最大 concurrency,卻沒有換到足以通過 SLO 的吞吐/延遲收益。它不是「開啟後固定多占某個 GB 數」,更不是官方已量到一個通用門檻。
vLLM Speculative Decoding 原理:驗 7 個候選,為何可能比生 7 次快?
一般 autoregressive decode 每輪只確定下一個 token:Target 模型讀取權重與 KV cache、算一次、提交一個 token,再開始下一輪。這種逐步依賴不能把七個未知的未來 token 直接平行生成。
Speculative Decoding 加入較便宜的 Drafter。假設它先提議 A→B→C→D,Target 就用一次帶有多個位置的驗證計算,評估這串候選在每個位置是否可接受;系統提交最長的可接受前綴,在第一個拒絕點修正,再進入下一輪。換句話說,Target 仍是裁判,但不必每判一個 token 都重新走一次完整的序列迴圈。

快的來源不是「免驗」,而是硬體對一小段候選做批次評分時,可能比連續啟動多次單 token decode 更有效率,尤其 baseline 受權重搬移與序列步驟限制時。原始 Speculative Sampling 論文用修正後的 rejection sampling,在硬體數值精度範圍內維持 Target 的輸出分布;這不等於兩次服務一定產生 byte-for-byte 相同文字,因為浮點運算、batch 與實作路徑仍可能帶來數值差異。
Acceptance rate 與 MAL 到底差在哪?
- Draft acceptance rate(AR):被接受的 draft token ÷ 提議的 draft token。它回答「猜中比例」,不包含每輪額外提交的 bonus token。
- Mean acceptance length(MAL):vLLM 的定義是 1 + accepted draft tokens ÷ verification steps。它回答「平均一次驗證前進幾個 token」。
- Per-position acceptance:第 1、2、3…個候選在所有驗證輪中成為可提交前綴的無條件比例。固定每輪提議 N 個時,
MAL = 1 + Σpᵢ,而 aggregateAR = Σpᵢ ÷ N;後段快速下滑,就表示拉長 N 會加入更多低命中位置。
截至 vLLM 0.29.0,每請求 acceptance metrics可用 --per-request-spec-decode-metrics summary 開啟,但這個介面仍標為 experimental,且只在單序列 n == 1 回傳。正式 A/B 可先用 vllm bench serve 從伺服器 /metrics 前後差值取得整批 acceptance,避免為 baseline 加上一個它不能使用的旗標。
MTP、EAGLE-3、DFlash 怎麼選?先看「猜的成本」
不同方法都叫 speculative decoding,成本結構卻不同。Native MTP 使用 Target 內建的 multi-token prediction 模組;vLLM 的 AMD 報告指出,它在該實作中不另載一個獨立 draft checkpoint,部分 embedding/output 元件也可共享。EAGLE-3 以 Target feature 做序列式候選;DFlash 用 block diffusion 平行草擬多個位置;DSpark 則結合平行預測與較輕的修正。
EAGLE-3、DFlash、DSpark 與 Gemma 4 MTP 的公開測試組合會載入額外 draft weights;vLLM 0.29.0 的 KV cache manager也會為未驗證 draft 與部分 proposer 的 lookahead 暫時配置 slots,只把已驗證 token 納入可重用 cache。實際 VRAM 增量仍受 checkpoint 大小、精度、tensor parallel 與 runtime buffer 影響。因此不能只寫「Speculative Decoding 固定多吃 X GB」,也不能把 native MTP 的記憶體特性套給所有 drafter。
這篇選 Qwen/Qwen3-8B+Qwen3-8B-DFlash-b16,理由不是宣稱它是冠軍,而是 vLLM 已公開相容設定、proposal sweep 與失敗案例,適合教你看懂 N、AR、MAL 與吞吐的拉扯。DFlash 官方文件仍標示 active development,並提醒並非所有硬體組合都已驗證;若你的模型有原生 MTP,也應把 MTP 放進同條件候選。
這個 DFlash checkpoint 的 model card 明列用於關閉 thinking mode。若 production 走 chat template,baseline 與 speculative 兩邊都要固定相同的 enable_thinking=false 設定,不能把 thinking on/off 混成 drafter 效果。
vLLM 部落格數據先拆雷:81.3% acceptance,吞吐仍只剩 0.80×
署名 AMD and Embedded LLM 的作者在 2026 年 8 月 23 日把測量發布於 vLLM 官方部落格。Qwen3-8B 等多數案例在配有 8× AMD Instinct MI300X 的平台執行;MiniMax M3 另用配有 8× MI355X 的平台。附錄中的 Qwen3-8B serve command 沒有 TP/DP 旗標,因此這裡不把平台卡數解讀成該案例必定由八卡共同推論。軟體環境包含 Ubuntu 22.04.5、ROCm 7.2.53211,以及開發版 vLLM 0.23.1rc1.dev1120+g0f0f28b53。這不是消費級 AMD 卡測試,也不是下文採用的 vLLM 0.29.0;數字只能解釋原測試組合,不能當你的預測值。
這份報告公開的是 aggregate output-token throughput 與 acceptance 附錄,文章原始檔與同目錄資產未附 raw benchmark logs、request 數、實際 batch/concurrency、TTFT、TPOT 或 VRAM telemetry。Qwen3-8B 的例示 command 也只在 DFlash/DSpark 設 max-num-batched-tokens=16384,baseline/EAGLE-3 沒設同一旗標。因此下圖只轉錄附錄的指定 rows;後面的自測流程則刻意讓兩邊所有非 speculative 參數一致。

第一個反例說明,猜中第一個候選的比例很高,仍可能付不起 drafter 與驗證開銷;第二個反例則說明,較長 proposal 可以讓 MAL 上升,卻同時做更多最後被拒絕的工作。你真正要最大化的是符合 SLO 的端到端效益,不是 AR、MAL 或 N 的單一最大值。
實作前準備:先把版本、硬體與信任邊界鎖住
以下流程以 2026 年 9 月 12 日的 vLLM 0.29.0 release 為基準。該版預設使用 Model Runner V2,但 release notes 明列某些 speculative methods 仍會 fallback 到 MRV1;所以除了版本號,也要保存啟動 log 實際選到的 runner。先確認三件事:
- 平台相容:依 vLLM 的硬體支援與該 draft checkpoint model card 核對 GPU、ROCm/CUDA、精度與方法;不要從 MI300X 報告推定消費卡可用。
- 容量足夠:Target baseline 能穩定啟動後,仍要留出 draft weights、runtime buffer 與 KV cache 空間。
- revision 固定:下方使用 2026-09-12 取得的兩個 Hugging Face commit SHA;未來若改 revision,視為另一個實驗,不混在同一組中位數。
# 先依官方 release 選 CUDA/ROCm 安裝物,再確認實際版本
vllm --version
# 這兩個選項都要出現在目前環境的 help
vllm serve --help | grep -E "speculative-config|revision"
若你使用 NVIDIA CUDA,可把 0.29.0 release 的 uv 指令改寫成可重現的鎖版形式:uv pip install "vllm==0.29.0" --torch-backend=auto;AMD ROCm 使用者則應從同一 release 頁選該版 ROCm wheel 或 vllm/vllm-openai-rocm:v0.29.0 映像。不要把 CUDA 指令原封不動套到 ROCm。
五步 A/B:Baseline 與 DFlash 只差一個變因
步驟 1:寫下控制變因與通過門檻
先建立實驗卡,記錄 GPU 型號與數量、driver/ROCm/CUDA、vLLM 版本、runner、Target/Draft SHA、dtype、tensor parallel、max-model-len、max-num-batched-tokens、gpu-memory-utilization、dataset、prompt/output 長度、temperature、request rate 與 concurrency。漏掉其中一項,往後就很難知道差異來自 speculative decoding 還是環境漂移。
門檻要先寫,才不會看到漂亮數字後移動球門。例如互動服務可要求「p50 TPOT 至少改善 10%,p99 TTFT 不超出既有 SLO,任務分數與成功率不退步」;批次服務可要求「output throughput 至少 1.10×,且額外 VRAM 不降低目標 concurrency」。10% 與 1.10×只是示範門檻,請換成你產品的成本與 SLO。
步驟 2:啟動 Baseline,先證明 Target 自己穩定
以下 Target revision 是 2026-09-12 的快照。若硬體需要 tensor parallel,兩邊必須加上相同的 --tensor-parallel-size;不要只改 speculative 那一邊。
vllm serve Qwen/Qwen3-8B \
--revision b968826d9c46dd6066d109eabc6255188de91218 \
--max-model-len 4096 \
--max-num-batched-tokens 16384 \
--gpu-memory-utilization 0.85
等 /v1/models 健康回應後,先記錄 idle VRAM,再跑一次短 smoke request。Baseline 若已 OOM、回應錯誤或輸出長度不符,先修 baseline,不要急著加入 drafter。
步驟 3:跑固定低併發與高併發 workload
先用 random dataset 固定 token 形狀,確認量測管線;它不代表你的真實 acceptance。下方低併發測試把輸入固定 512 tokens、輸出固定 256 tokens,明確指定 temperature 0,因為 0.29.0 的 bench 不再預設 greedy。每個設定跑三次,保留 JSON 並比較中位數。
LABEL=baseline-qps1-run1
mkdir -p results
vllm bench serve \
--backend openai \
--base-url http://127.0.0.1:8000 \
--model Qwen/Qwen3-8B \
--dataset-name random \
--input-len 512 \
--output-len 256 \
--num-warmups 20 \
--num-prompts 200 \
--request-rate 1 \
--max-concurrency 1 \
--temperature 0 \
--ignore-eos \
--save-result \
--save-detailed \
--metadata config=baseline load=qps1 \
--result-dir results \
--result-filename "$LABEL.json"
再把相同參數跑成壓力測試,只改 --request-rate inf --max-concurrency 16,檔名與 metadata 改成 load=concurrency16。這能分開回答「單人生成是否變順」和「多人同時使用時總容量是否增加」。若你的服務 concurrency 不是 16,就用實際流量值。
步驟 4:完全重啟程序,只加入 DFlash N=7
停止 baseline server,確認顯存釋放,再用相同 Target 參數啟動 DFlash。Draft revision 同樣鎖在 2026-09-12 快照;num_speculative_tokens=7 是 sweep 起點,不是通用最佳值。
vllm serve Qwen/Qwen3-8B \
--revision b968826d9c46dd6066d109eabc6255188de91218 \
--max-model-len 4096 \
--max-num-batched-tokens 16384 \
--gpu-memory-utilization 0.85 \
--speculative-config '{"model":"z-lab/Qwen3-8B-DFlash-b16","revision":"9b41424b7109f9c5413454f481b09a82b85333f4","method":"dflash","num_speculative_tokens":7}'
把步驟 3 的兩種負載原樣重跑,只把 LABEL 與 metadata 的 config 改成 dflash-n7。接著依序測 N=3、11、15,每換一個 N 都重啟 server;四個 N 之外的參數不得漂移。這就是 proposal sweep。
步驟 5:同時收 throughput、latency、acceptance、VRAM 與品質
vllm bench serve 的 JSON 會保留 request/output throughput、TTFT、TPOT、ITL、errors,以及從 Prometheus counters 計算的 speculative acceptance。Acceptance 是該 server/port 的 process-wide /metrics 前後差值;量測期間要隔離這個實例,避免其他流量污染 counters。顯存則在另一個終端機監控並留檔;AMD 可依 AMD SMI 官方用法執行:
# AMD:觀察 idle、載入後與 benchmark 峰值,並保存 120 秒紀錄
amd-smi monitor --vram-usage --process --watch 1 --watch_time 120 \
| tee results/amd-vram.log
# NVIDIA:每秒記錄各 compute process 的顯存;測完按 Ctrl-C
nvidia-smi \
--query-compute-apps=pid,process_name,used_memory \
--format=csv -l 1 \
| tee results/nvidia-vram.csv
- 速度:
spec output throughput ÷ baseline output throughput;互動服務另看 TPOT/ITL,不能用總吞吐代替體感。 - 啟動與排隊:看 TTFT 的 p50/p99;高併發吞吐變高,尾端等待仍可能惡化。
- 接受行為:看 AR、MAL 與 per-position curve,找出 proposal 後段何時只剩低命中工作。
- 容量:
spec peak VRAM − baseline peak VRAM,並確認相同 concurrency 不 OOM;只看 idle VRAM 會漏掉 runtime 峰值。 - 正確性:random dataset 只驗收管線。最後一定要換成合法、去識別、能代表 production 的 prompt set,固定評分器,另存 task score、成功率與錯誤類型。
解析 0.29.0 JSON 時還有一個單位陷阱:spec_decode_acceptance_rate 是 0–100 的百分比,spec_decode_per_position_acceptance_rates 卻是 0–1 的 fraction。先統一尺度再畫圖,否則同一批結果會被看成相差一百倍。
想補強「Runtime A/B 怎麼留證據」,可接著看本機 LLM 五關 A/B Test;若 KV cache 與記憶體容量仍不熟,先讀KV Cache 隨機淘汰評測。這兩篇會把輸出 parity 與記憶體指標拆得更細。
故意找失敗:低 acceptance 與高併發各跑一輪
不要先用「數學題、程式題或創作題」猜哪一類 acceptance 低。先在代表性資料上量 per-request/per-bucket acceptance,再把實際較低的一組獨立重跑。這能避免用題材刻板印象取代資料,也能看出 drafter 是否只熟悉某種 prompt 分布。
- 低 acceptance bucket:固定輸入/輸出與 sampling,對照 baseline、N=3、7、11、15;若 N 拉長但 MAL 幾乎不動,就是 proposal 後段沒有回收成本。
- 高 concurrency bucket:用 production 峰值附近的 request rate 與 concurrency,加入 goodput/p99 SLO;batching 已充分利用 GPU 時,speculative 的相對優勢可能改變,方向必須實測。
- 記憶體壓力 bucket:逐步增加 concurrency 或 sequence length,記錄第一個 OOM/拒絕點;若 draft 讓 KV cache 空間縮小,吞吐小幅上升也可能換來較低最大容量。
若要先建立「引擎、模型、硬體餘裕、服務層」的全貌,回到LLM 推論引擎選型教學;若正在估算自架與 API 的成本邊界,可搭配本機 LLM 主機損益表。Speculative decoding 是 runtime 優化,不會替你修掉錯的容量模型。
vLLM Speculative Decoding 開還是關?用這棵決策樹

- 開啟:在目標 workload 的三次中位數通過預先寫下的 latency/throughput/goodput 門檻,品質與錯誤率不退步,VRAM 仍保有容量餘裕。
- 只對部分 route 開:互動式長輸出受益,但高併發或低 acceptance bucket 退步;用 workload routing 隔開,不要求全站一個設定。
- 縮短 N:前幾個位置 acceptance 高、後段快速下滑,而且較大 N 的 throughput 回落。
- 關閉:baseline 更快、SLO 變差、OOM/最大 concurrency 下滑,或 task score/成功率沒有通過。
- 改方法再測:模型有原生 MTP,或另一個相容 drafter 的成本更低;每換 checkpoint/method 都是新實驗,不能沿用上一組 acceptance。
七個常見坑:看起來公平,其實已換了題目
- Baseline 與 spec 用不同 batching:像只在 DFlash 加
max-num-batched-tokens,你量到的是兩個變因。公平 A/B 要兩邊一致。 - 只跑一次:下載、JIT、cache、溫度與背景程序都會擾動;先 warm-up,再取至少三次中位數。
- 只看平均 throughput:平均變快不代表 p99 TTFT/TPOT 過關,也不代表每位使用者都變快。
- 用 random tokens 宣稱 production 會加速:固定 token 形狀適合驗量測管線,acceptance 必須回到代表性 prompt。
- 把 greedy 文字完全相同當唯一品質閘門:浮點與 batching 可改變邊界 token;固定條件下若不一致,仍要記錄並調查,再同時比較任務分數、約束遵守、錯誤率與輸出分布。
- 忽略額外 VRAM 的機會成本:Draft 能載入不代表服務能承受;要看它是否排擠 KV cache、batch 或另一個 replica。
- 把資料中心卡外推到消費卡:核心、記憶體、driver、kernel 與支援矩陣都可能不同;MI300X 結果只能當方法示範。
若你還在補 Attention 與 KV cache 的底層觀念,四個 Attention 互動實驗能先建立直覺。想把這套量測變成完整學習路線,也可從 AlphaLab 課程依自己的基礎往下拆。
版本與時效:這篇流程何時要重跑?
只要 vLLM、ROCm/CUDA、Target/Draft revision、quantization、runner、sampling、GPU 或流量分布任一項改變,就重跑。尤其 0.29.0 的 per-request acceptance 介面仍是 experimental,某些 speculative methods 仍可能 fallback 到 MRV1;升級後先看 release notes、啟動 log 與保存的完整 config,不要只比較版本前後的一個 tok/s。
也不要把官方 2026-08-23 報告與你現在的 stable build 直接混表。最穩妥的紀錄單位是「硬體+driver+vLLM commit/version+兩個 model SHA+完整 serve/bench command+dataset digest+三次 raw JSON」。這樣結果才可追溯。
vLLM Speculative Decoding 常見問題 FAQ
1. Target 還是要驗證,為什麼可能更快?
因為一次 Target forward 可評估多個候選位置。它節省的是逐 token 的序列輪次與低利用率,不是取消 Target。只有省下的時間大於 draft 與驗證成本,端到端才會加速。
2. 開啟後輸出一定完全相同嗎?
不保證 byte-for-byte 相同。經典 speculative sampling 的目標是在硬體數值精度內保留 Target 分布;實際服務仍會受浮點、batch 與 kernel 數值路徑影響。用任務品質與約束驗收,不把字串完全相同誤當理論定義。
3. Acceptance rate 高,就代表一定變快嗎?
不一定。vLLM 的 Qwen3-8B/EAGLE-3/MBPP 公開測量就出現 N=1、AR 81.3%,吞吐只有 baseline 0.80×。Draft 成本、驗證效率、batch 與硬體利用率仍會決定結果。
4. num_speculative_tokens 愈大愈好嗎?
不是。後段 acceptance 往往與 workload 有關;若多提議的位置最後被拒絕,N 增加會讓工作量先上升。從小 N 掃到大 N,以 throughput/SLO 中位數選擇。
5. Speculative Decoding 一定會多吃一個 draft model 的 VRAM 嗎?
不一定。額外 draft checkpoint 類方法會帶來 weights 與 buffer 成本;native MTP 的指定實作可使用 Target 內建模組,不等同再載一個完整獨立模型。兩種都要量實際峰值與可用 KV cache。
6. 消費級 AMD GPU 可以照抄官方倍數嗎?
不能照抄。該份 vLLM 報告的公開環境是配有 8× MI300X 的平台,MiniMax M3 另用配有 8× MI355X 的平台;這不等於每個案例都用八卡共同推論。消費卡要先過目前版本的 backend、model、dtype 與 kernel 相容性,再跑自己的 A/B。
7. 高併發一定讓 speculative decoding 失效嗎?
不一定。高併發會改變 batching、排隊與硬體利用率,可能縮小、放大或翻轉收益;官方 AMD 報告也把更廣的 concurrency 與長度評估列為後續工作。答案只能由你的峰值流量測出。
8. 最少要保存哪些指標?
至少保存 output throughput、TTFT、TPOT/ITL、AR、MAL、峰值 VRAM、成功/錯誤與任務分數。再加完整 config、dataset digest 與三次 raw result;否則下次升級時很難知道快在哪裡、又犧牲了什麼。
給新手的 6 個重點
- Target 仍驗證;加速來自一次評估多個候選,而不是跳過大模型。
- Acceptance 是解釋指標,throughput/latency/goodput 才是上線指標。
- Baseline 與 spec 只准差 speculative config,其他參數與 revisions 全鎖定。
- N 要 sweep;最長 proposal、最高 AR、最高 MAL 都不自動等於最快。
- VRAM 要看 benchmark 峰值與最大 concurrency,不只看模型載入後的 idle 數字。
- 把功能按 workload route 開關,比追求全站唯一設定更實際。
接著閱讀
左右滑動查看更多推薦
結語:最佳設定不是最高 acceptance,而是通過你的 SLO
Speculative Decoding 是一筆交換:用較便宜的猜測與額外記憶體,換取較少的序列式 Target 輪次。它可以加速,也可以讓你在很高 acceptance 下仍變慢。把版本與 workload 鎖住、把 N 掃完、把峰值 VRAM 和錯誤一起保存,最後只讓通過 SLO 的 route 開啟;這比背任何一個官方倍數更接近 production 答案。






