副标题:vLLM 本地部署 · AI 提效
本文为 vergex.cn 原创首发,转载请注明出处。
你在本地工作站装好驱动,Ollama 三分钟跑通,vLLM 折腾一天还报 NCCL 超时——多数人选型失败,不是因为某个框架更慢,而是把“模型跑起来”和“模型服务化”混为一谈。
先别比性能:你的场景到底属于哪一类
判断框架前先回答三个问题:谁会调用模型、调用频率如何、失败成本多高。个人写代码、做摘要、跑单轮对话,Ollama 的“模型即容器”体验更轻;一旦要为团队内部 API、Agent 编排或多用户并发提供稳定服务,vLLM 的 Continuous Batching 和 PagedAttention 才是正确的起点。第二个维度是显存与模型规模的匹配度:单卡能装下、且并发<=4 的轻量场景,Ollama 的 GGUF 量化标签(Q4_K_M、Q8_0)可以按桶选型;模型超过单卡或需要百级并发时,vLLM 的 Tensor/Pipeline Parallel 几乎是必选项。第三个维度常被忽略——你是否把模型当成需要版本管理的制品。Ollama 的 manifest+blob 机制和 Modelfile 天然适合做“本地模型镜像”,vLLM 则更像一个无状态的推理进程,模型文件只是启动参数。这三个维度我们在站点整理成了可打印的选型速查表,完整版见站点。
Ollama 的真实定位:不是“低配版”,而是“模型容器化”
很多文章把 Ollama 描述成“新手玩具”,但它真正的设计语义是本地模型的 Docker。~/.ollama/models 下有两个关键目录:manifests/ 存的是类似镜像清单的 JSON,blobs/ 存的是按 SHA256 命名的 GGUF 权重和模板文件。ollama pull 不是简单下载一个文件,而是在拉取 content-addressable 的 blob,这正是它能做增量更新、多 tag 共享底层权重的原因。
实操上,不要只会在命令行 ollama run。遇到需要固定系统提示、温度、上下文长度的场景,应该写 Modelfile:
FROM llama3.1:8b-instruct-q8_0
SYSTEM """You are a senior SRE assistant. Keep answers under 200 words."""
PARAMETER temperature 0.3
PARAMETER num_ctx 8192
PARAMETER top_p 0.9
ollama create sre-bot -f ./Modelfile
OLLAMA_NUM_PARALLEL=4 OLLAMA_MAX_LOADED_MODELS=1 ollama serve
OLLAMA_NUM_PARALLEL 控制的是服务端能同时处理的请求数,而不是客户端并发数;它的调度粒度是“会话”级别的简单并行,不是 vLLM 意义上的连续批处理。因此 Ollama 更适合“偶发并发”而非“高并发流水线”。另外,ollama serve 默认只监听 127.0.0.1:11434,如果要让局域网内其他机器访问,必须显式设置 OLLAMA_HOST=0.0.0.0:11434,这一点在文档里并不显眼。
vLLM 的选型门槛:当单卡推理不够用时
vLLM 的门槛不是安装,而是拓扑意识。很多人在 vllm serve 里直接加 --tensor-parallel-size 2 就以为万事大吉,结果在多路工作站或双路服务器上遇到 NCCL 超时、P2P 错误,根本原因是没先看 GPU 互联拓扑。正确流程是:
nvidia-smi topo -m
如果两张卡在同一 NUMA 节点且通过 NVLink 或 PCIe Switch 互联,TP(张量并行)收益最大;如果跨 NUMA 或只靠 QPI/UPI,张量并行的通信开销会把推理延迟吃掉。此时更稳妥的做法是:
- 同一 NUMA 内的卡做 TP;
- 跨 NUMA 用 Pipeline Parallel,或干脆拆成两个独立实例做路由。
最小可复现的 vLLM 启动命令如下,参数都是 2026 年主线版本支持的 flag:
vllm serve "unsloth/Llama-3.1-8B-Instruct" \
--dtype bfloat16 \
--max-model-len 8192 \
--gpu-memory-utilization 0.85 \
--tensor-parallel-size 1 \
--enable-prefix-caching \
--enable-chunked-prefill \
--max-num-seqs 256 \
--port 8000 \
--served-model-name llama31-local
--gpu-memory-utilization 不是显存上限百分比,而是预留给 KV cache 和模型权重的显存比例,默认 0.9;如果同一 GPU 还要跑 Embedding 模型或向量库,建议降到 0.75–0.85。--max-model-len 必须小于或等于模型 config 里的 max_position_embeddings,否则启动直接报错;对于受支持的长上下文模型,想真正用到 128K,还需要同步提高 --max-num-batched-tokens。
并发与上下文:一个参数就能让你翻车
Ollama 和 vLLM 对“上下文长度”的处理方式完全不同,很多人把两边参数混用导致OOM或性能暴跌。Ollama 通过 num_ctx 动态申请 KV cache,它不会一次占满显存,但如果你把 num_ctx 调到 32K 而模型只有 8B Q4,单条长对话就可能触发 CPU offload,TTFT(首 token 时间)从几百毫秒变成十几秒。vLLM 的 --max-model-len 则是在启动时按最大长度预分配 PagedAttention block,调得越大,能同时服务的并发数越少。
测量方法比背诵 benchmark 更重要。vLLM 自带 benchmarks/benchmark_serving.py,建议用它做基线:
python benchmarks/benchmark_serving.py \
--backend vllm \
--model llama31-local \
--dataset-name random \
--num-prompts 200 \
--max-concurrency 16 \
--random-input-len 1024 \
--random-output-len 256
Ollama 没有官方 benchmark 工具,可以用 Python 脚本并行请求 /api/chat,同时另开一个终端跑 nvidia-smi dmon,观察 GPU 利用率是否掉到 0、是否有大量 sysmem 占用。关键结论:上下文不是越长越好,而是要在 TTFT、TPOT 和并发数之间做三角取舍。
部署命令对照与最小可复现配置
下面给出两边从拉模型到可调参的完整命令,代码均可在当前主流版本直接运行。
Ollama 侧:
# 1. 拉取量化模型
ollama pull llama3.1:8b-instruct-q8_0
# 2. 创建带固定参数的自定义模型
cat > Modelfile <<'EOF'
FROM llama3.1:8b-instruct-q8_0
SYSTEM """You are a helpful coding assistant."""
PARAMETER temperature 0.6
PARAMETER num_ctx 8192
EOF
ollama create my-coder -f ./Modelfile
# 3. 服务端启动,允许 4 路并行
OLLAMA_HOST=0.0.0.0:11434 \
OLLAMA_NUM_PARALLEL=4 \
OLLAMA_MAX_LOADED_MODELS=1 \
ollama serve
vLLM 侧:
vllm serve "unsloth/Llama-3.1-8B-Instruct" \
--dtype bfloat16 \
--max-model-len 8192 \
--gpu-memory-utilization 0.85 \
--tensor-parallel-size 1 \
--enable-prefix-caching \
--enable-chunked-prefill \
--max-num-seqs 256 \
--port 8000 \
--served-model-name llama31-local
验证接口:
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "llama31-local",
"messages": [{"role": "user", "content": "hello"}],
"temperature": 0.6
}'
| 维度 | Ollama | vLLM |
|---|---|---|
| 核心定位 | 本地模型容器/桌面级推理 | 生产级推理服务引擎 |
| 启动入口 | ollama run / ollama serve |
vllm serve |
| 多卡扩展 | 自动按 VRAM 分层加载,无显式 TP/PP | tensor-parallel-size / pipeline-parallel-size |
| 并发调度 | 简单并行,受 OLLAMA_NUM_PARALLEL 限制 |
Continuous Batching + PagedAttention |
| 上下文控制 | Modelfile num_ctx / 请求 options |
--max-model-len / --max-num-batched-tokens |
| 量化生态 | 以 GGUF(Q4_K_M / Q8_0)为主 | AWQ / GPTQ / FP8 / BF16,GGUF 支持实验性 |
| API 形态 | Ollama REST + OpenAI 兼容层 | OpenAI 兼容 + vLLM 原生 API |
| 典型适用 | 个人、小团队、原型 | 内部 API、Agent、高并发、长上下文 |
避坑一:Ollama 的 KV cache 量化与动态上下文
Ollama 从近几个主线版本开始支持 OLLAMA_KV_CACHE_TYPE 环境变量,可以把 KV cache 从默认的 f16 降到 q8_0 甚至 q4_0,目的是在长上下文场景下省显存。但这里有一个隐蔽的坑:KV cache 量化只有在 Flash Attention 路径下才能获得预期的吞吐收益,如果因为驱动、CUDA 版本或模型不支持导致回退到普通 attention,CPU 反量化开销会把延迟拉得比 f16 还高。
更隐蔽的是它和 num_ctx 的交互。Ollama 的 KV cache 是按需增长的,如果你在 Modelfile 里把 num_ctx 设得很大,服务端会先预留较大的 cache 空间,结合 q8_0 后虽然显存勉强够用,但一旦单条请求接近上限,后续新请求的冷启动时间会出现非线性跳变。建议的排查步骤是:
- 先用默认 f16 测一条目标长度的对话,记录 TTFT;
- 打开
OLLAMA_FLASH_ATTENTION=1与OLLAMA_KV_CACHE_TYPE=q8_0后再测; - 如果 TTFT 变差或 GPU 利用率下降,说明当前路径不适合 KV cache 量化,回退即可。
不要只看显存占用数字,量化的收益应该用端到端延迟验证。
避坑二:vLLM 多卡张量并行的 NUMA/拓扑陷阱
vLLM 的 --tensor-parallel-size 依赖 PyTorch DDP/NCCL,而 NCCL 对拓扑非常敏感。双路服务器上常见的一幕是:两张 A6000 分别挂在两个 CPU socket 上,nvidia-smi topo -m 显示它们之间是 NODE 或 SYS 互联,而不是 PIX、PXB 或 NV#。此时如果直接 --tensor-parallel-size 2,NCCL 会尝试走 P2P,失败后再 fallback 到共享内存,轻则 latency 翻倍,重则直接 NCCL_P2P_LEVEL 相关报错。
解决思路不是换框架,而是把 TP 限制在同 NUMA 内。例如你有四张卡,socket 0 上是 GPU 0、1,socket 1 上是 GPU 2、3:
# 只使用同一 NUMA 下的两张卡做 TP
CUDA_VISIBLE_DEVICES=0,1 \
vllm serve "meta-llama/Meta-Llama-3.1-70B-Instruct" \
--tensor-parallel-size 2 \
--dtype bfloat16 \
--max-model-len 8192
如果必须跨 NUMA,考虑 --pipeline-parallel-size 2 配合 --tensor-parallel-size 2,或者在入口做请求路由,拆成两个独立 vLLM 实例。另一个容易忽略的参数是 NCCL_IB_DISABLE:本地没有 InfiniBand 时,显式禁用它可以避免 NCCL 花时间去探测不存在的网络设备,减少启动时间:
NCCL_IB_DISABLE=1 vllm serve ...
一份可直接对照的反模式清单
- [ ] 用 Ollama 做高并发 API 服务,却期望它媲美 vLLM 的吞吐。
- [ ] 在 vLLM 里把
--max-model-len无脑拉到模型理论最大值,导致并发数被 KV cache 吃掉。 - [ ] 多卡部署前没有执行
nvidia-smi topo -m,直接上 TP。 - [ ] 开启 Ollama KV cache 量化后,没有验证 Flash Attention 是否真正生效。
- [ ] 把
--gpu-memory-utilization当成“显存使用上限”,在同一 GPU 上叠加其他服务时引发 OOM。 - [ ] 本地 Ollama 只监听 127.0.0.1,却在局域网其他机器上调试了半天连接问题。
- [ ] 用 vLLM 跑小模型、低并发,却承受了 NCCL、依赖和部署复杂度,形成“大马拉小车”。
核心总结:Ollama 是“本地模型的容器运行时”,vLLM 是“GPU 推理的服务引擎”;选错框架不是性能损失,而是把运维复杂度前置到了生产环境。

