化:SGLang與vLLM部署實戰(zhàn))
相信很多做大模型應(yīng)用的朋友都有這種感覺模型在短文本下推理很快一旦把上下文拉長到幾十萬 token首字延遲就變得非常難以接受。用戶敲下問題后服務(wù)端要等好幾秒才吐第一個字這在生產(chǎn)環(huán)境里幾乎是致命的體驗問題。而這背后的主要瓶頸往往不是模型本身而是 LLM 推理過程中的 Prefill 階段。本文圍繞長上下文 LLM 推理中的 Prefill 優(yōu)化展開完整梳理 Prefill 階段為什么慢、主流的加速思路是什么、如何通過 SGLang 與 vLLM 對接生產(chǎn)部署并給出可復(fù)制的啟動腳本、關(guān)鍵參數(shù)說明和常見問題排查方案。無論你是在做 RAG 應(yīng)用、Agent 系統(tǒng)還是基于大模型的內(nèi)部服務(wù)這篇文章都適合參考。1. Prefill 階段為什么是長上下文推理的瓶頸1.1 一次 LLM 推理的完整過程Prefill Decode要理解 Prefill 優(yōu)化先要把 LLM 推理的完整流程拆開看。一次自回歸生成可以分成兩個階段Prefill預(yù)填充階段把用戶輸入的提示詞Prompt一次性喂給模型并行計算出所有輸入 token 的 Key/Value 狀態(tài)并生成第一個輸出 token。Decode解碼階段逐 token 生成后續(xù)輸出每一步只計算一個新的 token并把當前 token 的 K/V 追加到已有的狀態(tài)中。用一句話概括Prefill 是“一次算完輸入”Decode 是“一個一個往后蹦”。在短文本場景下Prefill 占用的時間很短大家主要關(guān)心 Decode 的速度。但當輸入上下文達到幾萬甚至幾十萬 token 時Prefill 的計算量會急劇膨脹成為延遲和吞吐的重要瓶頸。1.2 Prefill 階段的計算特征為什么 Prefill 會慢從計算特征來看原因非常直觀。第一它可以并行但計算量巨大。Prefill 階段需要對輸入序列中的所有 token 同時計算注意力計算復(fù)雜度與序列長度的平方成正比。一個 10 萬 token 的輸入注意力矩陣的規(guī)模是 10 萬乘以 10 萬顯存和算力消耗都相當驚人。第二它受限于顯存帶寬。除了計算注意力Prefill 還要把模型參數(shù)和輸入激活值反復(fù)搬運到計算單元。長序列下中間激活值占用大量顯存很容易觸發(fā)顯存溢出或者被迫降低 batch size從而拉低吞吐。第三它與 Decode 的優(yōu)化手段并不完全兼容。Decode 重視的是低延遲和 K/V 緩存復(fù)用而 Prefill 更依賴高并行度和算子融合。如果在同一個服務(wù)里用同一套參數(shù)處理這兩個階段往往沒辦法同時做到最優(yōu)。1.3 為什么說 TTFT 是用戶體感第一步TTFTTime To First Token指的是從用戶發(fā)起請求到收到第一個輸出 token 的時間。很多剛接觸大模型推理優(yōu)化的同學(xué)會困惑TTFT 到底包含 Prefill 還是“Prefill 加一次 Decode”從工程角度看通常所說的 TTFT 包含一次完整的 Prefill 計算以及首次 Decode 生成首個 token 的時間。因為服務(wù)端必須完成 Prefill 才能拿到第一個輸出 token所以 Prefill 的耗時基本決定了 TTFT 的下限。這也是為什么長上下文場景下必須優(yōu)先優(yōu)化 Prefill否則無論 Decode 多快用戶的第一印象都會很糟糕。2. 加速 Prefill 的主流技術(shù)路線2.1 注意力計算優(yōu)化注意力計算是 Prefill 階段最核心的耗時部分。常見的優(yōu)化思路包括FlashAttention 系列通過分塊計算注意力避免把完整的 N×N 注意力矩陣寫入顯存顯著降低顯存占用并提升計算效率。FlashInfer一個面向大模型推理的算子庫提供更高效的注意力模板被 SGLang 等框架作為后端集成。稀疏注意力/線性注意力針對超長序列設(shè)計但在通用場景下仍然需要謹慎評估精度損失。在實際部署中優(yōu)先使用支持 FlashAttention 或 FlashInfer 的推理框架是性價比最高的優(yōu)化手段。2.2 算子融合與并行Prefill 階段包含大量小算子例如矩陣乘法、Softmax、LayerNorm 等。如果每個算子都單獨啟動 kernelGPU 的利用率會很低。算子融合的核心思路是把多個連續(xù)操作合并成一個 kernel減少顯存訪問和 kernel 啟動開銷。在并行層面還可以通過以下方式提速Tensor Parallel張量并行把模型權(quán)重切分到多張 GPU 上適合單機多卡場景。Pipeline Parallel流水線并行把模型層切分到多張 GPU 上適合模型較大或跨機場景。數(shù)據(jù)并行與請求并行多路請求同時處理提升整體吞吐。SGLang 和 vLLM 都對張量并行和部分算子融合提供了內(nèi)置支持使用時只需要通過啟動參數(shù)配置即可。2.3 顯存管理與 Chunked Prefill長上下文輸入最容易碰到顯存溢出。一個很實用的優(yōu)化方案是 Chunked Prefill分塊預(yù)填充把超長的輸入切分成多個 chunk 逐塊處理。這樣可以避免一次性申請超大顯存同時還能讓 Prefill 與 Decode 請求交錯執(zhí)行提高 GPU 利用率。vLLM 中通過--max-num-batched-tokens等參數(shù)控制單次 batch 的最大 token 數(shù)實際上就能起到類似 Chunked Prefill 的效果。SGLang 也支持類似的調(diào)度策略對長上下文場景非常友好。2.4 緩存復(fù)用RadixAttention 與 Prefix Cache在多輪對話、Agent 工具調(diào)用、RAG 檢索場景中不同請求之間往往共享相同的前綴內(nèi)容。如果能把這些前綴的 K/V 緩存復(fù)用起來就能大幅減少重復(fù)的 Prefill 計算。vLLM 的 Prefix Cache基于 PagedAttention 的頁級緩存復(fù)用當請求前綴與已有緩存一致時直接復(fù)用 K/V 頁。SGLang 的 RadixAttention將 K/V 緩存組織成 Radix Tree基數(shù)樹結(jié)構(gòu)自動識別并復(fù)用公共前綴甚至支持更細粒度的緩存命中。這也是 SGLang 在長上下文、多輪對話和高并發(fā)場景下表現(xiàn)突出的重要原因。對于“47 倍速”之類的加速效果雖然不同硬件和場景下數(shù)據(jù)會有差異但緩存命中帶來的收益在實測中確實非??捎^。3. 環(huán)境準備與部署框架選型3.1 硬件與軟件環(huán)境Prefill 優(yōu)化和具體的硬件環(huán)境強相關(guān)。以下是一套參考環(huán)境版本需根據(jù)你的實際項目情況調(diào)整本文重點演示配置思路項目推薦配置操作系統(tǒng)Ubuntu 20.04 / 22.04GPUNVIDIA A100 / H100或昇騰 910B 等國產(chǎn)加速卡顯存單卡 40GB 以上長上下文建議多卡CUDACUDA 11.8 / 12.1 及以上Python3.10 或 3.11推理框架SGLang、vLLM 二選一或?qū)Ρ仁褂萌萜鞣桨窪ocker 或裸機 conda 環(huán)境均可如果你使用的是昇騰 910B 等非 NVIDIA 硬件需要特別注意框架對國產(chǎn)加速卡的適配情況。部分版本對昇騰的支持還不完善尤其是 embedding 模型和 reranker 模型的啟動方式可能與 GPU 環(huán)境不同建議先閱讀框架官方文檔確認。3.2 SGLang 與 vLLM 怎么選這兩個框架是目前大模型推理部署中討論度最高的兩個選擇SGLang主打高性能和靈活的運行時調(diào)度RadixAttention 是它的核心亮點。適合多輪對話、長上下文、復(fù)雜 Agent 調(diào)用等場景Prefill 優(yōu)化的可調(diào)參數(shù)比較多。vLLM生態(tài)成熟兼容性好社區(qū)用戶量大。它基于 PagedAttention對顯存管理和 Decode 階段優(yōu)化做得非常出色同樣支持 Chunked Prefill。在實際項目中如果團隊更看重穩(wěn)定性和生態(tài)兼容性可以優(yōu)先考慮 vLLM如果追求極限的長上下文性能和緩存復(fù)用率SGLang 非常值得嘗試。兩者都在快速迭代中建議在生產(chǎn)選型前做一次同模型同硬件的對比測試。4. 實戰(zhàn)用 SGLang 部署并優(yōu)化長上下文推理4.1 安裝 SGLang推薦使用 Docker 方式部署這樣環(huán)境隔離更干凈也方便后續(xù)升級。# 拉取 SGLang 鏡像 docker pull lmsysorg/sglang:latest # 創(chuàng)建容器并掛載模型目錄 docker run -it --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v /data/models:/models \ lmsysorg/sglang:latest \ bash如果你希望使用 conda 環(huán)境也可以先用 conda 創(chuàng)建 Python 3.10 環(huán)境然后通過 pip 安裝pip install --upgrade pip pip install sglang[all]安裝完成后可以用python -c import sglang; print(sglang.__version__)驗證。4.2 啟動服務(wù)下面以 Qwen 系列 32B 模型為例演示一個適合長上下文 Prefill 優(yōu)化的啟動腳本。python -m sglang.launch_server \ --model-path /models/Qwen2.5-32B-Instruct \ --host 0.0.0.0 \ --port 30000 \ --tp-size 4 \ --mem-fraction-static 0.8 \ --context-length 131072 \ --chunked-prefill-size 8192 \ --attention-backend flashinfer \ --enable-prefix-caching4.3 關(guān)鍵參數(shù)說明--tp-size 4表示使用 4 張 GPU 做張量并行。模型較大或上下文很長時這個參數(shù)能顯著加快 Prefill 計算。--context-length 131072設(shè)置最大上下文長度。需要根據(jù)模型實際能力和顯存調(diào)整不是越大越好。--chunked-prefill-size 8192單次 Prefill 的最大 token 數(shù)。長上下文場景建議設(shè)置成 4096 到 8192 之間的值避免一次性申請過多顯存。--attention-backend flashinfer使用 FlashInfer 作為注意力后端通常在長序列下能獲得更好的性能。--enable-prefix-caching開啟前綴緩存配合 RadixAttention 使用多輪對話和 Agent 場景提升明顯。--mem-fraction-static 0.8指定用于緩存和運行時的顯存比例需要根據(jù)顯存大小實測調(diào)整。啟動后服務(wù)會監(jiān)聽 30000 端口。可以用下面的 Python 腳本快速測試import requests resp requests.post( http://localhost:30000/generate, json{ text: 請用三句話說明什么是 Prefill 階段。, sampling_params: { max_new_tokens: 256, temperature: 0.7 } } ) print(resp.json())5. 實戰(zhàn)用 vLLM 部署并優(yōu)化 Prefill5.1 安裝 vLLMvLLM 同樣支持 Docker 和 pip 安裝。建議先用官方鏡像驗證環(huán)境再根據(jù)業(yè)務(wù)需求定制依賴。docker pull vllm/vllm-openai:latest docker run -it --gpus all \ --shm-size 32g \ -p 8000:8000 \ -v /data/models:/models \ vllm/vllm-openai:latest \ bash5.2 啟動服務(wù)python -m vllm.entrypoints.openai.api_server \ --model /models/Qwen2.5-32B-Instruct \ --host 0.0.0.0 \ --port 8000 \ --tensor-parallel-size 4 \ --max-model-len 131072 \ --max-num-batched-tokens 8192 \ --enable-prefix-caching \ --gpu-memory-utilization 0.85.3 與 SGLang 的差異說明--enforce-eager參數(shù)在 vLLM 中如果加上這個參數(shù)會關(guān)閉 CUDA Graph直接走 eager 模式。這個模式可以降低顯存占用但通常會犧牲部分性能。生產(chǎn)環(huán)境長上下文場景下建議先測試不要因為顯存緊張而盲目開啟必要時優(yōu)先縮小 batch size 或 max-model-len。--tensor-parallel-size等同于 SGLang 的--tp-size。--enable-prefix-cachingvLLM 的前綴緩存開關(guān)適合多輪對話和 RAG 場景。vLLM 默認提供 OpenAI 兼容接口部署完成后可以直接用 curl 測試curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: /models/Qwen2.5-32B-Instruct, messages: [{role: user, content: 你好請介紹 Prefill 優(yōu)化。}], max_tokens: 256 }6. 精度選擇與量化部署6.1 FP16、BF16 與 FP32 如何選擇精度選擇對 Prefill 階段的速度和顯存占用影響非常大。簡單說明三者的差別精度特點適用場景FP32數(shù)值范圍廣精度最高但顯存占用大、速度慢小模型調(diào)試FP16顯存占用減半速度較快但小數(shù)值容易出現(xiàn)精度溢出NVIDIA GPU 推理主流選擇BF16動態(tài)范圍與 FP32 接近訓(xùn)練和推理都更穩(wěn)定推薦用于大模型推理INT8/INT4顯存占用進一步降低速度提升但可能帶來精度損失資源受限或長上下文場景在長上下文 Prefill 場景下顯存是剛性約束。如果模型允許建議優(yōu)先用 BF16如果還是放不下再考慮 AWQ、GPTQ 或 INT8 量化方案。需要注意的是量化模型的 Prefill 計算可能依賴反量化算子不同框架的實現(xiàn)差異較大部署前要做精度對比驗證。6.2 量化模型的啟動示例以 Qwen3.5-122B-A10B-GPTQ-INT4 這類模型為例無論使用 SGLang 還是 vLLM核心思路都是指定量化模型目錄路徑并配合多卡張量并行啟動。SGLang 示例python -m sglang.launch_server \ --model-path /models/Qwen3.5-122B-A10B-GPTQ-INT4 \ --tp-size 8 \ --context-length 65536 \ --chunked-prefill-size 4096量化模型部署后建議用一組標準業(yè)務(wù)問題分別比較量化模型和原模型的輸出質(zhì)量再決定是否上線。7. 效果驗證與性能對比7.1 如何測量 TTFT測量 TTFT 最直接的方法是在客戶端記錄請求發(fā)出時間和第一個 token 返回時間。下面是一個簡單的 Python 腳本思路import time import requests url http://localhost:30000/generate long_prompt 這是一段很長的輸入... * 1000 start time.time() resp requests.post(url, json{ text: long_prompt, sampling_params: {max_new_tokens: 1} }, streamTrue) first_token_time time.time() - start print(fTTFT: {first_token_time:.3f} s)需要注意的是max_new_tokens1時模型只需要做 Prefill 和一次 Decode能更準確地反映 Prefill 階段的耗時。如果服務(wù)端有緩存命中首次請求和后續(xù)請求的 TTFT 會有明顯差異這種差異本身就是 Prefix Cache 效果的一種驗證。7.2 對比維度建議做性能對比時建議至少記錄以下指標TTFT首 token 延遲Prefill 耗時Decode 吞吐token/s顯存占用峰值同批次并發(fā)請求數(shù)盡量做到同一個模型、同一個輸入文本、同一個硬件環(huán)境下對比才具有參考價值。8. 常見問題與排查思路問題現(xiàn)象常見原因解決思路長上下文啟動時顯存溢出context-length 設(shè)置過大或顯存比例設(shè)置過高調(diào)小 context-length或降低 mem-fraction-static / gpu-memory-utilization使用 --enforce-eager 后性能下降關(guān)閉了 CUDA Graph執(zhí)行效率降低盡量保留 CUDA Graph優(yōu)先通過減小 batch size 來緩解顯存多卡并行時負載不均tensor 并行配置不合理或模型切分不均檢查 tp-size必要時結(jié)合 pipeline parallel前綴緩存命中率低輸入前綴動態(tài)變化或未開啟 prefix caching在 SGLang 開啟 --enable-prefix-cachingvLLM 開啟 --enable-prefix-caching昇騰 910B 上 vLLM 無法啟動 embedding 模型框架對國產(chǎn)加速卡的模型類型支持有限查看框架官方適配文檔必要時改用其他框架或單獨部署 embedding 服務(wù)量化模型輸出質(zhì)量明顯下降量化精度選擇不合適對比 FP16/BF16 輸出考慮改用 AWQ 或調(diào)整量化參數(shù)遇到問題時建議按以下順序排查確認框架版本和模型版本匹配。查看服務(wù)端日志定位是顯存問題還是算子兼容問題。把參數(shù)逐步降到最小可運行狀態(tài)例如先關(guān)閉 prefix caching調(diào)小 context-length。確認是 Prefill 慢還是 Decode 慢可以通過max_new_tokens1的請求分開測。對比不同 attention 后端例如 flashinfer 與 flash-attention。9. 最佳實踐與工程建議9.1 參數(shù)配置要按場景實測Prefill 優(yōu)化沒有“萬能參數(shù)”。長文檔問答、Agent 多輪調(diào)用、RAG 檢索等場景對 Prefill 的要求完全不同。建議把參數(shù)配置做成環(huán)境變量或配置文件方便在測試環(huán)境快速切換。9.2 優(yōu)先復(fù)用再談壓縮在長上下文場景中緩存復(fù)用帶來的收益往往比單純壓縮模型更明顯。如果業(yè)務(wù)中有大量重復(fù)前綴應(yīng)該優(yōu)先開啟 Prefix Cache 或 RadixAttention再考慮是否通過量化降低顯存。9.3 注意生產(chǎn)環(huán)境變更流程調(diào)整 Prefill 相關(guān)參數(shù)或升級框架版本前一定要在上線前做充分驗證。特別是涉及--context-length、--tp-size這些直接影響顯存分配和計算效率的參數(shù)時建議先在測試環(huán)境用壓測腳本模擬線上流量。記錄優(yōu)化前后的 TTFT、吞吐、顯存指標。保留可回滾的部署配置。逐步灰度發(fā)布不要一次性全量切換。9.4 日志與監(jiān)控生產(chǎn)環(huán)境建議至少監(jiān)控以下指標平均 TTFT 和 P95 TTFTPrefill 和 Decode 階段耗時拆分GPU 利用率和顯存占用前綴緩存命中率請求排隊時間和超時率有了這些數(shù)據(jù)才能判斷 Prefill 優(yōu)化是否真正解決了業(yè)務(wù)瓶頸而不是只靠啟動參數(shù)“感覺變快了”。10. 總結(jié)Prefill 階段是長上下文 LLM 推理中不可回避的性能瓶頸。本文從 Prefill 的原理出發(fā)梳理了注意力算子優(yōu)化、Chunked Prefill、張量并行、前綴緩存復(fù)用等主流加速手段并給出了 SGLang 和 vLLM 的完整部署示例與關(guān)鍵參數(shù)解釋。在實際項目中Prefill 優(yōu)化的收益非常依賴具體場景RAG 應(yīng)用中公共前綴越多緩存復(fù)用帶來的提升越明顯超長上下文中 Chunked Prefill 能顯著降低顯存壓力提高服務(wù)穩(wěn)定性。如果你正在部署長上下文服務(wù)建議先用同一份測試數(shù)據(jù)對比 SGLang 和 vLLM 在你當前硬件上的表現(xiàn)再決定把哪一套方案放進生產(chǎn)環(huán)境。下一步可以繼續(xù)深入學(xué)習(xí) FlashInfer 后端實現(xiàn)、K/V 緩存調(diào)度策略以及量化模型在長上下文場景中的精度表現(xiàn)。把這些內(nèi)容研究透大模型推理優(yōu)化的功底就算真正扎實了。