大模型的首字為什麼總是最慢?
下次把長文件發給大模型時,留意一個不算稀奇但很少被解釋的體驗:第一個字「打」出來要等好幾秒,等它出現之後,後面的字反而越吐越快。這不是網路抖了,是模型本身兩階段的分工造成的:prefill 和 decode。

大模型的首字為什麼總是最慢?
下次把長文件發給大模型時,留意一個不算稀奇但很少被解釋的體驗:第一個字「打」出來要等好幾秒,等它出現之後,後面的字反而越吐越快。這不是網路抖了,是模型本身兩階段的分工造成的:prefill 和 decode。
兩階段:先算完提示詞,再一字一字生成
模型收到你的輸入,先走 prefill。提示詞的所有 token 並行進入網路,逐層算完注意力,一次性產出「生成第一個字所需的狀態」。這一步是「把很多事同時做」,总算力大,但牆鐘時間不長。
之後進入 decode。生成第二個字必須依賴第一個字的結果,第三個又依賴第二個,只能一個字一個字往前推。像寫數學證明,每一步要等上一步的結論成立,再多加機器也並行不了。
兩個階段的瓶頸不一樣。prefill 卡在算力上,負載重,GPU 忙著做矩陣乘法;decode 卡在記憶體頻寬上。每步只新算一個 token,量很小,但每步都要把模型權重和之前所有 token 的快取從顯示記憶體搬一遍。32K 上下文下,decode 的單步開銷比 prefill 平均到每個 token 的開銷高出一個數量級。
KV cache:不重算,靠快取
如果沒有快取,每生成一個新字都要重新算它和前面所有字的注意力,生成 n 個字大約要 n×(n-1)/2 次成對計算,直接二次爆炸。所以每個 Transformer 都有一層快取,叫 KV cache:每個 token 在每層算出的 key 和 value 存下來,生成下一字時只算新 token 的 K/V,舊的照查。
代價是顯示記憶體隨上下文線性膨脹。拿一個假想的 8B 模型算給你看:32 層、每層 8 個 KV 頭、每頭向量 128 維、fp16 儲存。單個 token 每層存 2(K+V)×8×128×2 = 4KB,32 層下來每 token 128KB。32K 上下文的 KV cache 大約 4GB。這就是「長上下文吃顯示記憶體」的直接來源,也是 GQA、MQA 這類技術先動手砍它的方向——KV 頭從 32 砍到 8,快取就省四分之三。
搞懂之後能落地的三件事
一、TTFT 和 TPOT 是兩個指標。首字延遲(TTFT)反映 prefill 快慢,字間延遲(TPOT)反映 decode。有人抱怨「回答慢」,先分清是哪種:提示詞很長的場景多卡在 TTFT,輸出很長的場景多卡在 TPOT。混在一起談「延遲高」,最佳化方向會跑偏。
二、穩定的內容放前面。多個請求共享的前綴,位置越靠前,KV cache 命中直接複用的機率越大。所以 system prompt、工具說明、few-shot 範例放在提示詞前段,使用者這句每次都變的話放最後,是有工程含義的取捨,不是排版習慣。
三、別把上下文塞滿。不是模型記不住,是查找太貴:每生成一個字,它要對前面所有 token 的 KV 做一次查找。塞 10 萬字進去、九十萬字和問題無關,等於每個字的延遲裡都含著一筆十萬噸的搬運費。正確做法是先檢索再餵:向量庫拿候選段,重排模型留 top-k,再進模型這一段該花多少 token 就花多少。
晚上再開一局長文件問答時,看著那個孤零零的第一個字慢慢冒出來,你等的不只是它一個字的思考——是 GPU 把你的提示詞整篇並行消化完、把幾 GB 快取寫進顯示記憶體,然後才開始動筆。
留言區
歡迎分享你的想法!
載入留言中…