引擎選型:
Ollama vs vLLM
同一台電腦、同一顆 8B 模型,換一個推理引擎,體感差很多——但差的地方常常跟你以為的不一樣。 先別看規格表,點一個最像你的情境,看看該用哪一個:
看出規律了嗎?會亮起 vLLM 的四個情境是:同時很多人、同一段長前綴一直重複、 想把 KV cache 挪到 SSD 或別台機器,以及由前三者堆出來的「正式產品 API」。 這不是巧合——三件事其實是同一件事。這一課要證明的就是: 兩個引擎所有面向的差異,都可以回推到同一個源頭:KV cache 的記憶體怎麼發下去。 右邊的實驗場會把這件事真的算給你看。首次載入約 30–60 秒,正好夠你讀完第 1 節。
一個求方便,一個求效能
先把兩者放回它們被造出來的位置。Ollama 是本地端易用工具,底層是 llama.cpp——純 C/C++ 的單一執行檔,沒有 Python、沒有 CUDA runtime 依賴, 所以 ollama run 下載完模型就能跑,Mac、小顯卡、純 CPU 都吃得下。
vLLM 是生產級高吞吐推理引擎,底層是 PagedAttention + continuous batching—— 這兩項技術都是為了榨乾 GPU 而生,離開 GPU 就沒有舞台,所以它幾乎必須要有 NVIDIA 顯卡、 而且 VRAM 要夠。它是很多開源大模型公司發布前會一起做適配的對象,也是不少推論服務的內部選擇。
有兩件事常被誤會,先講清楚,免得你用錯理由做決定:
- 「OpenAI 相容 API 是 vLLM 的專利」——不是。 Ollama 也有,把 base_url 指到 http://localhost:11434/v1/、api_key 隨便填一個字串 (它要求要有、但不檢查),官方 openai SDK 就能直接打。
- 「GGUF 只有 Ollama 能跑」——也不是。 GGUF 是 llama.cpp 專案自己發明的格式,是 Ollama 的主場沒錯,但 vLLM 也支援載入 GGUF。 只是那不是它的最佳狀態,它主打的是 GPU 側的 AWQ / GPTQ / FP8。
所以選型的分界線不在「有沒有某個功能」,而在脾氣——同一件事,兩者用完全不同的方式做。 下一節那張表就是把脾氣攤開來看。
八個面向,一眼看完
這張表值得看兩次。第一次由上往下讀,知道差在哪; 第二次回頭找:其中有一列是其他七列的原因。
| 面向 | Ollama(llama.cpp) | vLLM |
|---|---|---|
| 安裝門檻 | 極低,ollama run 即用 | 較高,需要 Python / CUDA 配置 |
| KV Cache 管理 | Slot 固定分配(包廂制) | PagedAttention 動態分頁(拼桌制) |
| Prefix Caching | 陽春,只在 slot 內找相同前綴 | 完整,自動跨請求重用相同前綴 block |
| 並發能力 | 低~中,slot 有限又容易浪費 | 高,continuous batching 吞吐強 |
| 量化支援 | 強項,GGUF 各種量化 | 主打 GPU:AWQ / GPTQ / FP8 |
| 硬體需求 | 友善,CPU / 小顯卡 / Mac 皆可 | 幾乎必須 NVIDIA GPU,VRAM 要足 |
| 模型切換 | 極方便,多模型隨叫隨載 | 一個實例綁一個模型,重啟才換 |
| 擴展生態 | 內建即全部,無外掛需求 | 可搭 LMCache、PD 分離(Prefill/Decode 拆節點) |
找到了嗎?答案是第二列。KV Cache 怎麼管,直接決定了 Prefix Caching 做不做得到、 並發撐不撐得住、能不能接 LMCache 這類外掛——第 3、4、8 列全是它的下游。 剩下的差異則來自另一條線:C++ 單檔執行 vs PyTorch/CUDA 決定了第 1、6 列的安裝門檻與硬體需求, GGUF vs AWQ/FP8 決定了第 5 列各自的主場。
整張表其實只有兩個根:記憶體怎麼發,以及底層用什麼寫的。下一節先挖第一個。
包廂制 vs 拼桌制:KV cache 怎麼發
模型每生成一個 token,都要把前面所有 token 的 key/value 留在 VRAM 裡(就是 KV cache)。 這塊記憶體怎麼分給同時進來的請求,兩個引擎的答案完全相反。
llama.cpp 是包廂制:服務啟動時就預先切好幾個 slot,每個 slot 綁一個 sequence、 容量等於模型的 context length。開幾個 slot 是啟動參數決定的:
注意那個預設值:-np 不給就是 1——一個模型同一時間只服務一個生成請求。 而且包廂訂了就是你的:一個請求只用了 50 個 token,slot 卻佔著 4096,剩下的整塊空著也沒人能用, 利用率可能只剩個位數。
vLLM 是拼桌制:記憶體切成小 block(一塊 16 個 token),誰要誰拿、用多少拿多少, 只有最後一塊沒填滿才有零頭。幾乎不浪費,還能讓不同請求共用同一段前綴的 block。
到右邊拉「請求平均長度」跟「離散度」,兩制的利用率會當場重算。預設參數下 (8 個請求、平均 400 tokens、slot context 4096)算出來是 slot 制 9.1%、paged 制 98.1%——同一批請求,slot 制要多花約 10.8 倍的記憶體才裝得下。 然後把平均長度拉到最右邊,看差距怎麼塌掉。
第二張圖把帳面數字換成人:同一塊 KV 預算(預設 48k tokens), slot 制永遠只有 11 個位子——那是一條水平線,請求短不短它一點都不在乎; paged 制在平均 400 tokens 時能同時服務約 107 個請求,等請求長到接近 context 上限才掉回來。
VRAM 的兩種脾氣:用完就放 vs 開著就佔
第二個差異跟記憶體多寡無關,跟什麼時候佔著有關。
- Ollama:用完就放。第一次推理才把模型載進 GPU,閒置預設 5 分鐘自動卸載、把 VRAM 還給你。 想讓它別走,設 OLLAMA_KEEP_ALIVE=-1 就永久常駐。
- vLLM:開著就佔。權重加 KV cache 空間在啟動時全部預配好,之後一直佔著 GPU—— 換來的是穩定可預測的高吞吐。
這筆交易的價碼,實測(RTX 4090、Llama 3.1 8B Q4_K_M、閒置後第一次請求)長這樣:
| 指標 | Ollama | vLLM |
|---|---|---|
| 冷啟動首 token 延遲 | 8.3 秒 | 0.4 秒 |
| 冷啟動 tokens/s | 31 | 128(約 4.2×) |
| 暖機後穩態 tokens/s | 138 | 142(幾乎一樣) |
| VRAM 佔用 | 6.4 GB | 8.2 GB |
第三列是這張表最容易被跳過、也最重要的一列:暖機之後兩者穩態速度幾乎一樣(138 vs 142)。 你在自己電腦上「感覺 vLLM 比較快」的那個快,多半來自第一列——差別只在冷啟動。
那冷啟動多常發生?取決於你的使用節奏。右邊第三張圖模擬一段時間內零星進來的請求 (到達時間是抽出來的教學模型,不是實測),畫出誰在什麼時候佔著 GPU。 預設參數(平均間隔 8 分鐘、卸載門檻 5 分鐘、4 小時)下:27 個請求裡有 17 個踩到冷啟動(63%),光等模型上車就多花了 141 秒; 但同一段時間 Ollama 平均只佔著 2.9 GB,vLLM 從頭到尾佔滿 8.2 GB。
把「平均間隔」拉到 1 分鐘(像真的有人在用的產品),冷啟動幾乎歸零、Ollama 也一直佔著 VRAM, 兩邊的差別瞬間變小;拉到 20 分鐘(你自己偶爾問一句),幾乎每一發都是冷啟動, 但你的 GPU 有八成時間是空的,可以拿去跑別的事。 沒有誰對誰錯,只有你願不願意用閒置的 VRAM 換那 8 秒。
順帶一提,Ollama 另有 Cloud 模式(ollama run gemma4:31b-cloud)可以試更大的模型, 免費額度按 GPU 時間計費、有每 5 小時與每 7 天的雙重上限(社群回報約每 5 小時 135 次請求、 每週 500 萬 token 的量級,尖峰時段會降速)——夠拿來聊天、試模型,撐不了持續的 agent 工作。
「34.2×」不是快 34 倍
做完選型你一定會遇到 benchmark 圖:三根柱子、最右邊那根特別高,配一個大大的倍數。 這一節用一個真實的例子練習怎麼讀它——引用的是一份公開的吞吐對照 (Ollama 跑 Q4_K_M 4-bit、vLLM 跑 BF16 16-bit,第三根柱子是 32 個人同時打時整台機器的總吞吐 1606.78 tokens/s,標題倍數 34.2×, 第 1 對第 2 根是 4.6×)。
兩個陷阱疊在一起:
- 總量 vs 單人。1606.78 是 32 個人加起來的量。攤到每個人身上是 50 tokens/s,對上 Ollama 的 47——只有 1.07×。 標題那個 34.2× 是機器的,不是你的。
- 精度不同。第 1 根跑 4-bit、第 2 根跑 16-bit,本來就不是同一件事。 理論上 4-bit 更省記憶體、更該快,實際卻慢了 4.6 倍——那是量化實作與 kernel 的差別, 不能全記在「引擎比較快」頭上。
這不是要戳破 vLLM——吞吐本來就是它的賣點。32 個人同時打還能維持每人 50 tokens/s, 這正是 slot 制做不到的事(回頭看 03 節那條水平線)。只是它換來的是服務更多人, 不是「讓你一個人快 34 倍」。
什麼時候選誰
把前面五節收成一張可以帶去開會的清單。左欄的共同點是少量、間歇、要方便; 右欄的共同點是很多人、重複前綴、要壓榨 GPU。
| 選 Ollama,當你… | 選 vLLM,當你… |
|---|---|
| 在筆電 / Mac 上本地玩模型(CPU 與 Apple Silicon 都能跑) | 要做正式產品的後端 API(高吞吐、OpenAI 相容、穩定) |
| 做快速原型 / Demo / POC,需要常換模型 | 有高並發(多人同時打),continuous batching 吞吐遠勝 |
| 要在現場示範,環境穩、指令簡單最重要 | 有很長的 system prompt 一直重複用(自動 prefix caching 大降 TTFT) |
| 使用者少、請求間歇,單請求延遲已經夠好 | 想把 KV cache 存到 SSD 或跨實例共享(vLLM + LMCache,Ollama 做不到) |
| 顯卡小、想跑量化模型(GGUF + CPU/GPU 混合是它的主場) | 在意 GPU 利用率與成本(PagedAttention 不浪費記憶體) |
一條夠用的量尺:有 NVIDIA GPU、並發超過 20~50、而且是要上線的產品 API → vLLM; 其餘情況先 Ollama。
順帶一提:GGUF 與 MLX
同一顆模型會有多種打包格式,模型庫(如 ollama.com/library)上常常兩種都有:
- GGUF:跨平台通用,記憶體省、相容性最好、生態最成熟——哪裡都能跑。
- MLX(4-bit):Apple 原生格式,同尺寸模型下更快,但只在 Apple Silicon 有效。
規則簡單到一句話:在 Mac 上,有 MLX 就選 MLX,沒有再退回 GGUF;其他平台一律 GGUF。
真的要架起來的時候
決定用 vLLM 之後,別從空白檔案開始寫啟動指令。官方 recipes 才是起點: recipes.vllm.ai 收錄了各個模型的啟動指令與 compose 檔,大部分複製下來直接就能跑。
但它偶爾會缺件——最典型的是多模態模型缺依賴。例如語音轉文字的 Qwen3-ASR, 官方指令跑起來會缺音訊處理的套件,要自己補上 ffmpeg 與 librosa / soundfile / av / resampy:
注意那兩個參數:--gpu-memory-utilization 就是在講這一課的主題—— 你要撥多少比例的 VRAM 給這個實例預配(權重+KV cache); --max-num-seqs 則是同時最多幾個 sequence。 同一張卡要塞好幾個模型時,這兩個數字就是你的預算分配表。
然後是最務實的一招:整段丟給 AI 執行、讓它自己修到好。 把 recipe、錯誤訊息、健康檢查一起貼給它,錯了讓它改、改完再測, 直到服務健康、測試通過為止。部署失敗的訊息通常都很直白(缺套件、port 撞了、VRAM 不夠), 這正是 AI 最擅長的迴圈。
而在部署之前:先確認模型值得部署
選模型不要只看參數量。兩個成本很低的動作可以幫你省下整晚的部署時間:
- 去 Hugging Face Spaces 線上試玩。多數熱門模型都有官方 Space, 不用裝任何東西就能丟輸入進去。中文使用者有個好用的測試句: 丟「臺灣用繁體字」「台北 101」進去,看它會不會把繁體簡化掉、或把數字辨錯—— 這種毛病部署完才發現最痛。
- 再看 Arena 的盲測排名。 arena.ai 不是固定題庫,而是網友盲測投票、再用統計模型把幾百萬次投票換算成排名—— 比單一 benchmark 分數更能反映「一般人用起來覺得好不好」。
順序記起來就好:Spaces 試玩 → Arena 對排名 → recipes 抄配方 → AI 陪你除錯。
換你動手
右邊實驗場最後一節是你的沙盒,三個挑戰由易到難(每個都有折疊解答,卡住就打開):
把「請求平均長度」拉到 3800、「離散度」拉到 0,看兩制的利用率變成幾 %, 並用一句話解釋為什麼差距不見了。(提示:浪費=配額減去實際用量。)
掃描平均長度 200 → 4000,畫出「slot 制要多花幾倍記憶體」的曲線, 找出這個倍數掉到 2× 以下的平均長度。那個交叉點就是你的選型分水嶺。
加進 prefix caching:假設每個請求前面都掛著同一段 800 token 的 system prompt, PagedAttention 可以讓所有請求共用那幾塊 block,slot 制不行。重算兩制的配置量, 再回答:請求數從 5 變成 20 時,差距是怎麼變的?
做完這三題,你對「引擎的差異來自記憶體怎麼管」就不只是聽說了,是自己算過。 下一課我們把鏡頭再往裡推一層:記憶體管好之後,模型每一步到底怎麼從幾萬個字裡挑出下一個字—— 那幾顆你在 API 裡看過卻沒調過的取樣參數,其實各自在做很不一樣的事。
情境測驗
離開前試試看:下面的情境都真的會遇到。每題選一個你認為的最佳做法,選了馬上看得到解釋。
Q1 情境題
你要把一個內部問答服務上線:尖峰約 30 人同時打,每次請求都掛著同一份 6000 token 的規章當 system prompt,機器上有一張 NVIDIA 顯卡。該用哪個引擎、為什麼?
這題三個條件全部指向 vLLM:30 人同時打(continuous batching)、長前綴重複(自動 prefix caching 跨請求重用相同 block,大降 TTFT)、有 NVIDIA GPU(vLLM 的前提)。A 的問題是換機器解不了架構問題——slot 制的位子數由啟動參數決定,跟卡多好無關。B 是常見誤解:-c 是總 context,會平分給各 slot,開 30 個 slot 等於每人分到 1/30 的 context,6000 token 的規章根本放不進去;而且 slot 制的前綴共享只在同一個 slot 內找,30 份規章要各存一份。D 沒解決任何問題,只是把兩份維運成本都扛下來。
Q2 情境題
你在自己的 MacBook 上做原型,一天大概問十幾次,會在三、四個模型之間比較答案,希望不用時 GPU 記憶體還給系統。該怎麼選?
三個條件(Mac、要常換模型、希望閒置時還記憶體)正好命中 Ollama 的三個強項:Apple Silicon 友善、多模型隨叫隨載、閒置自動卸載。而在 Mac 上同一顆模型若有 MLX 版就選 MLX(同尺寸更快),沒有再退回 GGUF。A 幾乎行不通——vLLM 天生 GPU-bound、實務上綁 NVIDIA,而且一個實例只綁一個模型,「比較三四個模型」要重啟三四次。C 部分正確但方向相反:你明講了希望不用時把記憶體還回來,永久常駐正好違反這個需求(而且四個模型全常駐,VRAM 也未必塞得下)。D 是換題目,不是回答題目——本課的前提就是要在自己機器上跑。
Q3 錯誤診斷
同事拿一張 benchmark 圖來說服你換引擎:「vLLM 快 34 倍」。圖上的數字如下。這個結論最主要的問題是?
兩個陷阱疊在一起。第一,總量不是每個人的體感:1606.78 ÷ 32 ≈ 50 tokens/s,對上 Ollama 的約 47,實際只有 1.07×——34.2× 是機器的,不是使用者的。第二,bar 1 與 bar 2 精度不同(Q4_K_M 4-bit vs BF16 16-bit),那是兩件事的比較,4.6× 裡有一部分來自量化實作與 kernel,不是純粹的引擎差異。A 的算術確實沒錯,錯在把「機器總吞吐比」講成「快 34 倍」;B、C 都是症狀相似但方向不對——問題不在數字量錯了,而在拿來比的東西不對等。正確的讀法是問三句:幾個人同時打?兩邊精度一不一樣?倍數是總量還是單人?
Q4 錯誤診斷
你用 Ollama 架了一個內部小助手,同事回報:「早上第一次問要等快 10 秒才出字,之後就順了;午休回來又變慢。」實測數據如下。最可能的原因與修法是?
「第一次慢、之後順、閒一陣子又慢」是 Ollama 閒置卸載的典型指紋:預設 5 分鐘沒人用就把模型從 VRAM 卸掉,下一發請求得重新載入,也就是那 8.3 秒。修法有兩條,取捨在你:OLLAMA_KEEP_ALIVE=-1 讓它常駐(換來 VRAM 一直被佔著),或接受冷啟動、把閒置的 VRAM 留給別的用途。A 沒對上症狀——真是模型太大,每一次都會慢,不會只有第一次;而且穩態 138 tokens/s 已經很好了。B 症狀相似但排除得掉:同一條連線午休後再變慢,指向的是伺服器端的狀態而不是網路交握。D 是排隊症狀(大家同時都慢),跟「第一發慢、後面快」的時間形狀不同。
Q5 情境題
你在 vLLM 上跑一個聊天服務,多數請求只有兩三百 token,但 GPU 記憶體一直很吃緊,同時能服務的人數上不去。想先確認「換成 slot 固定分配會不會比較省」,最有效的驗證方式是?
這題考的是「知道結論就不用做實驗」。兩制的差距是一條可以直接推的曲線:請求越短、長度越參差,slot 制浪費越多——課裡預設參數(平均 400 tokens)算出來就是 9.1% vs 98.1%。你的請求只有兩三百 token,正是 paged 制領先最多的區間,換過去只會更糟。真正該做的是調 vLLM 自己的旋鈕:撥更高比例的 VRAM 給 KV cache(--gpu-memory-utilization)、把 --max-model-len 收到實際需要的長度。B 能執行但代價極高——花一週驗一件算得出來的事。C 等於自廢武功:把 block 撐到 context 大小,就是把拼桌制改回包廂制。D 部分正確(量化確實省記憶體)但答錯了問題,而且會動到輸出品質,跟「slot 還是 paged」無關。