大模型推理引擎实战选型:vLLM、SGLang、TensorRT-LLM与llama.cpp深度对比
1. 从“能用”到“好用”:推理引擎选型的现实困境
最近在折腾大模型本地部署的朋友,估计都绕不开一个灵魂拷问:我到底该用哪个推理引擎?是社区里风头正劲的vLLM,是学术圈新秀SGLang,是NVIDIA亲儿子TensorRT-LLM,还是那个“老而弥坚”的llama.cpp?这感觉就像去4S店选车,销售跟你讲了一堆参数,什么零百加速、扭矩、热效率,但真开起来堵在北京三环上,你才知道哪个最适合自己。
我手头有几台不同配置的机器:一台双路RTX 3090的工作站,一台海光DCU的国产化服务器,还有一台只有CPU的旧笔记本。目标也很明确:把Qwen3、Llama3这些主流模型跑起来,不仅要能跑通,还要跑得稳、跑得快、资源吃得少。在这个过程中,我把这四个引擎都深度折腾了一遍,从安装部署、模型加载、推理测试到生产环境适配,踩的坑比写的代码都多。今天这篇,我就从一个一线部署者的角度,掰开揉碎了聊聊这“四强”到底该怎么选。这不是一份冷冰冰的Benchmark跑分报告,而是一份带着温度、沾着泥土的实战心得。你会发现,没有“最好”的引擎,只有“最适合”你当下场景的那个。
2. 核心特性与设计哲学:它们到底想解决什么问题?
在深入细节之前,我们必须先理解这四个引擎各自的“出身”和“抱负”。它们的底层设计哲学,直接决定了其擅长和不擅长的场景。
2.1 vLLM:吞吐量之王与持续批处理的革命者
vLLM的核心贡献,是一个叫做PagedAttention的算法。你可以把它想象成计算机操作系统里的虚拟内存分页管理。传统的大模型推理,就像你请了一个记忆力超强但有点“轴”的专家(GPU),每次对话(推理请求)都必须把整本百科全书(模型的KV Cache)完整地、连续地放在他面前。如果同时和多个专家对话(多请求并行),他们就会为了抢“桌面空间”(GPU显存)打起来,导致很多专家闲着,效率极低。
PagedAttention 把这个过程“操作系统化”了。它把KV Cache切分成固定大小的“块”(Block),就像内存页。不同的对话请求可以共享这些块,并且可以非连续地存放。这样一来,GPU显存的利用率从“大通铺”变成了“高效公寓”,碎片大大减少。这使得vLLM在处理高并发、流式输出、请求长度变化大的场景时,吞吐量(Tokens per Second)能有数倍甚至数十倍的提升。它的设计目标非常明确:最大化服务端的整体吞吐,服务于云原生的大模型API服务。所以你会看到,vLLM最早、最成熟的接口就是OpenAI兼容的API Server(vllm.serve)。
注意:vLLM对“投机采样”等高级解码特性的原生支持相对较晚,它的强项在于利用PagedAttention把并行和调度做到极致。
2.2 SGLang:为复杂提示工程而生的“编程语言”
如果说vLLM优化的是服务端资源,那么SGLang优化的就是程序员的生产力。它的全称是Stochastic Graph Language,核心思想是把大模型的推理过程,特别是那些包含多轮对话、工具调用、分支判断的复杂提示(Prompt),抽象成一个有向无环图。
举个例子,一个复杂的Agent工作流可能包含:“根据用户问题生成搜索关键词 -> 调用搜索API -> 根据搜索结果生成分析 -> 如果分析不充分则进行第二轮搜索”。用传统的Python脚本写,你需要手动管理对话历史、拼接Prompt、处理中间结果,代码会变得冗长且易错。
SGLang允许你用更声明式、更结构化的方式来描述这个工作流。它提供了像parallel、select、fork这样的原语,让你能直观地表达并行、分支和循环。运行时,SGLang的调度器会智能地分析这个计算图,将可以并行的部分(比如多个独立的工具调用)批量发送给后端引擎(它本身不负责具体计算,后端可以是vLLM、Llama.cpp等),从而提升整体执行效率。SGLang的终极目标,是让复杂提示程序的编写和运行像写配置一样简单高效。它特别适合开发RAG系统、多模态Agent、自动化评测框架。
2.3 TensorRT-LLM:在NVIDIA硬件上榨干最后一滴性能
这是NVIDIA的“亲儿子”,是TensorRT生态针对大模型推理的垂直深度优化方案。它的工作流程非常“工程师化”:编译 -> 优化 -> 部署。
- 模型编译:你需要将Hugging Face格式的模型(如Qwen2-7B),通过TensorRT-LLM提供的工具链,编译成一个高度优化的TensorRT引擎文件(
.engine)。这个过程会进行算子融合、内核自动调优、精度校准(支持FP8, INT8量化)等大量底层优化。 - 运行时部署:部署时,你加载的是这个编译好的
.engine文件,而不是原始的PyTorch模型。运行时组件(Triton Inference Server插件或独立的Python运行时)负责执行这个高度优化的引擎。
TensorRT-LLM的优势在于极致的单卡性能和延迟。由于是针对特定GPU架构(如Ampere, Hopper)和特定模型进行了“贴身”优化,它的推理速度往往是所有方案中最快的。但它也有明显的代价:使用复杂度高,灵活性差。编译过程耗时(动辄数小时),且编译好的引擎与GPU型号、TensorRT版本甚至输入输出尺寸强绑定。模型有任何改动(哪怕只是改一下最大生成长度),都可能需要重新编译。它的定位很清晰:对延迟和成本极度敏感的线上生产环境,且硬件和模型相对固定。
2.4 llama.cpp:极简主义的跨平台捍卫者
llama.cpp的故事始于一个简单的需求:在MacBook上用CPU跑通LLaMA模型。它用纯C/C++实现,核心依赖极少(主要是ggml这个张量库),通过大量的手工汇编优化(AVX2, AVX512, NEON)来挖掘CPU、Apple Silicon甚至部分GPU(通过CUDA/OpenCL后端)的潜力。
它的设计哲学是“KISS”。模型格式统一为自有的.gguf(一种智能量化的二进制格式),推理通过一个简单的命令行接口或轻量级C API完成。没有复杂的服务框架,没有动态批处理,一切追求极致的轻量和可控。
llama.cpp的强项在于:
- 无与伦比的部署便利性:一个可执行文件+一个模型文件,就能在任何有现代CPU的设备上运行。
- 强大的量化支持:其
gguf格式集成了多种精妙的量化算法(如IQ4_XS, Q8_0),在精度损失极小的情况下,将模型压缩到难以置信的大小(如70B模型可压至4GB以下),使其能在消费级硬件上运行。 - 资源消耗极低:纯推理时内存占用稳定,没有Python进程的内存膨胀问题。
它的弱项也很明显:缺乏原生的高性能服务化能力(如动态批处理、多路并发),更适合单次推理、研究调试或资源极度受限的边缘场景。
3. 实战部署与性能调优:手把手带你避开深坑
理论说再多,不如动手跑一跑。下面我结合自己的踩坑经历,分别聊聊这四个引擎在实战中的关键步骤和那些文档里不会写的细节。
3.1 vLLM部署:从快速入门到生产级稳定
安装与环境准备官方推荐用pip安装,但这里有个大坑:vLLM对CUDA版本、PyTorch版本非常敏感。以最新的v0.26.1为例,如果你用pip install vllm,它可能会自动安装一个与你现有环境不兼容的PyTorch版本,导致后续运行失败。
推荐的做法是:
# 1. 首先确保有一个正确版本的PyTorch (例如 CUDA 11.8) pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 2. 然后安装vLLM,指定不安装其依赖的PyTorch pip install vllm --no-deps # 3. 再手动安装vLLM的其他核心依赖 pip install transformers>=4.36.0 accelerate>=0.25.0对于海光DCU或昇腾NPU等国产硬件,vLLM社区有非官方支持,但需要从源码编译,并打上针对特定计算库(如CANN)的补丁。这个过程非常繁琐,需要自行解决算子映射和内存地址映射问题(如昇腾模型的权重地址映射),除非有强烈需求,否则不建议新手尝试。
启动服务与基础使用最基本的启动命令很简单:
python -m vllm.entrypoints.openai.api_server \ --model Qwen/Qwen2.5-7B-Instruct \ --served-model-name qwen2.5-7b \ --port 8000但生产环境你需要关注更多参数:
--tensor-parallel-size: 张量并行度,多卡时必须设置。--gpu-memory-utilization: GPU显存利用率目标,默认0.9,在显存紧张时可调低至0.8以避免OOM。--max-model-len: 模型支持的最大上下文长度,需要根据模型能力和你的需求设置,设置过大会浪费显存。--disable-log-requests: 生产环境建议关闭请求日志,提升性能。
性能调优与“输出不一致”问题有用户反馈vllm serve输出不一致,这通常不是bug,而是解码策略的配置问题。vLLM默认使用采样(sampling)而非贪婪解码(greedy decoding)。如果你需要确定性输出,必须显式设置--temperature 0。
# 在启动服务器时指定 --temperature 0 # 或在请求API时指定 curl http://localhost:8000/v1/completions \ -H "Content-Type: application/json" \ -d '{ "model": "qwen2.5-7b", "prompt": "Hello, world", "temperature": 0, "max_tokens": 50 }'另外,使用vllm bench进行基准测试时,要区分“吞吐量”和“延迟”测试场景,通过--request-rate或--num-prompts参数来模拟不同负载。
3.2 TensorRT-LLM部署:一次编译,持续“飞翔”
编译流程详解以在RTX 3090(Ampere架构)上编译Qwen2.5-7B-Instruct的FP16版本为例:
# 1. 拉取TensorRT-LLM代码并安装依赖(这是一个漫长的过程) git clone https://github.com/NVIDIA/TensorRT-LLM.git cd TensorRT-LLM pip install -r requirements.txt # 2. 使用官方脚本编译模型 # 这里需要准备一个包含模型权重的目录 python scripts/build_wheel.py # 先构建TensorRT-LLM的wheel包并安装 cd examples/qwen # 修改配置脚本,指定模型路径、精度、GPU架构等 # 然后运行编译脚本,这可能会花费1-2小时 bash build.sh编译成功后,你会得到一个.engine文件。这个文件是硬件和模型参数的“结晶”,换一张不同架构的GPU(比如从3090换到4090),这个文件就不能用了。
部署与推理编译后,你可以使用TensorRT-LLM自带的Python运行时进行简单测试,但生产环境强烈推荐集成到NVIDIA Triton Inference Server中。Triton提供了动态批处理、模型队列、监控等企业级特性。你需要编写一个Triton的模型配置(config.pbtxt),将TensorRT-LLM的后端插件配置进去。这个过程有学习成本,但一旦跑通,其稳定性和性能是非常可靠的。
3.3 llama.cpp部署:极致简约,无处不在
模型量化与转换llama.cpp只认.gguf格式。你需要从Hugging Face下载原始模型,然后用convert.py脚本转换。
# 克隆llama.cpp仓库 git clone https://github.com/ggerganov/llama.cpp cd llama.cpp pip install -r requirements.txt # 下载原始Qwen2.5模型 (假设已通过git-lfs下载到./qwen2.5-7b-original) # 转换为F16格式的gguf python convert.py ./qwen2.5-7b-original --outtype f16 --outfile qwen2.5-7b-f16.gguf # 进一步量化成更小的IQ4_XS格式(推荐,精度损失小) ./quantize ./qwen2.5-7b-f16.gguf ./qwen2.5-7b-iq4_xs.gguf iq4_xsIQ4_XS是目前社区认为在精度和尺寸上平衡得非常好的量化格式,7B模型可以压缩到不到4GB,在RTX 3090上也能获得极快的推理速度。
运行与交互推理可以直接用命令行:
# 交互式对话 ./main -m ./qwen2.5-7b-iq4_xs.gguf -n 512 --interactive # 作为简单的API服务器(功能远不如vLLM强大) ./server -m ./qwen2.5-7b-iq4_xs.gguf -c 4096 --port 8080对于Qianfan-OCR这类多模态模型,llama.cpp社区也有扩展支持,但通常需要自己编译开启相关编译选项(如-DLLAMA_BUILD_EXAMPLES=ON)的版本,并找到对应的模型转换脚本。
3.4 SGLang部署:编织你的提示词工作流
SGLang的安装相对简单:pip install sglang。它的核心不是部署一个模型服务,而是编写和运行提示程序。
一个简单的并行调用示例
import sglang as sgl from sglang import function, system, user, assistant, gen, set_default_backend from vllm import AsyncEngineArgs, AsyncLLMEngine # 1. 设置后端(这里用vLLM) backend = AsyncLLMEngine.from_engine_args( AsyncEngineArgs(model="Qwen/Qwen2.5-7B-Instruct") ) set_default_backend(backend) @sgl.function def parallel_qa(questions): with sgl.parallel(): for q in questions: with sgl.user(): sgl.print("Question: " + q) with sgl.assistant(): sgl.print(gen("answer", max_tokens=100)) # 2. 运行 questions = ["什么是人工智能?", "如何学习编程?", "天气真好,对吗?"] parallel_qa.run(questions)在这个例子中,三个问题被并行地发送给vLLM后端处理,而不是传统的串行for循环,这在处理大量独立查询时能大幅缩短总耗时。
与vLLM/llama.cpp后端协同SGLang的强大在于其后端抽象。你可以轻松切换后端:
# 切换到llama.cpp后端 from sglang.backend.runtime_endpoint import RuntimeEndpoint backend = RuntimeEndpoint("http://localhost:8080") # 假设llama.cpp server在运行 set_default_backend(backend)这样,你就可以用SGLang的高级编程接口,去驱动一个由llama.cpp提供的基础推理能力的服务,结合了易用性和部署灵活性。
4. 横向对比与选型决策矩阵
看完各自的细节,我们来一场面对面的“PK”。下表从多个维度对比了这四个引擎:
| 特性维度 | vLLM | SGLang | TensorRT-LLM | llama.cpp |
|---|---|---|---|---|
| 核心目标 | 高吞吐推理服务 | 复杂提示编程框架 | 极致单卡性能 | 极简跨平台推理 |
| 性能强项 | 吞吐量(多请求并行) | 程序执行效率(工作流优化) | 延迟与单请求速度 | 低资源消耗,量化后性能 |
| 易用性 | 中等,API直观,但生产调优需经验 | 高(对开发者友好) | 低(编译部署复杂) | 极高(开箱即用) |
| 部署复杂度 | 中等,依赖Python生态 | 低 (作为库集成) | 高(需编译,绑定硬件) | 极低 (单文件) |
| 硬件支持 | NVIDIA GPU (主流) | 后端决定 (支持vLLM, llama.cpp等) | NVIDIA GPU(深度绑定) | 全平台(CPU/Apple/NVIDIA/AMD) |
| 模型支持 | 广泛 (Hugging Face格式) | 广泛 (依赖后端) | 主流模型 (需官方支持或自己写插件) | 广泛 (需转GGUF) |
| 服务化能力 | 原生强大(动态批处理,API Server) | 需结合后端 | 需集成Triton | 弱 (基础HTTP Server) |
| 量化支持 | 一般 (通过后端如AWQ) | 依赖后端 | 强大(FP8, INT8, 编译时优化) | 顶级(GGUF格式,多种算法) |
| 最佳场景 | 云上多用户API服务,高并发流式输出 | AI Agent,复杂RAG,自动化评测 | 对延迟敏感的固定模型生产推理 | 个人开发调试,边缘设备,CPU环境 |
如何根据你的场景做选择?
场景一:我要搭建一个类似ChatGPT的对外服务,预计有很多用户同时聊天。
- 首选vLLM。它的PagedAttention和持续批处理就是为这种高并发、长文本、流式输出的场景而生的。虽然初期调优有点麻烦,但一旦稳定,其吞吐量和资源利用率是其他方案难以比拟的。
vllm serve提供的OpenAI兼容接口,也让前端集成变得异常简单。
- 首选vLLM。它的PagedAttention和持续批处理就是为这种高并发、长文本、流式输出的场景而生的。虽然初期调优有点麻烦,但一旦稳定,其吞吐量和资源利用率是其他方案难以比拟的。
场景二:我在开发一个复杂的AI应用,里面有很多“if-else”和并行工具调用的逻辑。
- 首选SGLang。它能让你的代码从面条式的Prompt拼接中解放出来,变得清晰可维护。后端可以灵活选择vLLM(追求吞吐)或llama.cpp(追求部署简便)。它的价值在于提升开发效率和复杂工作流的运行时性能。
场景三:我有一个固定的大模型,部署在线上,要求单次响应速度最快,成本控制极严。
- 首选TensorRT-LLM。忍受一次漫长的编译过程,换来的是线上推理时极致的速度和最低的GPU资源占用(意味着更低的云服务成本)。适合模型和硬件环境长期不变的业务场景。
场景四:我只是个研究者/个人开发者,想在笔记本(哪怕是Mac)上快速验证模型效果,或者资源有限。
- 首选llama.cpp。下载一个可执行文件,找一个GGUF格式的模型,几分钟内就能开始对话。它的量化能力能让你在消费级硬件上跑起巨大的模型,对于学习和原型验证来说,性价比无敌。
场景五:混合场景。
- 组合使用。例如,用SGLang + vLLM:SGLang处理复杂的业务逻辑和工作流,vLLM作为高性能推理后端提供算力。或者,用llama.cpp在开发机上进行模型测试和量化,确定模型后,再用TensorRT-LLM为生产服务器编译一个极致优化的版本。
5. 进阶话题:生态、问题排查与未来展望
关于Ollama与vLLM的区别很多人问Ollama。Ollama更像一个开箱即用的模型管理器和运行器,它底层经常调用llama.cpp或其它本地库。它提供了更友好的命令行和API,适合不想折腾的普通用户。而vLLM是一个工业级推理引擎,专注于解决高并发服务下的性能瓶颈。Ollama简单,但功能上限和性能上限不如vLLM;vLLM强大,但需要更多的运维知识。两者定位不同。
常见问题排查思路
- vLLM输出不一致:首先检查
temperature参数是否为0。其次,确认是否开启了do_sample。确保所有请求的随机种子(seed)一致。 - vLLM部署OOM:降低
--gpu-memory-utilization;检查--max-model-len是否设置过大;使用--tensor-parallel-size将模型切分到多卡;考虑启用--enable-prefix-caching(如果支持)。 - TensorRT-LLM编译失败:99%的原因是因为环境不匹配。严格对照官方文档的CUDA、TensorRT、PyTorch版本要求。使用Docker镜像是最省事的方法。
- llama.cpp速度慢:首先确认是否使用了正确的量化格式(如IQ4_XS)。在命令行中指定正确的线程数(
-t参数)。如果有GPU,确保编译时启用了CUDA支持并通过-ngl参数将部分层卸载到GPU。
未来趋势的一点个人看法目前看来,vLLM在高性能服务领域的领先地位短期内很难被撼动,其生态也在不断扩大(如对更多模型架构、更多解码算法的支持)。SGLang代表了一种趋势:即大模型推理的编程范式正在从“低级的文本拼接”向“高级的声明式编程”演进。TensorRT-LLM会继续在NVIDIA的硬件生态中扮演性能标杆的角色,随着工具链的完善,易用性可能会有所提升。llama.cpp则牢牢占据了轻量级、跨平台的生态位,特别是其强大的量化技术,让大模型在端侧运行成为可能,生命力会非常顽强。
对于大多数团队,我的建议是:从vLLM开始构建你的核心服务能力,用SGLang来构建复杂的应用逻辑,在性能瓶颈处用TensorRT-LLM进行攻坚,同时用llama.cpp作为模型量化、测试和边缘部署的利器。技术选型不是找一把“银弹”,而是为不同的任务挑选最称手的“兵器”。
