第 7 章 — 進階批次處理策略

發佈於: 2026-04-29 最後更新於: 2026-07-08 版本: 1
第 7 章 — 進階批次處理策略

第 7 章 — 進階批次處理策略

LLM Primer VI:擴展 AI 系統》章節走讀的第七篇。這一章展示為什麼批次處理不是最佳化,而是讓受頻寬所困的 decoding 變得可解的關鍵動作 — 以及為什麼「批次」是動詞、不是名詞。


這一章為什麼存在

單一次 decode 步驟會從 HBM 讀取數十 GB 的權重,為的是產出一個 token。既然 GPU 反正都在串流這些權重了,它可以用同一步、幾乎零邊際成本地替許多請求各自產出一個 token。因此批次處理不是尋常意義下的最佳化 — 它是在受頻寬所困的硬體上讓 decoding 在經濟上可解的唯一辦法。但天真的批次做法一接觸真實世界就會塌陷,因為請求長短不一、完成時間也不一樣。第 7 章從那個差一點就成的天真方案,一路走到生產引擎實際跑的迭代級排程器,並替第 8 章即將要清償的那筆債務命名。

一句話總結:連續批次把「批次」從名詞變成動詞 — 序列在每次迭代都可以進入與離開 — 而在這麼做的同時,它把 KV 快取暴露成新的綁定限制。

7.1 靜態批次被最快完成者問題擊敗

靜態批次是每個人第一次都會寫的東西:收請求收到批次大小 B 或超時,以 S_max 長度對整批做 prefill,再跑 decode 迴圈,直到批次裡每個序列都吐出 EOS。兩項成本合起來是災難性的。Padding — 50 個 token 的提示詞跟 4,000 個 token 的提示詞放在同一批,它得替 80 倍於自己所需的 prefill 工作付錢。最快完成者 — decode 迴圈得跑到每個序列都完成,所以一個 20 個 token 的請求跟一個 2,000 個 token 的請求同批,會有 99% 的時間讓 31 個位子在產生會被丟掉的 token。平均吞吐量看起來還可以接受,但尾端延遲被批次裡碰巧含著的那個長請求主宰。動態批次(變動的超時,允許遲到者進入待處理批次)減緩了等待,但沒有改變本質方案;一旦 decode 開始,它就繼承同樣的最快完成者問題。

7.2 連續批次以迭代為單位排程,而不是以請求為單位

連續批次 — Orca 的迭代級排程、NVIDIA 的 in-flight batching、vLLM 與 TGI 的「核心把戲」— 是變數的替換。排程器不再把一個批次押在整個生成期間,而是每一次 decode 步驟都重新檢視批次組成。每一步之後:完成的序列離開它們的位子並釋放 KV;佇列裡的新序列進入釋放出來的位子;聯合的 decode 步驟在新的作用中集合上跑。LLM decoding 的兩項性質讓這件事可行。每一次 decode 步驟在結構上是同一個運算 — kernel 不在乎位子 7 跟位子 11 是哪個序列。而且每個序列各自帶著自己的 KV 快取,所以序列一離開,它的記憶體就變得可用。公平性的單位從請求變成迭代:一個 20 個 token 的請求不管批次裡還有誰,大約在 20 次迭代後完成;一個 2,000 個 token 的請求則佔用一個位子直到它需要多久都可以,不會綁死其他人。在真實的長尾流量上 — 短聊天輪與長 RAG 完成的混合 — 一顆 70B 模型的 GPU 利用率會從靜態批次典型的 10 到 20% 區間爬升到 60 到 80%,p99 延遲也會大幅收緊。

7.3 Chunked prefill 讓 prefill 與 decode 在同一顆晶片上共存

連續批次還留著一個張力。新到者需要 prefill,那是受制於運算的,喜歡每次跑很長的序列。在飛的序列需要 decode,那是受制於記憶體頻寬的,喜歡寬批次。在同一次前向傳遞裡對一段新的 4,000 個 token 的提示詞跑完整 prefill、又同時 decode 三十個進行中的序列,要嘛延遲那些進行中的 decode(對既有使用者的 TTFT 不好)、要嘛延遲新到者的 prefill(對新使用者的 TTFT 不好)。Chunked prefill 把 prefill 拆成小段 — 比方說一次 512 個 token — 並把這些小段跟作用中序列的 decode 步驟交錯起來。這時單一次前向傳遞同時帶著一些新提示詞的 prefill 工作與一些進行中的 decode 工作,兩個階段共用同樣的權重流。Prefill 那個受制於運算的性格吸收了算術;decode 對頻寬的需求則被攤到每個位元組更多的有用工作上。兩個階段在同一顆晶片上不再敵對。剩下的情況 — 流量大到它們還是會打起來 — 就是第 12 章解耦式服務的鋪陳。

值得記住:連續批次的吞吐量勝利是真的,而且它重新提出了記憶體問題。序列在每一步進入與離開,所以引擎沒辦法為每個位子預先配置一段 slab。取代 slab 的那個記憶體方案,得撐得住持續的准入與逐出 — 這就是為什麼要分頁。

第 7 章鋪陳出來的東西

連續批次做完它的工作,同時把 KV 快取暴露成並行度的綁定限制。每個作用中序列各自帶著自己的 KV,大小跟它目前的長度成正比;序列每一步進入與離開;引擎沒辦法事先知道它們每一個會有多長。天真的「每個位子一段 slab」的佈局會把批次處理的勝利大部分還回去。第 8 章把作業系統的解法搬過來:把快取切成小的實體區塊,用一個 page table 解耦邏輯 token 位置,並讓逐出策略在序列之間回收或共享區塊。PagedAttention 是讓連續批次的 KV 問題變得可解的動作。


下一篇 — 第 8 章:下一代 KV 快取管理PagedAttention、H2O 逐出、InfiniGen,以及 prefix cache 經濟學。

想看完整的全貌?書中章節包含可執行的靜態批次實作、以 vLLM/TGI 精神寫的完整連續批次排程器、六個請求走過四個位子引擎的逐步追蹤,以及這篇文章沒有篇幅容納的搶佔、逐出、與准入控制討論。在 Amazon 查看 LLM Primer VI →

下田 昌平
下田 昌平
RECEIPTROLLER 的 CTO 與創辦人。專注於數據、驅動創新、始終保持好奇心。