請求批次處理(request batching)
/ ree-KWEST BACH-ing /
請求批次處理,是把幾個進來的請求攢成一組、一趟送進模型裡一起跑,而不是一個一個來。回想一下:加速器晶片就像一間有成千上萬名廚工的廚房,只遞給它一張單子,等於浪費了絕大多數廚工。批次處理就是那位領班,他先攢上十幾張單子,再一次性全送進廚房,好讓每名廚工都忙起來。不論晶片處理 1 個還是 32 個輸入,做的活兒大致一樣多,所以批次處理近乎是白來的額外產能。
最簡單的做法是等上幾毫秒、攢齊一批再跑——拿每個用戶一丁點兒等待時間,去換總產能的一大筆進帳。現代文本生成裡用的更聰明的方案,叫「連續批次處理」或「動態批次處理」,它不讓已經辦完的請求陪著慢的一起等:某個用戶的答案一出來,那個空位就騰出來,新請求隨即補進去,讓晶片始終滿載,又不必讓誰去等整組人。這是壓低大語言模型運行成本最大的槓桿之一。
為什麼這很重要:批次處理往往就是「養得起的服務」與「貴到要命的服務」之間的分界,有時能把成本效率提上好幾倍。誠實的權衡是:它總會給單個請求添上一些延遲,而且只有在流量足夠、能把批填滿時才管用——凌晨三點只有一個用戶在線時,根本沒東西可攢,你只能按每個請求的全價付錢。它是一種吞吐量優化,有意地花延遲去買產能。
伺服器在第一個請求到來後最多等 10 毫秒,把這段時間裡來的其他請求一併掃進來。若進來了 16 個,這 16 個就在 GPU 裡一趟跑完——耗時和單跑一個差不多,卻以一個的代價應答了 16 個用戶。
10 毫秒的等待,把 16 個獨立任務併成了一個——這就是廉價推論背後的核心戲法。
批次處理並不是品質上的改進——它絲毫不改變模型給出的答案,只改變硬體產出這些答案的效率。它純粹是一根關乎成本與速度的槓桿,而且只有當進來的請求足夠、能填滿一批時,這根槓桿才拉得動。