測驗:vLLM 榨乾吞吐量
共 5 題,點選答案後會立即顯示結果
1. 關於 continuous batching(連續批次),文章的白話比喻是什麼?
2. --tensor-parallel-size 2 這個參數在做什麼?
3. 你觀察到「吞吐量偏低,但 GPU 使用率一直沒滿」,最可能該調哪個參數?
4. 關於 --quantization awq,文章強調的關鍵前提是什麼?
5. 壓測報告裡的 TTFT(Time To First Token)偏高,代表使用者感受到的是什麼?
系列第 3 篇,共 4 篇 | 難度:L2-進階
前置知識:已讀第 1、2 篇,理解vllm serve怎麼把模型跑起來、KV Cache 與--gpu-memory-utilization這些記憶體參數。
這篇要解決的問題
第 1、2 篇你已經能把模型 serve 起來、也知道 KV Cache 會吃掉多少顯存。但真正上線後,老闆問的是另一件事:
「同時 50 個人打過來,會不會卡?一張卡到底能扛多少 QPS?跑不動了要加卡還是換量化?」
這篇就是教你怎麼「看懂吞吐量的旋鈕」。重點不是要你手刻推論引擎——continuous batching 這些核心機制 vLLM 自動幫你做好了——而是讓你看懂 AI 或同事丟給你的啟動指令有沒有問題、壓測數字往哪個方向調。
你是驗收者:AI 很會生一長串 vllm serve 參數,但它常常把 --tensor-parallel-size 設錯、或量化模型名稱張冠李戴。你要能一眼認出紅旗。
一句話說明:continuous batching
白話: 請求隨到隨併進正在跑的那批,不用等湊滿一車才發車。
傳統 batching 像公車——要等座位坐滿(或等時間到)才開,先到的人得乾等。continuous batching(連續批次,vLLM 又叫 in-flight batching)像共乘計程車——車在路上跑,有人要上車就在下一個路口併進來,有人到站就放下,車一直是滿載狀態。
傳統 batch:
[req1 req2] 一起跑完 → 才收 [req3 req4]
req3 到得早也得等 req1、req2 全部生成完
continuous batch(vLLM 預設):
req1 生成中 ... req2 併入 ... req1 結束、req3 補位 ...
每個 decode step 重新組批,GPU 永遠不閒置
Code language: CSS (css)你要知道的只有一件事:這是自動發生的,vLLM 預設就開著。 你不用寫任何 code 去觸發它。你要做的是餵給它對的參數,讓「這台共乘車」能載更多人。
🚦 為什麼工程師要在乎它
因為它決定了兩個此消彼長的指標:
- Throughput(吞吐量):整台伺服器每秒能吐多少 token / 服務多少請求。批次越大越高。
- Latency(延遲):單一使用者感受到的快慢。批次太大時,你的請求要跟一堆人搶 GPU,反而變慢。
continuous batching 讓你在高吞吐的同時盡量不犧牲延遲,但天下沒有白吃的午餐——批次塞越滿,個別請求的延遲就越容易被拉高。調校就是在這條線上找你場景要的平衡點。
關鍵旋鈕:五個你會反覆看到的參數
AI 生成的啟動指令通常長這樣(最小可讀版本):
vllm serve Qwen/Qwen2.5-7B-Instruct \
--tensor-parallel-size 2 \
--max-num-seqs 256 \
--max-num-batched-tokens 8192 \
--quantization awq \
--dtype auto
一行一行翻譯成白話:
| 參數 | 這在幹嘛 | 調大會怎樣 |
|---|---|---|
--tensor-parallel-size(TP) |
把一個模型「切開」攤到幾張 GPU 上 | 能跑更大的模型,但卡間通訊有開銷 |
--max-num-seqs |
一批最多同時處理幾個請求(併發數上限) | 吞吐↑,但延遲可能↑、顯存↑ |
--max-num-batched-tokens |
一個 step 最多處理幾個 token(batch 的「總容量」) | 吞吐↑,設太小會卡住吞吐 |
--quantization |
用哪種量化格式壓縮權重(awq/gptq/fp8…) | 省顯存、可提併發,但精度略降 |
--dtype |
權重的運算精度(auto/float16/bfloat16) | 通常放 auto 就好 |
--tensor-parallel-size(TP):把模型攤到多張卡
--tensor-parallel-size 2 # 這顆模型拆成 2 份,用 2 張 GPU 一起算
Code language: PHP (php)白話: 一顆 70B 的模型單張卡塞不下,就把它「橫著切開」分給 2 張、4 張卡,大家算自己那塊、再把結果合起來。
✅ 必看懂:TP 數 = 你要用幾張卡跑「這一個」模型。TP=1 就是單卡。
🚩 紅旗(後面詳談):TP 數必須能整除模型的 attention head 數,而且通常設成你實際有的 GPU 張數。AI 很愛複製別人的指令,把 --tensor-parallel-size 4 貼到你只有 2 張卡的機器上——啟動直接爆。
--max-num-seqs vs --max-num-batched-tokens:兩個容量上限
這兩個最容易搞混,用一句話分開:
--max-num-seqs:幾個人能同時上車(請求數)。--max-num-batched-tokens:這批總共幾個 token 的處理量(工作量)。
vLLM 每個 step 會在「不超過這兩個上限」的前提下,盡量把在排隊的請求塞進批次。哪個先撞到上限,就由哪個決定這批多大。
情境:一堆長 prompt(各 4000 token)湧入
max-num-batched-tokens = 8192 → 一批只塞得下 2 個(8192 / 4000 ≈ 2)
就算 max-num-seqs = 256,也輪不到,token 上限先卡住
所以如果你看到吞吐上不去、GPU 使用率卻沒滿,很多時候是 --max-num-batched-tokens 設太小,批次根本喂不飽 GPU。
量化取捨:什麼時候該壓、壓了會怎樣
量化(quantization)= 把模型權重從 16-bit 壓成 8-bit 或 4-bit,換取更少顯存、更高併發。
--quantization awq # 用 AWQ(4-bit)格式載入
Code language: PHP (php)⚠️ 超重要前提:--quantization awq 不是「即時幫你壓」。它是告訴 vLLM「這個模型檔本身就是 AWQ 量化過的版本,請用 AWQ 的方式讀它」。你載入的模型名稱必須是量化版,例如 Qwen/Qwen2.5-7B-Instruct-AWQ,不是原版。這是新手第一號大坑(紅旗區細講)。
取捨表:省什麼、賠什麼
| 格式 | 精度 | 顯存 | 適合場景 | 代價 |
|---|---|---|---|---|
| 不量化(FP16/BF16) | 最高 | 最吃 | 精度敏感、顯存夠 | 併發受限於顯存 |
| FP8 | 高(幾乎無損) | 省約一半 | 新卡(H100/Ada)追吞吐 | 需硬體支援 FP8 |
| AWQ(4-bit) | 中高 | 省很多 | 顯存吃緊、要衝併發 | 精度略降、需 AWQ 版模型 |
| GPTQ(4-bit) | 中高 | 省很多 | 同上,社群模型多 | 同上 |
什麼時候「值得」量化
- ✅ 值得:模型塞不進你的卡、或想在同一張卡上服務更多併發(KV Cache 有更多空間)。
- ✅ 值得:你的任務對一兩分精度不敏感(聊天、摘要、客服)。
- 🤔 再想想:數學、程式碼生成、需要嚴謹推理——先用小樣本比對量化前後的答案品質再決定。
- ❌ 別為省而省:顯存明明夠,硬上 4-bit 反而白白損失精度,吞吐提升也有限。
📌 知道就好:FP8 通常是 H100 / L40S 這類新卡才吃得動;AWQ/GPTQ 是社群最常見、老卡也能跑的 4-bit 方案。你不用背細節,記得「量化 = 省顯存換一點精度」就抓得住方向。
壓測:用數字說話,別靠感覺
調參最忌諱「感覺好像變快了」。vLLM 內建了壓測工具,讓你用真實數字判斷。
概念:三個你一定要看懂的指標
TTFT (Time To First Token) 第一個字吐出來要多久 → 使用者「等待感」
TPOT (Time Per Output Token) 每個後續 token 間隔 → 打字「流暢感」
Throughput (tokens/sec) 整台機每秒總產出 → 你的「產能」
一句話記法:
- TTFT 高 = 使用者盯著空白畫面乾等(prefill 階段慢或排隊)。
- TPOT 高 = 字一個一個慢慢蹦(decode 階段慢,或批次太滿在搶資源)。
- Throughput 低 = 花同樣的錢服務的人變少(沒喂飽 GPU)。
怎麼跑(概念版)
新版 vLLM 提供 vllm bench 子指令;舊一點的版本是 benchmark_serving.py 腳本。你不用背參數,重點是看懂它在做什麼:
# 先在一個終端把 server 跑起來(第 1 篇教過)
vllm serve Qwen/Qwen2.5-7B-Instruct --max-num-seqs 256
# 另一個終端打壓測:模擬多個併發請求打進去
vllm bench serve \
--model Qwen/Qwen2.5-7B-Instruct \
--num-prompts 500 \
--request-rate 20
Code language: PHP (php)這在幹嘛:模擬「500 個請求、每秒約 20 個」灌進你的 server,跑完印出一張報告:平均 TTFT、TPOT、以及整體 throughput。
看懂報告,決定往哪調
拿到數字後的決策邏輯(這才是重點):
| 觀察到的現象 | 可能原因 | 調的方向 |
|---|---|---|
| Throughput 低、GPU 使用率沒滿 | 批次喂不飽 | 調高 --max-num-batched-tokens / --max-num-seqs |
| TTFT 隨併發暴增 | 請求在排隊 | 加卡(TP)或量化騰出 KV Cache 空間 |
| 高併發時 OOM / 請求被拒 | 顯存不夠塞 KV Cache | 量化、或調高 --gpu-memory-utilization(第 2 篇) |
| TPOT 偏高但吞吐也高 | 批次太滿,個別請求被稀釋 | 調低 --max-num-seqs 換低延遲 |
🎯 心法:一次只動一個參數,重跑壓測比較。同時改三個,你永遠不知道是哪個起的作用——這跟你叫 AI 一次改一個檔案再驗收,是同一個道理。
🚩 實戰紅旗:AI 生的指令最常見的坑
AI 給你的 vllm serve 指令看起來永遠很專業,以下四個是它最常出包、而你一眼就能抓的地方。
🚩 紅旗 1:TP 數不等於你的 GPU 張數
# AI 抄了別人 4 卡的指令,貼到你 2 卡的機器
vllm serve some-70b-model --tensor-parallel-size 4 # 🚩 你只有 2 張卡
Code language: PHP (php)症狀:啟動就報錯,類似 RuntimeError: ... world_size ... available devices 2。 怎麼跟 AI 說:「我這台只有 2 張 GPU,把 tensor-parallel-size 改成符合我的硬體」。 額外檢查:TP 數還要能整除模型的 attention head 數(通常 2、4、8 這種很安全)。設 3 這種怪數字要警覺。
🚩 紅旗 2:--quantization awq 卻載入原版模型
# 🚩 模型是原版 FP16,卻叫 vLLM 用 awq 讀它
vllm serve Qwen/Qwen2.5-7B-Instruct --quantization awq
Code language: PHP (php)症狀:載入失敗,或報「找不到量化權重 / quant config」。 根因:--quantization awq 是「用 AWQ 方式讀一個已經是 AWQ 的模型」,不是即時壓縮。 怎麼跟 AI 說:「要嘛換成量化版模型名稱(例如 -AWQ 結尾那個),要嘛拿掉 --quantization」。
🚩 紅旗 3:--max-num-batched-tokens 設太小,吞吐上不去
vllm serve my-model --max-num-batched-tokens 512 # 🚩 太小了
Code language: PHP (php)症狀:壓測時 GPU 使用率上不去、throughput 卡在低點,但沒有報錯(最陰險,因為「看起來能跑」)。 根因:每個 step 只能處理 512 token,長 prompt 進來連一個都塞不滿,GPU 大量閒置。 怎麼跟 AI 說:「吞吐偏低但 GPU 沒滿,幫我把 max-num-batched-tokens 調大(例如 8192 或更高)再壓測比較」。
🚩 紅旗 4:量化省下的顯存沒拿去用
量化把權重壓小後,多出來的顯存應該讓 KV Cache 吃掉、服務更多併發。如果 AI 量化了卻沒動 --max-num-seqs,等於省了錢沒花出去。
怎麼跟 AI 說:「我已經量化省了顯存,順便把併發上限(max-num-seqs)往上調,把空間用起來」。
🚩 紅旗 5:只憑一次結果就下結論
「我把 max-num-seqs 從 128 調到 256,感覺快多了」 # 🚩 沒有數據、沒有對照
Code language: PHP (php)沒有壓測數字、沒有固定其他變因,這種結論不可信。要有 before/after 的 TTFT / throughput 才算數。
Vibe Coder 驗收檢查點
拿到 AI 的調校方案時,逐項確認(做得到的動作):
- 對硬體:
--tensor-parallel-size的數字 = 你機器實際 GPU 張數嗎?- 動作:跑
nvidia-smi -L看有幾張卡,數字要對得上。
- 動作:跑
- 對模型:有
--quantization時,模型名稱是量化版嗎(通常帶AWQ/GPTQ/FP8字樣)? - 能起來:server 啟動 log 有沒有印出類似
Application startup complete/ 監聽埠號,而不是 traceback?- 動作:看啟動輸出最後幾行,卡在 error 就是沒起來。
- 有數據:調參前後都有跑
vllm bench(或等價壓測),拿得出 TTFT / throughput 的 before/after 嗎? - 一次一變數:這次調整只動了一個參數嗎?(多個一起動 → 要求分開驗證)
只要有一項打叉,就把它貼回去問 AI,別急著收。
看不懂就這樣問 AI
把指令或壓測報告直接貼給 AI,套用這些提問句:
「用白話解釋這串 vllm serve 參數每一個在幹嘛,我要判斷適不適合我的硬體。我有 __ 張 __ 顯卡。」
「這是我的 vllm bench 壓測報告(貼上),throughput 偏低但 GPU 使用率沒滿,最可能是哪個參數要調?一次只給我一個建議。」
「我想在同一張卡上服務更多併發,量化(AWQ/GPTQ/FP8)哪種適合我這張卡?各自的精度代價是什麼?」
「幫我檢查:這個 –quantization 設定跟我載入的模型名稱是相容的嗎?」
本篇小結
- continuous batching 是 vLLM 高吞吐的引擎,自動運作,你只要餵對參數把它喂飽。
- 五個核心旋鈕:
--tensor-parallel-size(幾張卡跑一個模型)、--max-num-seqs(幾個人上車)、--max-num-batched-tokens(一批總工作量)、--quantization(壓權重換顯存)、--dtype(放 auto 就好)。 - 量化 = 省顯存/提併發 換一點精度;顯存吃緊或要衝併發才值得,精度敏感任務先小樣本驗證。
- 調參靠數據:看 TTFT / TPOT / throughput 三個指標,一次動一個參數重壓測。
- 認得 5 個紅旗:TP 對不上卡數、量化格式對不上模型、batched-tokens 太小、省了顯存沒用、沒數據就下結論。
下一篇(#04,系列最終篇)會把這些串起來,談上線後的穩定性與監控——當半夜請求量爆了,你怎麼從指標看出是撞到哪個上限。
進階測驗:vLLM 榨乾吞吐量
共 5 題,包含情境題與錯誤診斷題。