器部署全攻略:從框架選型到生產(chǎn)級(jí)實(shí)踐)
年初我接到一個(gè)任務(wù)把內(nèi)部常用的 13B 模型從開發(fā)機(jī)搬到正式服務(wù)器做成一個(gè)可供其他團(tuán)隊(duì)調(diào)用的 API 服務(wù)。我當(dāng)時(shí)以為半天能搞定結(jié)果前后折騰了接近一周?;仡^復(fù)盤問題根本不在“把模型跑起來”而在“用正確的方式跑起來”。這個(gè)正確牽扯到框架選型、云服務(wù)器對(duì)比、顯存預(yù)算、量化策略、服務(wù)化封裝、壓測驗(yàn)證等一系列決策。那篇帖子里我承諾過要寫一份完整指南今天就把這套大模型服務(wù)器部署的完整流程按 2026 年的現(xiàn)狀整理出來從框架選型講到生產(chǎn)級(jí)流程把我踩過的坑和最終沉淀下來的方案一并交代清楚。無論你是剛接觸大模型部署的新人還是已經(jīng)在本地跑過 demo、準(zhǔn)備上生產(chǎn)的工程師這篇文章都值得你花二十分鐘讀一遍。我盡量只講實(shí)際操作和真實(shí)結(jié)論不堆理論。1. 部署一個(gè)模型為什么比想象中復(fù)雜1.1 “能跑”只是及格線很多人第一次部署大模型都是從“把模型跑起來”開始的。最簡單的方式確實(shí)是下載一個(gè) llama.cpp加載一個(gè) GGUF 文件然后輸入問題看著終端一行行輸出文字。那一刻感覺特別爽但爽完之后面對(duì)的是一個(gè)很現(xiàn)實(shí)的問題這個(gè)服務(wù)能不能給別人用一旦要給別人用事情立刻變復(fù)雜。別人不會(huì)像你一樣在終端里慢慢等輸出他們可能有幾十個(gè)人甚至幾百個(gè)人同時(shí)發(fā)起請(qǐng)求。每個(gè)請(qǐng)求的上下文長度不同有的只有幾百字有的帶幾萬字的歷史記錄。服務(wù)器響應(yīng)慢了調(diào)用方會(huì)認(rèn)為是服務(wù)不可用響應(yīng)速度快了但結(jié)果亂碼調(diào)用方會(huì)質(zhì)疑模型能力。這些都不是模型本身的問題而是部署架構(gòu)的問題。所以我把“部署”這件事分成了四個(gè)層次能跑、能用、能扛、能管。能跑是最低標(biāo)準(zhǔn)模型能加載、能推理、能出結(jié)果。能用是封裝成標(biāo)準(zhǔn)接口別人通過 HTTP 或 SDK 就能調(diào)用不需要知道模型文件放在哪個(gè)目錄。能扛是并發(fā)上來之后服務(wù)依然穩(wěn)定延遲在可接受范圍內(nèi)不會(huì)動(dòng)不動(dòng) OOM 或者排隊(duì)排到超時(shí)。能管則是更上層的維度監(jiān)控指標(biāo)、日志、告警、多副本擴(kuò)縮、版本回滾這些是一個(gè)生產(chǎn)系統(tǒng)必須具備的能力。1.2 四個(gè)層次各自的門檻能跑的階段最大的坑是框架不會(huì)用。你隨便用transformers的pipeline跑一個(gè) 7B 模型單條請(qǐng)求可能沒問題但吞吐量低到讓人絕望。因?yàn)?transformers 默認(rèn)的推理方式是逐個(gè) token 生成批處理能力幾乎沒有GPU 利用率可能只有個(gè)位數(shù)百分比。能用階段需要解決的是接口協(xié)議問題。現(xiàn)在社區(qū)基本已經(jīng)把 OpenAI 兼容接口當(dāng)成了事實(shí)標(biāo)準(zhǔn)vLLM、SGLang、Triton 這些框架都提供了現(xiàn)成的 OpenAI 風(fēng)格 API。你需要做的只是把模型路徑、顯存參數(shù)、端口配置好然后往/v1/chat/completions上扔 JSON 請(qǐng)求。能扛階段就要開始認(rèn)真對(duì)待顯存預(yù)算、KV Cache 占用、連續(xù)批處理參數(shù)、最大并發(fā)數(shù)、超時(shí)時(shí)間這些細(xì)節(jié)。我在后面的流程部分會(huì)給出具體的啟動(dòng)參數(shù)以及每個(gè)參數(shù)的判斷依據(jù)。能管階段通常是團(tuán)隊(duì)協(xié)作的產(chǎn)物。至少要有一套監(jiān)控面板能看到 GPU 利用率、顯存占用、請(qǐng)求延遲的 P50/P95/P99、每秒生成 token 數(shù)。還要有日志系統(tǒng)能定位到具體一個(gè)請(qǐng)求是卡在 prefill 還是 decode。再往后才是 Kubernetes 編排、自動(dòng)擴(kuò)縮容、灰度發(fā)布這些重型武器。1.3 一條可以復(fù)用的部署決策路徑我在踩過足夠多的坑之后逐漸固定了一套決策順序先確認(rèn)模型規(guī)模7B、13B、32B 還是 70B直接決定你需要多大的顯存。再確認(rèn)流量畫像是內(nèi)部幾十人低頻調(diào)用還是面向高并發(fā) API 場景兩者的框架選型和云服務(wù)器配置完全不同。接著確認(rèn)延遲要求內(nèi)部工具允許 5 秒首 token面對(duì)用戶的產(chǎn)品可能要求 1 秒內(nèi)出首字。然后選框架vLLM 和 SGLang 是當(dāng)前最主流的兩個(gè)選擇后面會(huì)細(xì)說。再然后選云服務(wù)器按需付費(fèi)、包月、競價(jià)實(shí)例各有適用場景。最后是服務(wù)化封裝、壓測、監(jiān)控、上線。這套順序我后來基本沒改過只是在不同項(xiàng)目里權(quán)重不同。下面我按照這套路徑逐步展開。2. 2026 年框架選型先看流量畫像再談技術(shù)棧2.1 主流推理框架的一頁紙對(duì)比走到 2026 年大模型推理框架的競爭格局已經(jīng)比較清晰了。vLLM 憑借生態(tài)和吞吐量穩(wěn)坐第一梯隊(duì)SGLang 在共享前綴緩存和多模態(tài)場景上形成了差異化優(yōu)勢TensorRT-LLM 在延遲敏感和極致性能場景依然有一席之地llama.cpp 則繼續(xù)擔(dān)當(dāng)輕量部署和本地實(shí)驗(yàn)的老黃牛。我把自己實(shí)際用過的框架放在一起做了個(gè)對(duì)比框架核心機(jī)制最大優(yōu)勢主要短板最適合的場景vLLMPagedAttention 連續(xù)批處理生態(tài)成熟、吞吐高、API 兼容度好多輪共享前綴的緩存能力不如 SGLang通用高并發(fā) API 服務(wù)SGLangRadixAttention 前綴樹緩存多輪對(duì)話和共享文檔前綴加速明顯社區(qū)規(guī)模仍在追趕 vLLM長上下文、多輪對(duì)話、Agent 場景TensorRT-LLMTensorRT 深度編譯優(yōu)化單卡延遲低、FP8 支持好、算子融合極致編譯時(shí)間長、動(dòng)態(tài) shape 處理麻煩延遲敏感、shape 相對(duì)固定llama.cppGGUF 量化 多平臺(tái)支持部署簡單、CPU 也能跑、跨平臺(tái)高并發(fā)吞吐能力有限本地開發(fā)、邊緣設(shè)備、臨時(shí)演示Triton Inference Server多模型管理 請(qǐng)求調(diào)度生產(chǎn)組件齊全、多模型共用配置學(xué)習(xí)成本高多模型網(wǎng)關(guān)、需要 A/B 測試的復(fù)雜生產(chǎn)環(huán)境2.2 vLLM吞吐優(yōu)先場景的第一選擇如果讓我給大多數(shù)人一個(gè)閉著眼睛不會(huì)太錯(cuò)的方案我會(huì)選 vLLM。它過去兩三年里迭代速度非??焐鐓^(qū)生態(tài)已經(jīng)形成了事實(shí)標(biāo)準(zhǔn)。PagedAttention 把 KV Cache 切成分頁減少了顯存碎片連續(xù)批處理讓新請(qǐng)求可以在當(dāng)前 decode 批次中動(dòng)態(tài)插入不用等整個(gè)批次生成完就能加入吞吐量提升非常明顯。實(shí)際使用中vLLM 還有一個(gè)隱性優(yōu)勢它大量兼容 OpenAI 接口格式/v1/chat/completions、/v1/completions、/v1/embeddings這些端點(diǎn)都是現(xiàn)成的接入業(yè)務(wù)方時(shí)幾乎不需要寫適配層。如果你的團(tuán)隊(duì)主要工作是做業(yè)務(wù)集成而不是研究推理框架本身vLLM 是最省事的選擇。vLLM 的缺點(diǎn)也很明確它對(duì)前綴復(fù)用的優(yōu)化不如 SGLang 激進(jìn)。什么叫前綴復(fù)用就是兩個(gè)請(qǐng)求如果共享了一大段系統(tǒng)提示詞或歷史對(duì)話理論上可以復(fù)用前面已經(jīng)算過的 KV Cache不用重新計(jì)算。vLLM 也有自動(dòng)前綴緩存功能但相對(duì) SGLang 的 RadixAttention 在設(shè)計(jì)上更淺一些。如果你的場景是大量請(qǐng)求都帶一個(gè)很長的公共 system promptSGLang 能吃到更多紅利。2.3 SGLang多輪對(duì)話與長上下文場景的利器SGLang 的核心理念是 RadixAttention把前綴 KV Cache 構(gòu)建成一顆基數(shù)樹來共享。舉個(gè)例子如果系統(tǒng)提示詞有 2000 個(gè) token一千個(gè)并發(fā)請(qǐng)求都帶著這段提示詞SGLang 只需要真正計(jì)算一次公共前綴剩下九百多次都能直接復(fù)用緩存。在多輪對(duì)話場景里上一輪的計(jì)算結(jié)果也能被下一輪復(fù)用首 token 延遲會(huì)明顯下降。我實(shí)際測試過一個(gè) 32B 模型在模擬 50 個(gè)并發(fā)用戶、每人帶 3000 token 歷史對(duì)話的壓測場景里SGLang 的 TTFT首 token 延遲比同一臺(tái)機(jī)器上的 vLLM 低了大概 30%。但如果把公共前綴去掉大家各自隨機(jī)提問兩者的差距就沒那么明顯了。所以我的建議是如果業(yè)務(wù)形態(tài)是大量帶固定 system prompt 的 Agent 應(yīng)用或者長文檔問答優(yōu)先試一下 SGLang。如果只是標(biāo)準(zhǔn)的通用 API用 vLLM 就行別為了追求新東西給自己增加維護(hù)成本。2.4 TensorRT-LLM延遲敏感場景的另一個(gè)選項(xiàng)TensorRT-LLM 是英偉達(dá)官方的推理優(yōu)化方案思路是把模型編譯成高度優(yōu)化的 TensorRT 引擎算子融合、層融合、量化對(duì)齊都做得非常深。好處是同一個(gè)模型在三方框架下可能延遲是 50msTensorRT-LLM 能壓到 35ms 甚至更低。但代價(jià)也很現(xiàn)實(shí)編譯一次引擎可能要花幾十分鐘到幾小時(shí)而且對(duì)輸入輸出 shape 有要求動(dòng)態(tài) shape 處理起來非常麻煩。如果你的 API 要接收不定長輸入引擎配置就要寫得相當(dāng)細(xì)致每次改模型結(jié)構(gòu)都要重新編譯驗(yàn)證。我個(gè)人的判斷是TensorRT-LLM 適合那種請(qǐng)求模式非常固定、性能要求極高的少數(shù)場景比如在線游戲 AI、實(shí)時(shí)語音交互。大部分業(yè)務(wù) API 的延遲瓶頸不在框架的算子級(jí)優(yōu)化而在顯存不夠?qū)е碌呐抨?duì)這時(shí)候選 vLLM 或 SGLang 更務(wù)實(shí)。2.5 llama.cpp 的不可替代性別因?yàn)?llama.cpp 吞吐量不如 vLLM 就看不起它。在我這里它有兩個(gè)不可替代的價(jià)值第一GGUF 格式的量化模型非常省事一個(gè)文件拷走就能跑跨平臺(tái)、跨設(shè)備第二它能在沒有 NVIDIA GPU 的環(huán)境里靠 CPU 和 Apple Silicon 跑模型對(duì)開發(fā)調(diào)試和邊緣部署極其友好。很多人在本地 Mac 上把模型跑通了然后直接把同樣的模型權(quán)重丟到服務(wù)器上發(fā)現(xiàn)服務(wù)器環(huán)境一堆問題。如果你一開始就用 llama.cpp 跑 GGUF那么從筆記本到小服務(wù)器之間幾乎是無縫遷移。當(dāng)然生產(chǎn)環(huán)境我還是建議用 vLLM 或 SGLang因?yàn)?GGUF 在高并發(fā)下的吞吐表現(xiàn)確實(shí)不夠好。2.6 我的選型經(jīng)驗(yàn)綜合來看我的選型決策可以壓縮成三句話內(nèi)部高頻 API 服務(wù)默認(rèn)用 vLLM大量共享前綴或長上下文場景用 SGLang值得評(píng)估延遲要求苛刻且請(qǐng)求模式固定再考慮 TensorRT-LLM。llama.cpp 永遠(yuǎn)保留在工具箱里用來快速驗(yàn)證模型和遷移環(huán)境。有一個(gè)很容易被忽略的環(huán)節(jié)是框架的版本和模型格式的匹配。每次升級(jí)框架大版本最好先拿同一份模型權(quán)重做一次回歸測試確認(rèn)輸出質(zhì)量和延遲沒有退化。我在生產(chǎn)環(huán)境就碰到過 vLLM 升級(jí)之后某量化模型輸出概率異常的情況最后回退了版本才恢復(fù)正常。3. 云服務(wù)器對(duì)比GPU 實(shí)例的真實(shí)門檻3.1 先算明白顯存賬選擇云服務(wù)器之前第一步不是比價(jià)格而是算清楚你的模型需要多少顯存。以 FP16 精度為例模型權(quán)重的大小大約是參數(shù)量乘 2 字節(jié)。一個(gè) 7B 模型就是 14GB 權(quán)重文件一個(gè) 13B 模型就是約 26GB一個(gè) 70B 模型大約 140GB。這還沒算 KV Cache。KV Cache 是個(gè)容易被新手忽略的大頭。簡單來說生成過程中模型要緩存歷史 token 的 key 和 value 張量占用顯存和你的max_model_len、層數(shù)、注意力頭數(shù)成正比。一個(gè) 7B 模型在 8192 上下文長度下KV Cache 可能額外占幾個(gè) GB如果模型更大、上下文更長十幾個(gè) GB 甚至幾十個(gè) GB 都正常。所以我的經(jīng)驗(yàn)法則是7B 模型至少準(zhǔn)備 24GB 顯存的卡13B 模型至少準(zhǔn)備 40GB 左右的顯存或者上 48GB 的 L40S32B 模型需要 80GB 級(jí)別比如 A100/H100或者用 AWQ/GPTQ 量化后塞進(jìn) 48GB70B 模型單卡基本放不下要么兩張 80GB 卡做張量并行要么用量化方案配合多卡。3.2 三種計(jì)費(fèi)模式的分場景選擇云服務(wù)器廠商一般提供按量付費(fèi)、包月包年和競價(jià)實(shí)例三種計(jì)費(fèi)方式它們的適用場景差別很大。按量付費(fèi)適合開發(fā)和測試階段。你只需要跑半天實(shí)驗(yàn)用完就釋放不用為閑置時(shí)間買單。包月包年適合已經(jīng)上線、流量穩(wěn)定的服務(wù)雖然單價(jià)貴但按長期使用攤薄下來比按量便宜太多。競價(jià)實(shí)例適合批處理、離線推理、可容錯(cuò)任務(wù)價(jià)格可能只有按量的兩三折但隨時(shí)可能被回收不能用于核心在線服務(wù)。我個(gè)人的習(xí)慣是先按量付費(fèi)把部署流程徹底跑通壓測結(jié)果滿意之后再?zèng)Q定包月或者切競價(jià)。很多人在測試階段直接買了包月結(jié)果框架參數(shù)都沒配好白白浪費(fèi)一個(gè)月的費(fèi)用。3.3 主流云廠商 GPU 實(shí)例的橫向視角這里不點(diǎn)名推薦某一家因?yàn)楦鱾€(gè)廠商的實(shí)例變化太快但可以分享一個(gè)橫向比較的框架看卡型、看顯存、看網(wǎng)絡(luò)、看計(jì)費(fèi)靈活性、看配套服務(wù)。比較維度說明卡型同一代型號(hào)下A10/L4 適合 7B 級(jí)輕推理L40S/A100 適合 13B~32BH100/H200 適合 70B 和訓(xùn)練場景顯存24GB、48GB、80GB 三檔決定你能否單卡部署網(wǎng)絡(luò)帶寬GPU 實(shí)例如果帶寬只有 1Gbps大模型權(quán)重下載和模型更新會(huì)非常痛苦計(jì)費(fèi)靈活性是否支持按秒釋放、競價(jià)實(shí)例、包年折扣配套服務(wù)對(duì)象存儲(chǔ)、鏡像倉庫、日志服務(wù)是否順手如果你主要在國內(nèi)云環(huán)境跑通常要留意實(shí)例的可用區(qū)是否有目標(biāo)卡型的庫存熱門卡型在促銷季經(jīng)常一卡難求。如果你用海外云服務(wù)則要重點(diǎn)考慮訪問延遲和數(shù)據(jù)傳輸成本GPU 實(shí)例本身便宜但跨區(qū)域流量可能很貴。3.4 網(wǎng)絡(luò)與數(shù)據(jù)面成本模型部署之后真正消耗成本的不只是 GPU 實(shí)例本身。一次模型權(quán)重的更新可能是幾十 GB 甚至上百 GB 的數(shù)據(jù)傳輸。如果云服務(wù)器和對(duì)象存儲(chǔ)之間沒有內(nèi)網(wǎng)互通走公網(wǎng)下載不光慢流量費(fèi)用也非??捎^。所以部署前一定要確認(rèn)模型文件放在對(duì)象存儲(chǔ)的哪個(gè)區(qū)域GPU 實(shí)例是否和存儲(chǔ)在同一內(nèi)網(wǎng)。舉例來說如果模型放在北京區(qū)域的存儲(chǔ)實(shí)例也在北京就能走內(nèi)網(wǎng)高速拉取跨區(qū)域的話下載速度和費(fèi)用都不樂觀。另外一個(gè)容易忽略的點(diǎn)是出口帶寬。模型 API 返回的 token 量雖然不大但并發(fā)很高的情況下對(duì)帶寬也有要求。我曾經(jīng)在某個(gè)低帶寬的實(shí)例上壓測發(fā)現(xiàn) GPU 利用率還不到 30%延遲就已經(jīng)飆高最后定位到是出口帶寬被打滿了。這個(gè)坑很隱蔽排查成本高最好在選型階段就預(yù)留足夠的帶寬。3.5 我的建議先小后大先按量后包月操盤過幾次 GPU 實(shí)例采購之后我建議所有人在初期都采取“先小后大”的策略。先用最小可用的卡型把鏈路跑通用最小的上下文長度驗(yàn)證接口邏輯然后逐步放大。直接上頂配卡型看似省事實(shí)際上你往往不知道哪些參數(shù)需要調(diào)出了問題排查成本反而更高。另外每家公司對(duì)數(shù)據(jù)主權(quán)、日志合規(guī)、模型文件留存的規(guī)則不同選地域的時(shí)候要提前確認(rèn)。這個(gè)我不是在說玄學(xué)而是很多正規(guī)項(xiàng)目上線評(píng)審時(shí)就會(huì)卡在這一環(huán)。部署層面盡早確認(rèn)免得服務(wù)已經(jīng)跑起來了才發(fā)現(xiàn)地域不符合合規(guī)要求被迫遷移。4. 生產(chǎn)級(jí)部署流程從權(quán)重文件到穩(wěn)定 API4.1 模型準(zhǔn)備下載、校驗(yàn)與格式確認(rèn)生產(chǎn)部署的第一步是把模型權(quán)重完整拿到服務(wù)器上?,F(xiàn)在主流模型權(quán)重都托管在 Hugging Face 或國內(nèi)的 ModelScope 上官方 CLI 工具可以直接拉取。我習(xí)慣用命令行指定目錄下載避免默認(rèn)緩存目錄造成混亂huggingface-cli download Qwen/Qwen2.5-7B-Instruct --local-dir /data/models/Qwen2.5-7B-Instruct下載完成后做一個(gè)基礎(chǔ)校驗(yàn)至少確認(rèn)關(guān)鍵文件大小和目錄結(jié)構(gòu)正確。safetensors 格式的權(quán)重比 PyTorch 的.bin更適合生產(chǎn)環(huán)境因?yàn)樗忻鞔_的張量大小信息加載更安全更穩(wěn)定?,F(xiàn)在多數(shù)新模型都默認(rèn)提供 safetensors 文件如果你的模型還停留在.bin建議轉(zhuǎn)換成 safetensors 再部署。4.2 量化選型FP16、FP8、AWQ、GPTQ 怎么選框架選完之后接下來要決定用什么精度部署。這個(gè)決定直接影響顯存占用、生成質(zhì)量和部署復(fù)雜度。FP16 是最保真的選項(xiàng)模型有多少顯存需求就按多少給不需要額外折騰。但如果顯存不夠就需要量化。AWQ 和 GPTQ 是兩類流行的權(quán)重量化方法把權(quán)重壓到 4bit 或 3bit顯存占用大幅下降生成質(zhì)量通常還能保持不錯(cuò)。FP8 則是更接近無損的量化方式但需要 GPU 硬件支持比如 H100、L40S 這一代卡基本都能很好地支持 FP8 推理。我給的參考方案如下顯存充足追求穩(wěn)妥FP16省心。顯存不夠模型 30GB 以內(nèi)首選 AWQ 4bit 或者 GPTQ 4bit注意觀察輸出質(zhì)量。硬件支持 FP8優(yōu)先考慮 FP8在顯存和精度之間平衡最好。本地或邊緣設(shè)備直接用 llama.cpp 做 GGUF 的 Q4_K_M / Q5_K_M 量化。有一個(gè)經(jīng)驗(yàn)教訓(xùn)量化模型上線前一定要做一次“針對(duì)性回歸”把你業(yè)務(wù)中最常見的幾種輸入各跑一遍對(duì)比量化前后的輸出。不要只看 ppl困惑度指標(biāo)有些量化模型在復(fù)雜指令上的表現(xiàn)退化非常明顯。4.3 啟動(dòng)參數(shù)vLLM 與 SGLang 的推薦配置vLLM 啟動(dòng)一個(gè)大模型 API 服務(wù)最簡單的命令大概是python -m vllm.entrypoints.openai.api_server \ --model /data/models/Qwen2.5-14B-Instruct \ --tensor-parallel-size 1 \ --max-model-len 8192 \ --gpu-memory-utilization 0.90 \ --port 8000幾個(gè)關(guān)鍵參數(shù)的理解--tensor-parallel-size是張量并行度。單卡部署時(shí)設(shè)為 1如果模型需要兩張 80GB 卡才能放下就設(shè)為 2。--max-model-len決定最大上下文長度直接影響 KV Cache 預(yù)分配和單請(qǐng)求的顯存占用。--gpu-memory-utilization告訴框架可以占用多少比例的 GPU 顯存我通常設(shè) 0.90留出一點(diǎn)余量給 CUDA context 和碎片。如果你用 SGLang啟動(dòng)命令類似python -m sglang.launch_server \ --model-path /data/models/Qwen2.5-32B-Instruct \ --tensor-parallel-size 1 \ --max-total-tokens 16384 \ --port 30000啟動(dòng)之后你會(huì)發(fā)現(xiàn)日志里會(huì)打印初始化完成、KV Cache 池大小等信息這些輸出記得保留排查顯存問題時(shí)非常有用。4.4 服務(wù)化封裝OpenAI 兼容協(xié)議、鑒權(quán)與限流框架啟動(dòng)后默認(rèn)就暴露了 HTTP 接口。以 vLLM 為例直接可以用 curl 測試curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: Qwen2.5-14B-Instruct, messages: [{role: user, content: 你好介紹一下你自己}] }如果接口直接暴露在公司內(nèi)網(wǎng)至少要做兩層保護(hù)第一層是 API Key 鑒權(quán)vLLM 啟動(dòng)時(shí)可以加--api-key參數(shù)或者在外層網(wǎng)關(guān)統(tǒng)一校驗(yàn)第二層是限流防止某個(gè)調(diào)用方把 GPU 資源全部打滿。限流可以在 Nginx 層做也可以在 API 網(wǎng)關(guān)層做按 IP、按用戶、按服務(wù)維度分別配置 QPS 限額。4.5 部署形態(tài)systemd、容器與 Kubernetes 的取舍部署形態(tài)這個(gè)選擇取決于你的運(yùn)維基礎(chǔ)設(shè)施。如果只有一臺(tái)服務(wù)器我推薦直接用 systemd 托管推理進(jìn)程簡單可靠。寫一個(gè) service 文件設(shè)置Restarton-failure進(jìn)程崩潰能自動(dòng)拉起日志交給 journald 管理。不少團(tuán)隊(duì)在這里用 Docker但說實(shí)話在單機(jī)場景下 Docker 的優(yōu)勢并不明顯反而增加了一層鏡像構(gòu)建和卷掛載的心智負(fù)擔(dān)。如果服務(wù)要橫向擴(kuò)展到多臺(tái)服務(wù)器就得考慮容器化加 Kubernetes。vLLM 這類無狀態(tài)推理服務(wù)非常適合 Kubernetes你可以按照 GPU 資源聲明來調(diào)度配合 HorizontalPodAutoscaler 做自動(dòng)擴(kuò)縮。不過Kubernetes 的調(diào)度器對(duì) GPU 資源的分配有自己的規(guī)則需要設(shè)置好顯存資源的 requests 與 limits否則會(huì)出現(xiàn)“一臺(tái)機(jī)器上兩個(gè) pod 都申請(qǐng)了整張卡實(shí)際只有一個(gè) pod 在用”的尷尬局面。4.6 多副本與自動(dòng)擴(kuò)縮從單卡到集群當(dāng)單卡實(shí)例的吞吐量扛不住業(yè)務(wù)流量時(shí)最簡單的擴(kuò)容方式是開多副本前面掛一個(gè)負(fù)載均衡。推理框架的多副本不需要像數(shù)據(jù)庫那樣考慮數(shù)據(jù)一致性模型權(quán)重是只讀的副本之間完全獨(dú)立擴(kuò)容起來非常輕松。我推薦的做法是每個(gè)副本獨(dú)立部署一套 vLLM 或 SGLang 服務(wù)通過負(fù)載均衡把請(qǐng)求分發(fā)到不同實(shí)例。Kubernetes 環(huán)境下用 Service 加 Deployment 天然支持云廠商也有托管的負(fù)載均衡服務(wù)。如果你的請(qǐng)求量波動(dòng)很大可以基于 QPS 或 GPU 利用率設(shè)置自動(dòng)擴(kuò)縮規(guī)則。這里要注意自動(dòng)擴(kuò)縮有個(gè)延遲模型服務(wù)啟動(dòng)加載權(quán)重可能需要一兩分鐘直接落在 K8s 的默認(rèn)擴(kuò)縮策略上會(huì)導(dǎo)致擴(kuò)容滯后。更好的方式是根據(jù)流量預(yù)測提前擴(kuò)容或者設(shè)置一個(gè)較高的 CPU 利用率閾值但配合實(shí)例預(yù)熱。5. 實(shí)戰(zhàn)踩坑部署過程中最疼的五個(gè)教訓(xùn)5.1 GPU 顯存碎片導(dǎo)致隨機(jī) OOM一次完整的排查鏈路有一次我部署一個(gè) 13B 模型上線初期一切正常跑了幾天之后開始隨機(jī)會(huì)報(bào) CUDA out of memory。重啟之后又恢復(fù)一陣子然后再次出現(xiàn)。剛開始以為是并發(fā)太高于是調(diào)低了并發(fā)限制但問題依舊。后來我把 vLLM 日志拉出來發(fā)現(xiàn) OOM 時(shí)單個(gè)張量申請(qǐng)的顯存其實(shí)很小可能只有幾十 MB但就是分配不出來。我用nvidia-smi看顯存占用發(fā)現(xiàn)進(jìn)程占用的顯存里有大量零散空洞這就是顯存碎片化。最終解決思路不是壓縮模型而是給 KV Cache 池留出更合理的余量。我把--gpu-memory-utilization從 0.95 降到 0.88給框架更多緩沖空間同時(shí)顯式限制了每個(gè)請(qǐng)求的最大 token 數(shù)避免單請(qǐng)求把 cache 池?fù)纹啤U{(diào)完之后跑了兩個(gè)星期沒再出現(xiàn)隨機(jī) OOM。這個(gè)坑給我的教訓(xùn)是顯存利用率不是越高越好尤其在生產(chǎn)環(huán)境留出 10% 到 15% 的緩沖非常必要。5.2 并發(fā)一高 P99 就爆只測平均延遲的惡果另一個(gè)讓我印象深刻的坑是壓測時(shí)只看平均延遲。當(dāng)時(shí)服務(wù)用的是 vLLM單請(qǐng)求首 token 延遲大約 400ms看起來很健康。但并發(fā)加到 30 之后整體平均延遲還是 1.2 秒左右感覺還能接受可一上線就有用戶反饋“卡死了”。我后來把監(jiān)控粒度切到百分位才看明白P95 延遲到了 4 秒P99 更是飆升到了 8 秒。平均數(shù)被大量快速請(qǐng)求平均掉了真正在排隊(duì)等 GPU 計(jì)算的慢請(qǐng)求完全被掩蓋。從此之后我所有項(xiàng)目的監(jiān)控指標(biāo)第一個(gè)看的就是 P99而不是平均值。大模型推理的延遲天然具有長尾特征因?yàn)檩斎腴L度和輸出長度變化極大極端場景下某個(gè)請(qǐng)求可能比其他請(qǐng)求慢一個(gè)數(shù)量級(jí)。如果不用百分位指標(biāo)前端用戶拿到的真實(shí)體驗(yàn)很容易失真。5.3 容器啟動(dòng)后反復(fù)退出退出碼 137 和 110 的區(qū)分有段時(shí)間我們用 Kubernetes 部署推理服務(wù)發(fā)現(xiàn) Pod 啟動(dòng)后反復(fù)重啟。排查時(shí)看到退出碼是 137第一反應(yīng)是 OOMKilled也就是內(nèi)存超了。但檢查容器內(nèi)存配置后發(fā)現(xiàn)限制并不小。后來仔細(xì)看才知道Kubernetes 里 137 除了內(nèi)存限制還有可能是被外部 kill而真正的原因其實(shí)是另一個(gè)問題啟動(dòng)命令里沒有指定正確的模型目錄服務(wù)啟動(dòng)失敗但由于探針配置錯(cuò)誤Pod 一直處于未就緒狀態(tài)不斷被健康檢查殺掉表現(xiàn)也是反復(fù)重啟。這里的排查經(jīng)驗(yàn)是不要只盯著退出碼要把事件、日志、健康檢查探針三者結(jié)合起來看。退出碼 137 代表進(jìn)程被 kill但被誰 kill、為什么 kill要靠事件和日志來定位。后來我統(tǒng)一在 Deployment 里加了清晰的 startupProbe給足模型加載時(shí)間再配合 livenessProbe 做崩潰恢復(fù)這個(gè)問題才算根治。5.4 輸出亂碼與歷史對(duì)話錯(cuò)亂tokenizer 版本不匹配有一次我把模型從測試環(huán)境復(fù)制到生產(chǎn)環(huán)境用的是同一個(gè)目錄名但生產(chǎn)環(huán)境加載之后對(duì)話結(jié)果明顯異常中英混雜甚至出現(xiàn)了連續(xù)生成同一個(gè) token 的怪象。一開始懷疑 GPU 有問題換了卡還是不行。后來我對(duì)比兩個(gè)環(huán)境的tokenizer_config.json和vocab.json發(fā)現(xiàn)文件 hash 不一致。原因是測試環(huán)境用的模型目錄是舊的生產(chǎn)環(huán)境重新下載時(shí)模型版本已經(jīng)更新權(quán)重和 tokenizer 混用了。大模型的權(quán)重要和 tokenizer 嚴(yán)格綁定哪怕 tokenizer 少一個(gè)特殊 token都會(huì)導(dǎo)致亂碼和采樣分布異常。這件事之后我養(yǎng)成了兩個(gè)習(xí)慣第一模型目錄默認(rèn)帶版本號(hào)比如Qwen2.5-14B-0421避免新舊權(quán)重互相覆蓋第二每次部署前用固定腳本對(duì)模型目錄做完整性校驗(yàn)對(duì)比關(guān)鍵文件的 hash 值。5.5 壓測工具選錯(cuò)單線程 curl 造成的虛假瓶頸最早我給同事寫壓測方案圖省事直接寫了一個(gè) shell 循環(huán)用 curl 不斷請(qǐng)求接口。結(jié)果測出來最大 QPS 只有 5同事直接說服務(wù)太垃圾。我當(dāng)時(shí)也很困惑后來才發(fā)現(xiàn)問題根本不在服務(wù)而在壓測工具本身。一個(gè)串行 curl 循環(huán)意味著第一個(gè)請(qǐng)求返回之后才發(fā)第二個(gè)請(qǐng)求網(wǎng)絡(luò)連接也沒有復(fù)用來每次都要重新建 TCP 連接這測出來的完全是“串行請(qǐng)求 建連開銷”和真實(shí)并發(fā)場景沒有任何關(guān)系。要模擬真實(shí)生產(chǎn)流量至少要用支持并發(fā)、連接復(fù)用的壓測工具。前面說的這些坑我只是挑了幾個(gè)最痛的實(shí)際上還有鑒權(quán)配置錯(cuò)誤、日志沒配導(dǎo)致排障抓瞎、模型路徑硬編碼導(dǎo)致遷移失敗等等。經(jīng)驗(yàn)就是教訓(xùn)換來的別看每個(gè)坑都細(xì)碎踩多了真的會(huì)讓人懷疑人生。6. 上線前的壓測與調(diào)優(yōu)讓服務(wù)扛住真實(shí)流量6.1 構(gòu)造貼近真實(shí)場景的壓測腳本壓測不是隨便打一堆請(qǐng)求而是要盡量還原真實(shí)流量。大模型的請(qǐng)求特征和傳統(tǒng)接口完全不同它帶長文本、輸出也是流式的、不同請(qǐng)求的輸入長度差異巨大。我壓測時(shí)通常準(zhǔn)備三類請(qǐng)求模板短問題模擬一般聊天場景長系統(tǒng)提示詞加短用戶問題模擬 Agent 場景帶多輪歷史對(duì)話的請(qǐng)求模擬真實(shí)業(yè)務(wù)。三類請(qǐng)求按一定比例混在一起并發(fā)用戶數(shù)和請(qǐng)求速率也按業(yè)務(wù)預(yù)估來設(shè)。工具層面我偏好用 Locust 或者自定義 Python 腳本。因?yàn)榇竽P?API 的壓測要記錄每個(gè)請(qǐng)求的輸入長度、輸出長度、首 token 延遲、總延遲這些信息比單純統(tǒng)計(jì) QPS 有價(jià)值得多。我甚至?xí)褖簻y期間的 GPU 利用率、顯存占用、KV Cache 使用率同步采集出來方便后續(xù)一起分析。6.2 必須盯住的五個(gè)數(shù)字大模型推理服務(wù)有別于傳統(tǒng) Web 服務(wù)核心指標(biāo)也更細(xì)致。我每次壓測和上線后盯的指標(biāo)就是這五類指標(biāo)含義我關(guān)注的原因QPS每秒完成的請(qǐng)求數(shù)服務(wù)容量的直接表現(xiàn)TTFT首個(gè) token 的延遲用戶感受到的“響應(yīng)速度”TPOT每個(gè)輸出 token 的平均生成時(shí)間決定整個(gè)回復(fù)要多長時(shí)間GPU 利用率GPU 計(jì)算資源忙閑程度判斷瓶頸是算力還是排隊(duì)KV Cache 使用率顯存中的緩存池占用比例判斷是否接近容量上限vLLM 暴露了/metrics端點(diǎn)SGLang 也有類似的監(jiān)控輸出Prometheus 直接抓取就行。我在儀表盤里優(yōu)先展示這幾項(xiàng)而不是默認(rèn)的 CPU 和內(nèi)存指標(biāo)。6.3 常見瓶頸與調(diào)優(yōu)方向根據(jù)我的壓測經(jīng)驗(yàn)大模型服務(wù)的結(jié)果通常落在三種情況第一種GPU 利用率打滿TTFT 和 TPOT 都偏高。說明算力確實(shí)是瓶頸調(diào)參能改善的空間有限要么上更強(qiáng)的卡要么開多副本。第二種GPU 利用率不高但 TTFT 偏高。這說明請(qǐng)求在排隊(duì)但不是因?yàn)橛?jì)算排隊(duì)很可能在框架的調(diào)度層卡住了。這時(shí)候可以檢查max_num_seqs是否太小連續(xù)批處理是否沒生效模型加載參數(shù)是否需要調(diào)整。第三種KV Cache 使用率長期接近 1.0同時(shí)頻繁出現(xiàn)超時(shí)。這就是顯存池太小要么降低max-model-len要么開更大的顯存卡要么考慮量化模型降低單請(qǐng)求緩存占用。調(diào)優(yōu)時(shí)我還有一個(gè)習(xí)慣先做單請(qǐng)求延遲基線測試再做并發(fā)壓測。單請(qǐng)求延遲能定位到模型和框架層面的問題并發(fā)壓測能定位到調(diào)度和容量層面兩者不能混在一起看。7. 長期實(shí)踐留下的幾個(gè)部署習(xí)慣內(nèi)容寫到最后我想分享幾個(gè)長期踩坑后養(yǎng)成的部署習(xí)慣每個(gè)習(xí)慣都對(duì)應(yīng)著一次真實(shí)教訓(xùn)。第一個(gè)習(xí)慣是模型目錄永遠(yuǎn)帶版本號(hào)并且部署腳本里要做文件校驗(yàn)。這能避開權(quán)重和 tokenizer 不一致的問題也能讓多版本模型并存、快速回退。第二個(gè)習(xí)慣是啟動(dòng)參數(shù)集中管理。我把max_model_len、gpu_memory_utilization、max_num_seqs、tensor_parallel_size這些參數(shù)統(tǒng)一放到一個(gè)配置文件里每次調(diào)整都留記錄。這樣出了性能問題可以快速還原當(dāng)時(shí)的配置而不是靠記憶去猜。第三個(gè)習(xí)慣是日志默認(rèn)帶上請(qǐng)求級(jí)別信息包括輸入 token 數(shù)、輸出 token 數(shù)、TTFT 和總耗時(shí)。有了這些日志線上反饋“某個(gè)請(qǐng)求很慢”的時(shí)候我能直接定位到是輸入太長、排隊(duì)太久還是生成太多而不是兩眼一抹黑。第四個(gè)習(xí)慣是每次調(diào)整架構(gòu)或框架版本之后一定做一次小規(guī)?;貧w壓測。哪怕只是從 vLLM 0.6 升到 0.7行為也可能發(fā)生變化。推理框架版本迭代很快并不是越新越穩(wěn)。最后一個(gè)習(xí)慣是對(duì)監(jiān)控報(bào)警的 P99 閾值做動(dòng)態(tài)調(diào)整。大模型服務(wù)的延遲天然波動(dòng)固定閾值容易誤報(bào)我會(huì)根據(jù)近一周的延遲分布自動(dòng)更新基線。報(bào)警的價(jià)值不在多而在準(zhǔn)。部署大模型這門手藝說到底是把模型能力、硬件資源、框架特性、業(yè)務(wù)流量四者匹配起來的過程。沒有一組固定參數(shù)能通吃所有場景但只要理解了顯存、吞吐、延遲和成本這四本賬按這套流程走一遍至少不會(huì)出大方向上的錯(cuò)誤。希望這篇指南能幫你少踩幾個(gè)我踩過的坑。