自研RDNA高併發推論引擎 以AI Max+ 395為範例
-
趁Qwen4 27B出來前先開源分享這個
連結分享 https://github.com/dardeaw/MBufo
命名為MBufo:從gufo模改出的Mixed Batch推論引擎,支援主流的gguf雖然現在strata當紅,但strata並不具備高併發能力
我已有兩台strata主機,速度跟智商也不錯,但有個絕對致命傷 - 只適合單流對話
一遇到多對話就得排隊,完全不適合做為服務,
strata這種推論框架只建議用高性價方案去簡單拼湊就好,不要花大錢,多對話排隊的體驗不佳,
真正的高併發,在於總吞吐量要隨著對話數量提高,並且不同對話之間不能有過久的等待,
手上還有AI Max+395,為了展現他的價值,我開啟了手搓推論引擎之旅,
兩個月前因Halogen的專用引擎效率很好,曾經試著魔改llama.cpp成自製引擎想要跟Halogen比拚效能,拚了兩天就投降因為halogen確實先天上就贏llama.cpp太多了一直到了gufo的出現
gufo發布約晚halogen三週,但他開源呀!!
我們先談談Halogen最大的缺點,要把他取代掉就得從這邊下手
第一,它是黑盒。docker拉來跑,只能調環境變數,裡面長什麼樣全靠猜。想加模型?此路不通,想加功能?門都沒有。
第二,它卡死的點是結構性的,排程的機制、KV的量化機制全部他說的算。
第三,幾乎無高併發能力,除了預訂了四個slots做緩存增量快取與舊對話落盤SSD,其餘都是單對話思維做的設計。以 gufo為底進行改造。理由就一個:看得見、改得動,
它的基底是半套高併發理由如下:
1.它有batch但不是mixed batch,他有chunked prefill但不會左手prefill右手decode
2.它的排程與插隊只有先進先出,跟llama.cpp、strata也一樣
3.它的KV機制是fork的增量快取,類似較粗的radix tree,若把增量快取機制來比喻,SGlang是樹葉級、gufo是樹枝級、而llama.cpp、strata、halogen等都只是各別獨立的樹幹各自做增量快取。MBufo
針對以上經驗,專為 AMD Strix Halo 打造的 gufo 分支,
定位為公平性+高效低銷的推論引擎——排隊不插隊靠公平調度,花費少靠低精度計算。上游 gufo 負責單路極限效能;MBufo 真的做到服務端的問題:一台 Strix Halo 節點同時面對十六路請求時能跑多滿,每一路又能吃多長的上下文?三根支柱回答它——負載下公平的排程(§1)、更高壓縮的KV快取(§2)、一個 port 服務多顆模型的 GGUF覆蓋(§3)。底層引擎、核心與絕大部分程式碼都來自上游,在此致謝 gufo-org 及所有貢獻者。
而同為RDNA3/4家族的7900XTX、R9700應該也能稍做修改就相容(但以VRAM為基準無法合併系統RAM使用),
甚至能魔改出雙卡TP,無奈我手上沒有設備能開發測試。MBufo 三個數字
# 數字 含義 1 短請求 TTFT 0.7 秒 被 25 萬 token prefill 卡住的短請求,原本要等 3.4 秒;公平排程後只要 0.7 秒(fairness-A 160 → 7.32、fairness-B 856 → 191,ITL 不變,貪婪輸出位元一致;v0.25.3)。 2 KV 記憶體省一半 blocked-Q8 快取讓 262144 token 的 session 從 6.44 GB 降到 3.42 GB(K4V4 為 1.81 GB),代價是量出來的、不是假設的(v0.25.2)。 3 11 個 GGUF 家族 一個 HTTP port 全數服務——v0.28.0 新增 8 個可用家族,加上 Flash-Next、27B、Gemma 4(見§3 模型總表),陸續新增中。 §1 高併發(架構差異)
併發不是一個數字。一台吃重的伺服器能不能用,是兩件事決定的,直接影響使用上的體感:
- ITL(token 間延遲)——請求已經在串流之後,它前後兩個 token 之間的間隔。 批次效率再高,只要會讓一條會話凍住一整個 prefill 步驟,那就不叫服務,那叫排隊加上額外手續。
- 公平性——沒有任何 session、客戶端或 prompt 可以讓別的對話等不到。一段 25 萬 token 的 prompt 插進對話中途,不該比十六路短對話得到更多資源。
原先gufo的排程器骨架已經是對的:prefill chunk 有上限、有待跑decoder 時先服務 decode 再做 prefill、admission 有每客戶端上限。它缺的是「便宜地同時兌現這三件事」:一個有上限的 chunk 仍然吃掉一整個 tick,而那個 tick 裡沒有任何 decoder 產出 token——因為 chunk 與 decode 是兩趟分別掃過權重的計算。ITL 與公平性就是從這個 tick 漏掉的:每一輪,串流中的請求都要付一次與它無關的 prefill 步驟。
MBufo 把兩者合併:chunk 與 decode 列共用同一個
ForwardBatch、同一個注意力核心,於是 prefill 的那個 tick 也順便把該出的 token 全部產出。合併沒有繞過公平政策;公平政策正是讓合併安全的前提。統一 mixed-batch 介面 統一KV量化介面
以物件導向(OOP)實作各模型的引擎,使得所有支援的模型都能享受到Mixed Batch的好處與支援各種KV量化
公平性:排隊不插隊(SRTF+飢餓 decode 優先搶佔+near-done 閘門)
長 prefill 曾把短請求的 TTFT 擠爆(5 進 4 反飢餓場景)。三個機制修掉它,全程保持貪婪輸出位元一致(sha 比對通過:24K prefill 單跑與併發跑出相同 sha):
- SRTF prefill 選取——剩餘 ≤1 個 chunk 的 near-done prefill 排在長 prefill 續片前面(同級按 FIFO)。
- 飢餓 decode 優先搶佔——有請求在排隊等 session 槽位時,長 prefill chunk 讓路, 先把常駐 decode 排空,好讓等待者一有常駐完成就被接納。
- near-done 閘門——只有當某個常駐 decoder 距
token_limit≤64 token(槽位即將 空出)才觸發搶佔;若常駐全是長輸出 decoder,就不做無意義的 prefill 延遲。光是這個 閘門就把 fairness-A 從 76.5 拉回 7.32。
投機解碼(MTP / DFlash)
- Qwen Flash-Next MTP——併發寬度 2/3/4 的接受率 ** 88.7/91.6/89.5%**。接受率不再隨 batch 衰減,本構建
穩在 ~90%——各寬度總吞吐全面超過上游(97/111/133 對 70/105/112)。 - Qwen 27B DFlash2——支援 blocked-Q8 KV(verify 寫進 blocked sidecar,continuation快取與 serve 磁碟身分位元級攜帶); decode(short/prose/code/json 22.9/19.5/56.2/52.3 tok/s)。
- Muse Glimmer DFlash——端到端投機草稿 ~89%。
- Gemma 4 MTP——async-GPU 草稿重寫+單 forward verify 之後,decode 達 74–86 tok/s
多 sessions 生產配置範例 (以Strix Halo 128G搭配 Qwen Flash Next為例)
目標 設定 16 路、高併發 --sessions 16 -c 65536 --kv-quant q8(約 103 GB,餘 20 GB)8 路、長對話 --sessions 8 -c 131072 --kv-quant q8(約 101 GB,餘 21 GB)單路、最大上下文 --sessions 1 -c 262144 --kv-quant q84 路、最大上下文 --sessions 4 -c 262144 --kv-quant q8(約 101 GB,餘 21 GB——總位元組與 8×131072 相同)單路、最快最精準 prefill --sessions 1 -c 262144 --kv-quant f16(全精度 KV;每位置最重,但單流裝得下)還原上游排程 環境變數 GUFO_MIXED_BATCH=0排程器保證什麼
保證 機制 待跑 decoder 絕不排在 prefill 之後 只有在沒有 decoder 待跑時(或正在湊第一批時)才進合併步驟,所以 prefill 只在空隙裡跑,永遠不會插隊到串流請求前面。 chunk 不能把 decoder 擠出輪替 每次合併或 prefill 步驟後, MarkAllDecodersDue會把所有常駐 decoder 重新標記為待跑,下一步就全部服務。任何 prompt 都無法獨佔裝置 chunk 是有上限的切片( --prefill-chunk預設 512 token),25 萬 token 的 prompt 每輪只餵一片。同等的 session 輪流 decode 佇列會輪替( PopDecoder把服務過的請求移到隊尾),不是固定隊頭順序,所以沒有哪個 session 能一直贏得前排。單一客戶端無法塞滿佇列 --max-pending-per-client限制單一客戶端的待處理請求(回client_quota),出隊也跨客戶端輪流,一個客戶端爆量不會餓死別人。某一層拒絕也不損失 每一層都可獨立降級;投機列被拒就退回原本路徑:正確,只是沒有加速。 多模型 router
一個 port、多顆模型。
serve llm --multi-model把伺服器變成模型 registry:啟動模型成為預設,每個請求依model欄位路由到對應模型。模型可在執行期增減(admin API)——不重啟、不斷線。§2 提供更多壓縮精度(成本差異)
模式 狀態 說明 f16預設 基準數值。KV 快取不做量化。 q8支援 Blocked 8-bit,每 32 個元素配一個 f16 尺度(34 位元組)。 q8+GUFO_KV_V4=1手動開啟,K8V4 4-bit value 打包成 18 位元組,key 維持 8-bit。 q8+GUFO_KV_Q4=1手動開啟,K4V8 4-bit key 打包成 18 位元組,value 維持 8-bit。 q8+ 兩者同時手動開啟,K4V4 key 與 value 都是 4-bit。 建議使用
q8。 blocked 模式在編解碼層級是位元精確的;f16仍是預設與基準。4-bit 路徑是給「KV 記憶體成為瓶頸」的機器手動開啟的環境變數鉤子,不是--kv-quant的格式選項,也不會改變任何預設值——未設定時引擎與不含這些路徑的版本位元相同(以 logit dump 雜湊比對驗證)。完整說明見 docs/KV-V4.md。佔用
每個 KV 位置的位元組數,以及
-c 262144、Qwen3.8 Flash-Next 12 個注意力層下單一 session 的總量:模式 每位置位元組 262144 單一 session f162048 6.44 GB q81088 3.42 GB K8V4 / K4V8 832 2.62 GB K4V4 576 1.81 GB 代價(量出來的)
以
q8為基準的正確性:三個互不相關的 400-token 上下文、各 98 步matched-token decode、對三個上下文取平均:模式 decode KL decode 最大 KL 貪婪 argmax 一致率 K4V8 0.0214 0.258 90.5% K8V4 0.0209 0.120 93.2% K4V4 0.0335 0.411 89.8% 支援模型權重精度:W8A8/ROCmFP4/MXFP4/Q4_K
逐模型精度表
模型 權重精度 KV Qwen3.8 Flash-Next ROCmFP4-FAST(4.25 bpw)或 UD-Q4_K_XL;decode Q4_1 拷貝(+17.4%) blocked-Q8( --kv-quant q8);MTP Q8_0 sidecarQwen3.8 27B UD-Q4_K_XL(建議)或 ROCmFP4-FAST blocked-Q8(含 DFlash2; QWEN_KV_QUANT、--kv-quant覆寫)Gemma 4 26B-A4B Q4_0;Q4→Q8 dense 一次性預轉(每 chunk 省 210 次反量化啟動) SWA 層共用 Q8(prefill −2.8%、decode −6.4%) Qwen3.6-35B-A3B Q6_K→Q8_0 載入;split-K router GEMV 僅引擎/bench 路徑 GPT-OSS 20B/120B 原生 MXFP4 routed GEMM text 後端服務路徑 Muse Glimmer 30B W8A8/Q8_0;MQB-first 注意力 serve 後端 --kv-quant旗標Llama-3.1-8B dense GQA(見模型卡) text 後端服務路徑 Qwen3-Embedding-0.6B dense Qwen 注意力 prefill-only single-prefill Embed bge-m3 Q4_K_M loader;逐形狀 autotune prefill-only /v1/embeddingsbge-reranker-v2-m3 共用 rerank 評分頭 padding ScoreBatch(超目標 +15%)Qwen3-Reranker yes/no head,Qwen 分派 純評分 對比 llama.cpp(v0.28.0,gfx1151)
同權重、release build、greedy;prefill=冷 KV 單流 tok/s,decode=開投機 tok/s。正數=MBufo 較快。六格數字皆為 CHANGELOG 量測到的 v0.28.0 開發期數字原文重述。
負載 Prefill 差值 Decode 差值 條件/備註 Flash-Next +52% 持平或更好 冷 KV、greedy、開 MTP Qwen3.6-35B-A3B +52.5% 持平或更好 split-K router GEMV decode;greedy bge-m3(長文件) +35~50% n/a(純 prefill) 長文件形狀、hipBLASLt autotune、快取執行器 Qwen3-Embedding-0.6B(長文件) +41~50% n/a(純 prefill) 長文件形狀、single-prefill Embed Reranker(批次評分) n/a 超目標 +15% padding 多序列 ScoreBatch GPT-OSS 120B +62% -17% 結構性差距,照實陳述:此路徑 decode 仍卡記憶體頻寬 此次版本推進未跑模型服務效能測試;上表為量測到的 v0.28.0 開發期數字重述,此處未重測。
§3 GGUF 相容(覆蓋承諾)
支援的模型(v0.28.0)
將經典模型架構都做出支援,除了LLM並且能載入Embedding與Reranker
Qwen3.8 Flash-Next、Qwen3.8 27B 、 Qwen3.6-35B-A3B 、Gemma 4、 GPT-OSS 20B/120B 、Muse Glimmer 30B、Llama-3.1、Qwen3-Embedding、bge-m3、bge-reranker-v2-m3、Qwen3-Reranker§4 效能測試 單對話基準(MBufo,以gfx1151 Strix Halo測試)
冷 KV(每請求唯一 prompt,
cached_tokens≈0)、think off、F16 KV、-j 1、
ctx 262144。四組設定:27B(UD-Q4_K_XL 對 ROCmFP4-FAST)+ Flash-Next(ROCmFP4-FAST
對 UD-Q4_K_XL)。投機:27B=DFlash2、Flash-Next=MTP。(註:舊中文版此節為 v0.24.1
數字,已同步為與英文版一致的 v0.25.5。)這些是單流數字,用來隔離模型與建置版本的選擇;負載下改變的是同時能跑幾條,那是
§1 高併發的故事。Prefill(tok/s,越高越好)
tokens 27B Q4_K_XL 27B ROCm FP4-FAST FN ROCmFP4 FN Q4_K_XL 2K 605 455 1739 1301 8K 615 564 1701 1549 32K 567 551 1598 1618 64K 508 496 1695 1678 128K 409 407 1504 1507 250K — — 1438 1415 Decode(tok/s,投機開)
標準:5 個冷 KV 情境(標明 temp)+ 8 任務 ReAct 代理套件。
情境 27B Q4_K_XL 27B FP4-FAST FN ROCmFP4 FN Q4_K_XL 散文 (temp 0.4) 23.5 19.7 43.3 43.6 費波那契 (temp 0.4) 67.9 56.2 86.3 84.7 JSON 約束 (temp 0) 55.1 46.5 51.5 51.7 貪心程式碼 /128 (temp 0) 61.9 55.3 70.5 73.2 重複文本 /256 (temp 0) 70.6 60.8 74.8 75.3 代理任務(agent_bench_v2,t1–t8,沙箱工具)
27B Q4_K_XL 27B FP4-FAST FN ROCmFP4 FN Q4_K_XL 通過 8/8 7/8 7/8 7/8 核爆(須為 0) 0 0 0 0 生成 tps 區間 9.1–31.1 9.3–21.5 16.7–56.6 16.8–55.1 §5 效能測試 高併發測試
三引擎投機併發比較表 — Qwen3.8 Flash-Next
引擎:A Halogen 0.18.1(FN v2,
.hgn)/B gufo-upstream 0.21.0+FN Q4_K_XL+MTP/C MBufo v0.25.3+FN ROCmFP4+MTP。FN 投機器=MTP。① Decode 總吞吐 total_tps(N=1/2/3/4 併發)
引擎 N1 N2 N3 N4 A Halogen 84.9 81.6 75.3 87.8 B gufo+Q4 57.3 64.0 108.4 127.1 C MBufo+ROCmFP4 66.0 82.8 110.2 128.5 ② 平均每 session decode_tps
引擎 N1 N2 N3 N4 A Halogen 84.9 41.3 25.4 22.3 B gufo+Q4 57.3 32.2 36.9 32.9 C MBufo+FP4 66.0 41.6 38.2 32.8 ③ MTP 接受率(batch_width 2/3/4,server 端):Halogen只在單流時投機,多併發完全沒有增益
④ Prefill 總吞吐(64K 冷,N=1/2/3/4)引擎 N1 N2 N3 N4 A Halogen 840 1687 1662 1714 B gufo+Q4 1588 1545 1554 1559 C MBufo+FP4 1612 1582 1570 1572 ⑤ Fairness 退化比(場景 A 混長文/場景 B 混 4K,越低越好):A 322/1140|B 15.3/399|C 18.9/187
⑥ ITL mean/p95/max(ms,注入 4K prefill):A 83/341/738|B 49/93/501|C 43/68/459
判讀
- 單流 decode:A(halogen)最強 84.9(NPU+獨占 MTP),但 halogen 只在獨占時投機,一旦併發即關投機頭 → per-session 崩到 22–25、總吞吐停滯(75–88)。
- 高併發 decode:C(MBufo)最佳——per-session 平穩 33–42、總吞吐線性到 128.5、N3–N4 反超 B;B 次之;A 最差(投機 off)。
- Fairness:MBufo 場景 B 187 最佳
- 結論:單發求極限速度選 Halogen;併發/代理/多工實戰選 MBufo。
§6 Qwen3.8 27B 高併發測試
① Decode 總吞吐 total_tps(N=1/2/3/4 併發)
引擎 N1 N2 N3 N4 A Halogen+dflash2 48.0 48.2 47.1 47.0 B gufo+DFlash2 60.4 73.0 73.4 84.0 C MBufo+DFlash2 61.4 74.5 73.6 85.7 ② 平均每 session decode_tps
引擎 N1 N2 N3 N4 A Halogen+dflash2 48.0 24.1 15.7 11.75 B gufo+DFlash2 60.4 37.7 25.5 21.6 C MBufo+DFlash2 61.4 38.4 25.6 22.0 ③ Prefill 總吞吐(64K 冷,N=1/2/3/4)
引擎 N1 N2 N3 N4 A Halogen+dflash2 423 425 419 416 B gufo+DFlash2 462 449 447 452 C MBufo+DFlash2 470 460 459 461 ④ Fairness 退化比(場景 A 混長文/場景 B 混 4K,越低越好):A 187/34.3|B 200/1832|C 167/212
⑤ ITL mean/max(ms,注入 4K prefill):A 49/144|B 92/1437|C 91/1408
判讀
- 結論:27B 投機態下 C(MBufo v0.25.6)綜合最佳——單流最快、高併發擴展最好、fairness 搶佔領先;A(halogen)僅單流 ITL 平順但高併發無擴展;B(上游)decode 接近 C 但 fairness 場景 B 差 8.6×。
結論
llama.cpp並沒有針對RDNA運算做到最佳的優化(預設完全沒用到wmma矩陣加速)
sglang對gguf的支援太爛、用AWQ、GPTQ又造成較大的內存開銷,而且對A卡的性能釋放不利
strata沒有高併發魔改的先天條件
為改善使用體驗,以此自製做為範例,若有興趣的可以試著一起開發魔改下去