选开源推理引擎这件事,我最近被问得耳朵起茧。vLLM、SGLang、Ollama、llama.cpp 这四个名字排在一起,看着都是“开源推理引擎”,实际用起来完全是四个物种。有人用 vLLM 部署 Qwen 当线上 API,一天几十万请求稳如老狗;有人用 Ollama 想在 Windows 笔记本上跑个 7B 模型做实验,结果卡在下载和 500 报错上;还有人装着 llama.cpp 在 Android 手机上断断续续生成文本,觉得“这也能行”不可思议。这篇文章就围绕这四款引擎,从核心机制差异、选型逻辑、实际部署过程到踩坑排查,一次性聊透,给你一套“看见项目需求就知道该选谁”的判断方法。我尽量按我平时干活的口吻写,不整虚的,每一步都是可以照着操作的。
1. 先搞清楚你手里的牌:四个引擎的定位与机制差异
1.1 vLLM:PagedAttention 与 engine core 的高并发工厂
vLLM 在我看来本质是一个“批量请求调度工厂”。它最核心的贡献是 PagedAttention,也就是把 KV Cache 切成固定大小的块,像操作系统的虚拟内存页一样管理。这样显存里的小碎片能利用起来,同样一批请求可以塞进更大的 batch,吞吐自然就上去了。这解决的是在线服务场景最痛的问题:大量用户同时发请求,如何让 GPU 一直在干活而不是空转。
如果你去看 vLLM 的源码,会看到内部有三个重要角色:engine core、scheduler、executor。engine core 负责启动时初始化模型和配置,并持有整个推理循环的状态;scheduler 在每一轮迭代中检查队列里的请求,决定哪些请求能被 prefill、哪些能继续 decode、哪些因为显存不够或 token 数超长要排队;executor 则负责把调度器安排好的任务真正丢到 GPU 上执行。三者关系可以理解为:scheduler 是排班经理,executor 是干活工人,engine core 是整个公司的老板。vLLM 1.x 之后把 engine core 抽象出来,让这种交互流程更清晰,也方便做多模态、结构化输出等扩展。这也是为什么很多团队把它和对话平台、API 网关绑在一起用。
vLLM 适合的场景非常明确:OpenAI 兼容的 API 服务、高并发场景、需要连续 batching 在线推理。你用它部署一个大模型,然后在 8000 端口起一个服务,聊天机器人前端来调,它能把并发请求压缩成一个一个小 batch,吞吐比朴素的 transformers 实现高出数倍。代价是引入的模块多、显存和 CUDA 驱动要求高,个人电脑要跑起来并不轻松。
1.2 SGLang:把前缀缓存做进骨子里
SGLang 是 vLLM 的强有力对手,最近热度一路走高。它给我的印象是:更“聪明”地安排同样输入的复用。SGLang 的招牌是 RadixAttention,它在每次请求时把 prompt 拆成前缀树节点缓存下来。多轮对话的 system prompt 完全相同、检索增强生成里一堆文档都带同一个固定模板前缀……这些场景中重复的 KV Cache 不需要重新计算,直接复用已有缓存,prefill 开销大幅降低。
当然,SGLang 并不只有前缀缓存。它也实现了自己的 scheduler、executor、continuous batching,还引入了“统一内存池”和自动编译前端,能把多个请求的执行计划融合起来。简单说,vLLM 在“怎么让 GPU 多塞请求”下功夫,SGLang 在“怎么让相同内容少算第二遍”下功夫。所以很多长上下文、多轮对话、共享 prefix 的业务会明显感觉到 SGLang 更快。我在对比测试里,用同样的 Qwen2.5 7B,跑那种带 2000 token 固定 system prompt 的请求,SGLang 首个 token 延迟肉眼可见地比 vLLM 低。这件事在 vLLM 开启 prefix caching 后差距缩小,但 SGLang 的 RadixAttention 粒度更细,细节上更有优势。
SGLang 适合的场景是:对首 token 延迟敏感、大量重复前缀、多轮会话、长上下文。如果你的业务开发者每天都在调一个知识库 bot,强烈建议试试 SGLang。不过它比 vLLM 社区更年轻,部分模型、量化格式的支持要留意版本适配。
1.3 Ollama:个人电脑上的“模型管家”
Ollama 跟前面两个完全不是一个路线。它不是为了最大化 GPU 利用率,而是为了“让普通人把模型跑起来”。Ollama 相当于一个模型管理工具:安装之后,ollama pull qwen2.5:7b拉模型,ollama run qwen2.5:7b进对话,一个命令搞定。它内部把模型包成一层一层,真正做推理的底层默认是 llama.cpp 的构建版本。所以 Ollama 和 llama.cpp 有血脉关系。
Ollama 的定位是本地开发、个人笔记、桌面端 demo、小团队内部体验。它提供 OpenAI 兼容接口(默认 11434 端口),所以 AnythingLLM、Dify、LangChain、Goose 这类工具也可以直接接。它吸引人的地方是:模型包自带 Modelfile,可以配置温度、上下文长度、system prompt 等;服务可以单机多模型挂载;有 web 或桌面客户端生态。但它不适合极端高并发,因为底层 llama.cpp 的连续 batching 和 nvGPU 优化不如 vLLM 激进。你在本地拿 4090 跑 Ollama 做个人助手问题不大,要扛十几位并发用户就要小心了。
Ollama 最让人头疼的是下载模型太慢,官方仓库在海外,国内网络经常龟速。解决办法基本都是配置国内镜像源、通过代理下载(我这里不提代理工具,只说镜像站方式)、或者把别人下好的 GGUF 文件手动导入。热词里的“ollama国内镜像源”“ollama 离线安装包”“gguf模型下载后如何导入ollama”都是这个痛点引出来的,后面我要讲具体做法。
1.4 llama.cpp:CPU 也能跑的轻量引擎
llama.cpp 是 GGUF 格式的娘家。它用 C/C++ 实现,没有厚重的 Python 依赖和 CUDA 生态绑定。它的设计目标很朴素:只要有一台电脑,CPU 也能推理大模型。通过量化 GGUF 文件(比如 Q4_K_M 每参数只占约 4.5 bit),7B 模型只要 4~5 GB 内存就能跑。它也对 GPU offload 做了支持,你可以指定-ngl 99把全部层扔给显卡,也可只用 CPU 跑。
llama.cpp 的“轻”体现在很多地方:有llama-cli、llama-server、llama-bench等命令行工具,能跨平台编译 Windows、Linux、macOS、Android。热词里“llama.cpp android 版”不是新鲜事,市面上很多手机端本地模型应用的内核就是 llama.cpp。你想在自己安卓机上跑一个离线小模型,把 termux 装上,编译个 llama.cpp 或者下载预编译包,然后运行 GGUF 文件即可。虽然生成速度只有每秒几个 token,但在移动端场景这种灵活性无可替代。
llama.cpp 不适合线上高并发服务。它虽然提供llama-server并带 OpenAI 兼容 API,但单请求吞吐、调度能力跟 vLLM 不在一个量级。它适合的场景:离线推理、边缘设备、CPU 机器、模型实现调优、自定义采样器研究,以及那些想要“干净、没依赖、可控”的实现。Ollama 用了它的内核,这并不代表 Ollama 的所有能力就是 llama.cpp 的上限,真正面向大流量的项目还是要回到 vLLM 或 SGLang。
2. 选型逻辑与硬件依赖:别只看跑分
2.1 场景比拼:在线服务、离线批处理、个人尝鲜
很多朋友选引擎时,习惯去论坛看 “vLLM 和 SGLang 哪个快”,然后跟风。我建议先按场景画一个坐标:左边是“要不要高并发在线 API”,右边是“就一台个人电脑跑跑”。如果是左边,直接排除 Ollama 和 llama.cpp 作为主服务端;如果是右边,vLLM 和 SGLang 可能成了负担。
我列一张对比表,把几个维度说清楚:
| 对比项 | vLLM | SGLang | Ollama | llama.cpp |
|---|---|---|---|---|
| 核心优化点 | PagedAttention、continuous batching | RadixAttention 前缀缓存 | 模型管理与一键部署 | CPU/GPU 混合轻量推理 |
| 主要格式 | FP16/BF16、AWQ、GPTQ、FP8 | FP16/BF16、量化兼容 | GGUF | GGUF |
| 并发能力 | 强 | 强 | 中低 | 低 |
| 部署复杂度 | 高,建议 Docker | 高,建议 Docker | 低 | 低 |
| OpenAI 兼容 API | 原生 | 原生 | 原生兼容 | llama-server 提供 |
| 典型场景 | 线上 API、高并发 | 多轮对话、长上下文、知识库 | 个人本地、小团队 demo | 离线、移动端、CPU 机器 |
所以如果你做的是“给公司业务提供大模型接口”,不用纠结,默认 vLLM,然后对比 SGLang 是否更快再切换;如果你自己是开发者,想在笔记本上快速跑个 7B 模型做原型,Ollama 最省事;如果你在树莓派或手机上跑,或者只想在纯 CPU 机器上跑,llama.cpp 是唯一正解。
2.2 显存、内存的粗算方法(附实例)
推理引擎跑之前最怕的是“模型装不上”。其实显存占用可以提前粗算。以 7B 模型为例,FP16 权重约 14GB(7B × 2 字节)。BF16 一样。如果做 Q4_K_M 量化,GGUF 文件通常只有 4.3~4.5GB,内存占用接近这个值加一点上下文。而 vLLM 部署时除了权重还要给 KV Cache 预留显存,在长上下文场景下这是大头。
具体计算:假设你用 vLLM 跑 Qwen2.5-7B-Instruct,FP16 权重 14GB,设置--max-model-len 32768,KV cache 在 batch 为 1、无 GQA 加持时非常大,但因为有 GQA 和跳动 KV cache,实际预留可能也要 5~8GB。所以一张 24GB 的 4090 是可以舒服跑 7B 长上下文的;想跑 70B 至少要 2~3 张 48GB 或配合量化。用 llama.cpp 的 Q4_K_M 跑 7B 则只需约 5GB 内存,CPU 也能跑,只是速度感人。
量化格式也要注意:vLLM 1.x 支持 GPTQ、AWQ、FP8 等,但它对 GGUF 支持的体验不如 llama.cpp 好;你要是已经有一堆 GGUF 模型,用 Ollama 和 llama.cpp 更顺。反过来,你从 HuggingFace 拉了原版 weights,想快速起个服务,vLLM 直接--model <目录>就行,不需要提前转格式。
2.3 CUDA 与 Docker:90% 坑从环境来
部署 vLLM 或 SGLang 最忌讳的事是裸机安装时版本不搭。vLLM 对 PyTorch、CUDA、GCC、甚至 NVIDIA 驱动都很敏感。一个常见错误是驱动太老,报CUDA error: no kernel image is available;另一个常见问题是 pip 安装的 PyTorch 是 CPU 版或 CUDA 版本不一致。所以官方推荐 Docker 镜像不是没有道理——镜像里已经把环境隔离好了,宿主机只需要有 NVIDIA 驱动和支持 nvidia-container-toolkit 的容器运行时。
Docker 拉起 vLLM 的标准套路是:先装驱动,再装 nvidia-container-toolkit,然后docker run --gpus all。镜像地址一般用vllm/vllm-openai,标签对应版本。热词里有“vllm/vllm-openai:v0.27.1 加载 qwen3-embedding-0.6b”,这个场景就是docker run时传入--model和--task embedding之类的参数,vLLM 1.x 对 embedding 模型支持也变好了。此外“glm5.3 使用 vllm 哪个版本的镜像”这类问题说明版本匹配确实困扰人,我的建议是看模型官方文档给出的 vLLM 最低版本,不要闭眼用最新镜像,很多新版本性能反而出现回退,社区里有不少反馈。
3. 四款引擎的实操部署详解
3.1 vLLM 部署 DeepSeek/Qwen 系列服务
先说我在 Linux 服务器上部署 Qwen/DeepSeek 系列的标准操作。假设模型已经下载到宿主机/data/models下,目录里有config.json和权重文件。我用 Docker,因为升级和排障都方便:
docker run --runtime nvidia --gpus all \ -p 8000:8000 \ -v /data/models:/models \ vllm/vllm-openai:v0.27.1 \ --model /models/qwen2.5-7b-instruct \ --max-model-len 32768 \ --gpu-memory-utilization 0.9 \ --served-model-name qwen2.5-7b启动后,本地就能请求了:
curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"qwen2.5-7b","messages":[{"role":"user","content":"你好"}],"max_tokens":256}'热词里的“vllm部署deepseek”“docker部署vllm模型教程”都是这条路。有几个参数要解释:--gpu-memory-utilization 0.9表示预留 90% 显存给 vLLM,不能设太大,否则显存溢出就起不来;--max-model-len是模型最大上下文长度,设得太大,KV Cache 预留就多,并发时容易 OOM,设太小,超长 prompt 会被截断。对于 7B 模型在 24GB 卡上,32768 是常见安全值。
vLLM 新版本 v0.6.x 到 0.8.x 之间变化挺大,热词里“vllm新版本性能下降”不是空穴来风。有的版本 scheduler 改动后,某些模型的 throughput 和 latency 都变差。我的实践原则是:如果模型官方指定了镜像版本,就用那个;如果没有,稳定优先,用 vLLM 0.6.x 或 0.7.x 的成熟版本,而不是追上最新的 tag。生产环境锁版本是一个好习惯。
如果要用 embedding 模型,比如 qwen3-embedding-0.6b,命令类似,但要加参数指定任务类型。vLLM 1.x 支持--task embedding,然后请求/v1/embeddings。这个能力对于搭建 RAG 链路很有用,不过要注意 vLLM 对 embedding 模型的支持并不是所有版本都完善,部署前先去看 release notes。
3.2 SGLang 部署与一致性加速
SGLang 的部署也很像 vLLM,但有一个明显的记忆点是“前缀缓存”。如果你搭一个知识库问答,所有用户请求前都附带着同一个固定 system prompt 加一堆候选 chunks,vLLM 每次都要重新 prefill 这些公共内容,而 SGLang 的 RadixAttention 能直接命中缓存。这是它最大的卖点。
在服务器上,SGLang 可以用 Docker 也可以 pip 安装。我常用的方式是在 Python 虚拟环境里装:
pip install --upgrade sglang python -m sglang.launch_server \ --model-path /data/models/qwen2.5-7b-instruct \ --host 0.0.0.0 \ --port 30000 \ --mem-fraction 0.8SGLang 启动后会暴露一个 OpenAI 兼容接口,默认端口是 30000。--mem-fraction是显存占用比例,可参考 vLLM 的--gpu-memory-utilization。我做压测对比时,同样的 7B 模型,SGLang 在多轮对话且 system prompt 很长的情况下,首 token 延迟比 vLLM 低 20%~40%,吞吐在并发中等时也更好。如果你的业务场景没那么“重复前缀”,两者相差不算太大,更看模型适配度。也有不少模型在发布时官方直接给出 SGLang 参考部署,比如长上下文 MoE 模型,SGLang 的内存调度策略往往更细腻。
SGLang 的坑主要在版本和依赖上:它自己会带一套sgl-kernel、flashinfer等加速底层,需要和 CUDA 版本匹配,如果编译失败,建议直接换官方 Docker 镜像,或者在干净环境里用pip install sglang[all]而不是手拼依赖。
3.3 Ollama 本地部署:下载、镜像、导入 GGUF
Ollama 是我给刚入门的人推得最多的。第一步是安装。Windows 用户官网下载OllamaSetup.exe,国内直接下载慢的话,可以用一些开源镜像站下载离线安装包。安装包本身不大,问题主要在模型下载。设置国内镜像源是最实用的手段。Ollama 支持配置OLLAMA_HOST、OLLAMA_MODELS环境变量,而镜像地址通常通过设置OLLAMA_REGISTRY_MIRROR之类的环境变量来指定,我把这个写清楚:
- 在 Windows 上:右键“此电脑” -> 属性 -> 高级系统设置 -> 环境变量,新增
OLLAMA_MODELS指定模型存放目录,比如D:\ollama_models。这样能解决“ollama怎么安装在d盘”的问题,因为模型默认集中在C:\Users\me\.ollama\models,不改的话 C 盘很容易爆。 - 设置
OLLAMA_REGISTRY_MIRROR=<你的镜像地址>,拉取模型就会走镜像。不少国内镜像加速服务提供 Ollama 仓库转存,填上后ollama pull qwen2.5:7b速度就有明显变化。 - 如果公司内网或离线环境,就用离线安装包 + 手动放入 GGUF 模型文件。
手动导入 GGUF 的操作方法:ollama create需要一个 Modelfile。比如你下载了一个qwen2.5-7b-instruct-q4_k_m.gguf文件,先写一个Modelfile:
FROM /data/gguf/qwen2.5-7b-instruct-q4_k_m.gguf TEMPLATE """{{ if .System }}<|im_start|>system {{ .System }}<|im_end|> {{ end }}<|im_start|>user {{ .Prompt }}<|im_end|> <|im_start|>assistant """ PARAMETER stop "<|im_end|>" PARAMETER temperature 0.7然后执行:
ollama create qwen2.5-7b -f Modelfile ollama run qwen2.5-7b这样本地 GGUF 文件就能变成 Ollama 可管模型。Modelfile 里的模板要跟着模型走,Qwen 系列、LLaMA 系列、ChatML 格式各不相同,模板写错会导致对话乱套或“不思考”。
Ollama 的 500 Internal Server Error 是高频问题,热词里“ollama run qwen2.5:7b error: 500 internal server error”就是一个典型抱怨。后面我会专门讲。
3.4 llama.cpp:服务器与 Android 端的另类玩法
先看服务器上的基本用法。编译 llama.cpp 常见两种:纯 CPU 版和带 CUDA 版。在 Linux 下:
git clone https://github.com/ggml-org/llama.cpp cd llama.cpp cmake -B build -DGGML_CUDA=ON cmake --build build --config Release带 CUDA 后,运行 GGUF 模型并尽量让 GPU 参与:
./build/bin/llama-cli -m /models/qwen2.5-7b-q4_k_m.gguf -p "介绍一下开源推理引擎" -n 128 -ngl 99-ngl 99代表把模型层尽量全部加载到 GPU。CPU 跑大型模型时,这个参数可为 0。你也可以启动交互式服务:
./build/bin/llama-server -m /models/qwen2.5-7b-q4_k_m.gguf --host 127.0.0.1 --port 8080llama-server 会提供/v1/chat/completions接口,能让 LangChain、Open WebUI 等工具直接连接。
Android 端玩法更“折腾”。你可以用 Termux 编译一个 android 版,或者在 GitHub 下载别人构建好的二进制。装好后把 GGUF 文件放进手机存储,命令行里执行:
./llama-cli -m /sdcard/Download/qwen2.5-3b-q4_k_m.gguf -p "你好" -n 64手机会很热,速度取决于 CPU 和内存带宽。但这个东西的意义不是说一定要体验多流畅,而是证明大模型推理不再是只能躲在机房里。你在讨论班、户外、没有网络的场景里,也可以用本地模型做演示和简单问答。llama.cpp 的模型文件与 Ollama 可互通,这就是为什么“gguf模型下载后如何导入ollama”成为热搜词。
4. 踩坑实录与排查速查
4.1 为什么 vLLM 最新版不总是最优选
很多朋友喜欢追新,只要看到 vLLM 出了新版本就立刻升级。但我自己踩过不止一次:某个小版本对特定模型支持不好,或者新调度逻辑在并发场景下 latency 抖动明显。社区里“vllm新版本性能下降”的讨论就是一个信号。生产环境升级 vLLM 的正确姿势是:先在测试环境用量化跑 benchmark,对比旧版本,再决定是否升级。尤其当你的模型是特殊结构(MoE、多模态、embedding)时,更不能拿“通用指标”代替你的真实流量。
我建议锁定一个可复现的 Docker tag,记录下来。比如vllm/vllm-openai:v0.27.1对某些 embedding 模型可用,你就把它写进 CI 或部署脚本。后续再统一评估升级。同理,SGLang 版本更新也很快,有时候为了一个 bug fix 就需要换版本,所以组件版本驱动要单独管理,最好用环境锁文件。
4.2 Ollama 下载与 500 报错的真实原因
Ollama 下载慢的问题前面已经说了:国内直连困难。除了配置镜像源,还可以手动下载模型包然后放到models/blobs目录。但更傻瓜的方式是:在能正常访问的机器上ollama pull后把.ollama/models整个文件夹拷到目标机器,注意目标机器的OLLAMA_MODELS环境变量要指向这个目录。
ollama run报 500 Internal Server Error 的原因多样,常见的几个:
- GPU 显存不足,模型一加载就 OOM,Ollama 进程返回 500。可以尝试
ollama run时限制并发或者换更小量化模型。 - 模型文件损坏,拉取中断导致 blob 不完整,删掉模型后重新拉取。
- 端口或模式冲突,比如同时运行多个模型,显存分配冲突。
- 底层 llama-server 进程崩溃,查看日志:Windows 下在系统托盘 Ollama 图标日志,Linux 下
journalctl -u ollama或直接前台运行ollama serve看 stdout。
报错信息里只要有llama-server process字样,基本就是底层推理进程崩了,先把模型换成 Q4_K_M 小模型试试,如果好了,说明是资源或兼容性问题。
4.3 CUDA 加速与显存不足怎么破
Ollama 在 Windows 上的 CUDA 加速默认是自动的,只要 NVIDIA 驱动装好。但很多人装完驱动发现能跑 CPU,就是没走 GPU,原因可能是模型版本或 ollama 版本不支持当前显卡架构。最简单的验证方法:ollama run时看日志里有没有offloaded 20/20 layers to GPU这种输出,或者用nvidia-smi看显存占用。
vLLM 显存不足时,除了调--gpu-memory-utilization,还有一个思路是降低--max-model-len,因为预留的 KV cache 会随最大 token 数线性增长。如果你跑长文档但实际很少超过 8192,就别设置 128K,否则 4090 根本扛不住。llama.cpp 显存不足则调低-ngl,甚至设 0 全 CPU。
4.4 模型文件管理的五个细节
模型文件动辄几个 GB,管理不好会浪费大量时间。我的习惯是:
- 统一目录:在服务器上建
/data/models,按模型名/版本分子目录,镜像挂载时不要全盘挂载,而是挂这个目录。 - 校验文件:下载 GGUF 或 weights 后,用
cksum、sha256sum和源站比对,少一个 shard 文件都可能导致加载异常。 - 区分权重格式:
config.json里的quantization_config会标明模型是 Gaussian 还是量化,部署参数要匹配。 - 定期清理:Ollama 的
ollama list能看到模型占用,删掉不常用大模型能腾出磁盘。 - 备份
Modelfile:手动导入的模型重新部署时,没有 Modelfile 就得从头写模板,最好把 Modelfile 放到和 GGUF 同目录,提交到 git。
5. 决策建议:这把刀适合谁
5.1 从团队规模与部署形态倒推
选型不是选最火的那个,而是选“你最可能把它用起来”的那个。如果你所在团队做产品闭环:前端聊天、后端 API、多用户访问,那主引擎就是 vLLM 或 SGLang。判断依据很简单:你的请求是不是有大量重复前缀?有,优先 SGLang;没有,用 vLLM 省心安逸。SGLang 目前对较新模型和功能支持速度很快,但如果你不想跟随一个年轻项目的节奏,vLLM 的文档和案例更多,招聘时也好找人。
如果你只是一个人在本地做实验、跑知识库、或者给公司内部做 demo,Ollama 是最低成本的起点。它的生态工具(AnythingLLM、Dify、Goose)已经很成熟,不用自己写推理层。等并发上来了再平滑迁到 vLLM 也不迟——API 兼容可以减少改动量。
如果你要在无 GPU 的服务器、嵌入式设备、手机上跑,llama.cpp 是唯一可靠的方案。GGUF 格式的便携性加上llama-server的 API 能力,让它成为边缘推理的事实标准。Ollama 本身就是建立在其之上。
5.2 我个人的项目经验参考
我自己的项目一般是这样组合:快速原型用 Ollama,因为拉模型、改参数、试 prompt 太方便了;正式上线用 vLLM 或 SGLang 其中之一,看客户请求特征。在部署时,我习惯用 Docker 先把环境钉死,再用模型层的版本控制管理模型升级。vLLM 我一般选择稳定版镜像,SGLang 在小流量 A/B 验证后再切。遇到 “某个模型用哪个镜像”的问题,我第一反应是去看对方模型卡上的示例代码,那上面写的就是经过验证的版本组合,比自己瞎猜可靠得多。
踩过几次坑之后,我最大的体会是:这些引擎没有绝对的优劣,只有适不适合你的负载。vLLM 的高并发调度、SGLang 的前缀复用、Ollama 的管理便捷、llama.cpp 的轻量可嵌入,分别压中了不同场景。把机制搞明白,选型就不会被跑分和热度带着走。