 50 講」——從本地模型部署到多智能體系統(tǒng),一年省 87 萬(wàn) 第6節(jié))
第 06 課 | 高性能推理vLLM 部署與 OpenAI 兼容接口Ollama 好用但它是「單線程」的——一次只能處理一個(gè)請(qǐng)求。當(dāng)你跑多 Agent 系統(tǒng)的時(shí)候4 個(gè) Agent 同時(shí)發(fā)請(qǐng)求Ollama 就只能排隊(duì)。vLLM 就是來(lái)解決這個(gè)問題的高并發(fā)、高吞吐、生產(chǎn)級(jí)推理引擎。為什么需要 vLLM前兩節(jié)課我們用 Ollama 跑起了本地模型體驗(yàn)不錯(cuò)。但 Ollama 有一個(gè)明顯的局限它是一次只處理一個(gè)請(qǐng)求的。當(dāng)你跑一個(gè)簡(jiǎn)單的對(duì)話時(shí)這沒問題。但當(dāng)你在后面構(gòu)建多 Agent 系統(tǒng)時(shí)問題就來(lái)了——4 個(gè) Agent 同時(shí)向模型發(fā)請(qǐng)求Ollama 只能一個(gè)一個(gè)處理其他 3 個(gè)得排隊(duì)等著。這就好比一個(gè)餐廳只有一個(gè)廚師不管來(lái)了多少客人菜只能一道一道做??腿松俚臅r(shí)候沒問題客人一多就全堵住了。vLLM就是來(lái)解決這個(gè)問題的。它是一個(gè)高性能的 LLM 推理引擎核心特性包括連續(xù)批處理Continuous Batching動(dòng)態(tài)合并多個(gè)請(qǐng)求一起處理PagedAttention高效利用顯存支持更長(zhǎng)的上下文高吞吐量比 Ollama 快 2-4 倍特別是在并發(fā)場(chǎng)景下OpenAI 兼容 API代碼幾乎不用改切換后端就行打個(gè)比方如果 Ollama 是一個(gè)廚師vLLM 就是一個(gè)廚房——多個(gè)廚師同時(shí)做菜還能動(dòng)態(tài)調(diào)整誰(shuí)先做誰(shuí)后做。對(duì)于我們的教程來(lái)說前期開發(fā)用 Ollama 就夠了。但當(dāng)你開始跑多 Agent 系統(tǒng)場(chǎng)景三的時(shí)候vLLM 的高并發(fā)能力就派上用場(chǎng)了。vLLM 核心特性先簡(jiǎn)單了解 vLLM 的兩個(gè)核心技術(shù)。你不需要成為專家但理解它們有助于你做出正確的架構(gòu)選擇。PagedAttention傳統(tǒng)的 LLM 推理會(huì)把整個(gè) KV Cache注意力機(jī)制的中間結(jié)果放在連續(xù)的顯存空間里。但顯存是稀缺資源連續(xù)的顯存空間更難找。PagedAttention 借鑒了操作系統(tǒng)虛擬內(nèi)存的思想把 KV Cache 分成固定大小的「頁(yè)」不需要連續(xù)存儲(chǔ)。這樣顯存利用率大幅提升能支持更長(zhǎng)的上下文和更大的批處理。連續(xù)批處理傳統(tǒng)批處理是等一個(gè)批次的所有請(qǐng)求都完成后才開始處理下一個(gè)批次。如果批次里有一個(gè)請(qǐng)求特別長(zhǎng)其他請(qǐng)求就得等它完成。連續(xù)批處理更聰明它動(dòng)態(tài)地把新請(qǐng)求加入正在處理的批次把已完成的請(qǐng)求移出。這樣 GPU 始終在滿負(fù)荷工作吞吐量大幅提升。vLLM 連續(xù)批處理請(qǐng)求 1 2 3一起處理總耗時(shí) 6sOllama 單請(qǐng)求請(qǐng)求 1處理 5s請(qǐng)求 2處理 5s請(qǐng)求 3處理 5s圖 1Ollama 單請(qǐng)求 vs vLLM 連續(xù)批處理安裝 vLLMvLLM 的安裝比 Ollama 稍微復(fù)雜一點(diǎn)因?yàn)樗枰?CUDA 環(huán)境。首先確認(rèn)你的 NVIDIA 驅(qū)動(dòng)和 CUDA 版本nvidia-smi看輸出里的CUDA Version字段應(yīng)該是 12.x 以上。然后安裝 vLLMuv pip install vllm如果你遇到安裝問題可能是因?yàn)?Windows 上 vLLM 的支持不如 Linux 完善。vLLM 官方主要支持 LinuxWindows 上可能需要通過 WSL2 來(lái)運(yùn)行。如果你的 Windows 環(huán)境安裝 vLLM 有困難不用擔(dān)心——Ollama 已經(jīng)足夠支撐我們學(xué)完大部分課程。vLLM 主要在后期的多 Agent 高并發(fā)場(chǎng)景才體現(xiàn)出優(yōu)勢(shì)。你可以先把 Ollama 用熟后面需要 vLLM 的時(shí)候再裝。啟動(dòng) vLLM 服務(wù)安裝成功后啟動(dòng) vLLM 服務(wù)python-m vllm.entrypoints.openai.api_server \--model Qwen/Qwen2-7B-Instruct \--host 0.0.0.0 \--port 8000 \--max-model-len 8192 \--gpu-memory-utilization 0.85參數(shù)說明--model模型名稱vLLM 會(huì)自動(dòng)從 HuggingFace 下載--host 0.0.0.0監(jiān)聽所有網(wǎng)絡(luò)接口--port 8000服務(wù)端口--max-model-len 8192最大上下文長(zhǎng)度--gpu-memory-utilization 0.85顯存使用率上限留 15% 給系統(tǒng)服務(wù)啟動(dòng)后vLLM 會(huì)提供一個(gè) OpenAI 兼容的 API地址是http://localhost:8000。驗(yàn)證一下curl http://localhost:8000/v1/models如果返回模型列表就說明服務(wù)啟動(dòng)成功了。用 Python 調(diào)用 vLLMvLLM 的 API 和 Ollama 幾乎一樣——都是 OpenAI 兼容格式。這意味著你之前寫的調(diào)用代碼幾乎不用改就能用。# vllm_chat.py - 用 Python 調(diào)用 vLLM# AI Agent 全棧開發(fā) 50 講 - 第 06 課importrequestsdefchat_vllm(prompt:str,model:strQwen/Qwen2-7B-Instruct)-str:調(diào)用 vLLM 的 OpenAI 兼容 APIurlhttp://localhost:8000/v1/chat/completionspayload{model:model,messages:[{role:user,content:prompt}],temperature:0.7,}responserequests.post(url,jsonpayload,timeout120)response.raise_for_status()resultresponse.json()returnresult[choices][0][message][content]defmain():replychat_vllm(用 3 句話總結(jié)一下 AI Agent 的核心價(jià)值。)print(fvLLM 回復(fù):\n{reply})if__name____main__:main()看到了嗎代碼和第 4 課的ollama_chat.py幾乎一模一樣只是 URL 從localhost:11434變成了localhost:8000。這就是 OpenAI 兼容 API 的好處——切換后端幾乎零成本。性能對(duì)比vLLM vs Ollama我們用腳本測(cè)試一下 vLLM 和 Ollama 的性能差異。# vllm_benchmark.py - vLLM vs Ollama 性能對(duì)比# AI Agent 全棧開發(fā) 50 講 - 第 06 課importrequestsimporttimeimportconcurrent.futuresdefsingle_request(url:str,model:str,prompt:str)-dict:單次請(qǐng)求測(cè)試payload{model:model,messages:[{role:user,content:prompt}],temperature:0.7,}starttime.time()responserequests.post(url,jsonpayload,timeout120)elapsedtime.time()-start contentresponse.json()[choices][0][message][content]tokenslen(content)/2return{elapsed:round(elapsed,2),tokens_per_second:round(tokens/elapsed,1),}defconcurrent_requests(url:str,model:str,prompt:str,n:int5)-dict:并發(fā)請(qǐng)求測(cè)試starttime.time()withconcurrent.futures.ThreadPoolExecutor(max_workersn)asexecutor:futures[executor.submit(single_request,url,model,prompt)for_inrange(n)]results[f.result()forfinfutures]total_elapsedtime.time()-start avg_tpssum(r[tokens_per_second]forrinresults)/len(results)return{total_elapsed:round(total_elapsed,2),avg_tokens_per_second:round(avg_tps,1),requests:n,}defmain():prompt用 200 字介紹一下人工智能的發(fā)展歷程。print(*60)print( vLLM vs Ollama 性能對(duì)比)print(*60)# 測(cè)試配置configs[{name:Ollama (Qwen2 7B),url:http://localhost:11434/v1/chat/completions,model:qwen2:7b},{name:vLLM (Qwen2 7B),url:http://localhost:8000/v1/chat/completions,model:Qwen/Qwen2-7B-Instruct},]forconfiginconfigs:print(f\n[{config[name]}])# 單請(qǐng)求測(cè)試try:resultsingle_request(config[url],config[model],prompt)print(f 單請(qǐng)求:{result[elapsed]}s,{result[tokens_per_second]}tokens/s)exceptExceptionase:print(f 單請(qǐng)求: [錯(cuò)誤]{e})# 并發(fā)測(cè)試5 個(gè)并發(fā)try:resultconcurrent_requests(config[url],config[model],prompt,n5)print(f 5 并發(fā): 總耗時(shí){result[total_elapsed]}s, 平均{result[avg_tokens_per_second]}tokens/s)exceptExceptionase:print(f 5 并發(fā): [錯(cuò)誤]{e})if__name____main__:main()在我的 RTX 3090 上測(cè)試結(jié)果如下測(cè)試項(xiàng)OllamavLLMvLLM 提升單請(qǐng)求速度~45 tokens/s~50 tokens/s11%5 并發(fā)總耗時(shí)~25 秒~7 秒3.6x5 并發(fā)平均速度~9 tokens/s~36 tokens/s4x關(guān)鍵發(fā)現(xiàn)單請(qǐng)求速度vLLM 比 Ollama 略快但差距不大11%。并發(fā)場(chǎng)景vLLM 的優(yōu)勢(shì)非常明顯。5 個(gè)并發(fā)請(qǐng)求vLLM 的總耗時(shí)只有 Ollama 的 1/3.6平均速度是 Ollama 的 4 倍。這就是連續(xù)批處理的威力。當(dāng)多個(gè)請(qǐng)求同時(shí)到達(dá)時(shí)vLLM 能把它們合并成一個(gè)批次一起處理GPU 利用率大幅提升。Ollama vs vLLM如何選擇是否你的場(chǎng)景是什么本地開發(fā)/個(gè)人使用生產(chǎn)部署/多 Agent用 Ollama簡(jiǎn)單、快速、夠用需要高并發(fā)用 vLLM高吞吐、低延遲Ollama 也行簡(jiǎn)單優(yōu)先圖 2Ollama vs vLLM 選擇決策樹維度OllamavLLM安裝難度簡(jiǎn)單一行命令中等需要 CUDA使用難度簡(jiǎn)單中等單請(qǐng)求速度好略好并發(fā)能力弱串行處理強(qiáng)連續(xù)批處理適用場(chǎng)景本地開發(fā)、個(gè)人使用生產(chǎn)部署、多 AgentWindows 支持好一般建議 WSL2我的推薦開發(fā)階段用 Ollama。簡(jiǎn)單、快速、夠用。生產(chǎn)部署用 vLLM。高并發(fā)、高吞吐、更穩(wěn)定。教程學(xué)習(xí)前期用 Ollama后面多 Agent 場(chǎng)景再切換到 vLLM。統(tǒng)一 LLM 客戶端設(shè)計(jì)為了讓代碼能在 Ollama 和 vLLM 之間無(wú)縫切換我們?cè)O(shè)計(jì)一個(gè)統(tǒng)一的 LLM 客戶端。# llm_client.py - 統(tǒng)一 LLM 客戶端# AI Agent 全棧開發(fā) 50 講 - 第 06 課importrequestsfromconfigimportLLM_BACKEND,LLM_MODEL,LLM_BASE_URL,LLM_API_KEYclassLLMClient:統(tǒng)一的 LLM 客戶端支持 Ollama 和 vLLMdef__init__(self,backend:strNone,model:strNone,base_url:strNone):self.backendbackendorLLM_BACKEND self.modelmodelorLLM_MODEL self.base_urlbase_urlorLLM_BASE_URL self.api_keyLLM_API_KEYdefchat(self,messages:list,temperature:float0.7)-str:發(fā)送聊天請(qǐng)求 Args: messages: 消息列表 [{role: user, content: ...}] temperature: 溫度參數(shù) Returns: 模型回復(fù)文本 urlf{self.base_url}/chat/completionsheaders{}ifself.api_keyandself.api_key!ollama:headers[Authorization]fBearer{self.api_key}payload{model:self.model,messages:messages,temperature:temperature,}responserequests.post(url,jsonpayload,headersheaders,timeout120)response.raise_for_status()resultresponse.json()returnresult[choices][0][message][content]def__repr__(self):returnfLLMClient(backend{self.backend}, model{self.model})defmain():# 創(chuàng)建客戶端自動(dòng)讀取配置clientLLMClient()print(f客戶端:{client})# 測(cè)試對(duì)話messages[{role:system,content:你是一個(gè)專業(yè)的市場(chǎng)分析師。},{role:user,content:用 2 句話總結(jié) AI Agent 的核心價(jià)值。}]replyclient.chat(messages)print(f\n回復(fù):\n{reply})if__name____main__:main()這個(gè)客戶端通過配置文件自動(dòng)選擇后端。想切換 Ollama 和 vLLM只需要改.env文件里的LLM_BASE_URL# 用 OllamaLLM_BASE_URLhttp://localhost:11434/v1# 用 vLLMLLM_BASE_URLhttp://localhost:8000/v1代碼完全不用改。這就是統(tǒng)一接口設(shè)計(jì)的好處。小結(jié)與預(yù)告這節(jié)課我們學(xué)習(xí)了 vLLM——一個(gè)生產(chǎn)級(jí)的高性能推理引擎。核心收獲vLLM 的優(yōu)勢(shì)連續(xù)批處理、PagedAttention、高并發(fā)性能對(duì)比并發(fā)場(chǎng)景下 vLLM 比 Ollama 快 3-4 倍統(tǒng)一客戶端封裝了 LLMClient支持 Ollama 和 vLLM 無(wú)縫切換現(xiàn)在你有了兩個(gè)推理引擎可選Ollama 適合開發(fā)vLLM 適合生產(chǎn)。后面的課程中我們會(huì)根據(jù)場(chǎng)景靈活切換。下一節(jié)課我們會(huì)把 Ollama、vLLM、OpenAI API 統(tǒng)一封裝成一個(gè)客戶端通過配置文件一鍵切換。這是整個(gè)教程的基礎(chǔ)設(shè)施——后面所有的 Agent 調(diào)用都通過這個(gè)客戶端完成。我們下一課見。系列教程導(dǎo)航上一篇第 05 課 | 模型量化與優(yōu)化讓 14B 模型也能流暢運(yùn)行下一篇第 07 課 | 統(tǒng)一 LLM 客戶端本地與云端 API 無(wú)縫切換本系列共 50 課持續(xù)更新中。關(guān)注我不迷路。