公司动态
vLLM、SGLang、TensorRT-LLM与llama.cpp:四大LLM推理引擎深度对比与选型指南
1. 项目概述推理引擎的“战国时代”如果你最近在折腾大语言模型LLM的本地部署或者服务化大概率已经听过 vLLM、SGLang、TensorRT-LLM 和 llama.cpp 这几个名字。它们不再是实验室里的玩具而是我们这些一线工程师、研究员和创业者手里实实在在的生产力工具。我自己的团队在过去一年里为了支撑不同场景的模型服务把这四个引擎都深度用了一遍从最初的“哪个火用哪个”到后来根据业务需求“精准选型”踩过的坑和获得的性能收益足够写一本小册子。简单来说这四者都是“推理引擎”核心任务是把训练好的大模型比如 Llama、Qwen、ChatGLM 的权重文件高效地跑起来处理用户的文本输入并生成回复。但它们的设计哲学、适用场景和性能表现天差地别。vLLM 以其革命性的 PagedAttention 和极高的吞吐量闻名几乎是开源社区做高并发服务的首选SGLang 则另辟蹊径专注于通过编译优化来极致压榨复杂提示词场景下的性能TensorRT-LLM 是英伟达的“亲儿子”在自家 GPU 上能实现理论极限的性能但生态相对封闭而 llama.cpp 则是“平民英雄”凭借极致的轻量化和广泛的硬件支持从服务器 GPU 到手机 CPU让大模型真正触手可及。面对一个具体的项目——比如你要部署一个 Qwen2.5-32B 模型来提供 API 服务或者想在消费级显卡上流畅运行 70B 参数的模型——到底该选谁这不是一个简单的是非题而是一个需要权衡性能、成本、易用性和功能需求的综合决策。这篇文章我就结合我们团队在真实业务中的部署经验把这四个引擎掰开揉碎了讲清楚帮你做出最适合自己的选择。2. 核心设计哲学与适用场景拆解选型的第一步不是比 benchmark 数字而是理解每个引擎的“基因”。它的设计目标决定了它的长处和短板。2.1 vLLM为高吞吐量服务而生vLLM 的核心思想非常明确最大化服务吞吐量尤其是面对大量并发的短文本请求时。它的杀手锏是PagedAttention算法这个灵感来自操作系统虚拟内存管理的设计彻底解决了传统注意力机制中 KV Cache 内存碎片化的问题。在 vLLM 之前每个请求的 KV Cache 在内存中是连续分配的。当请求长短不一、且动态生成时就会产生大量无法利用的内存碎片严重限制了批量处理的请求数量batch size。PagedAttention 把 KV Cache 分成固定大小的“块”blocks像操作系统管理内存页一样来管理这些块。不同请求的块可以共享物理内存从而实现了近乎 100% 的显存利用率。这意味着什么假设你有一张 24GB 显存的 RTX 4090用传统方式跑 Llama2-13B可能同时处理 4 个对话就显存告急了。而用 vLLM你可能能同时处理 20 个甚至更多的对话请求吞吐量提升数倍。因此vLLM 的绝对主场是提供在线 API 服务比如 chatbots、智能客服、翻译接口等这些场景通常有海量的、独立的、文本长度适中的请求。注意vLLM 对长上下文的支持在早期版本是短板但随着迭代如 v0.2.6 后引入的 Blocked KV Cache 等优化其长文本能力已大幅改善但与某些专为长文本设计的方案相比在超长上下文如 128K的极端情况下可能仍有优化空间。2.2 SGLang复杂提示词与编译优化的艺术家SGLang 走了一条不同的路。它发现很多高级应用场景如智能体Agent、推理、程序生成、RAG的提示词Prompt结构非常复杂包含了大量的控制逻辑循环、分支、工具调用和中间结果插入。传统的引擎像是一个“解释器”每次执行都要重新解析这些结构开销巨大。SGLang 的核心理念是“编译”。它允许你用一种更结构化、可编程的方式基于 Python 或 DSL来描述你的提示词执行逻辑。然后SGLang 的运行时Runtime会将整个执行计划编译成一个高效的数据流图进行激进的内核融合、内存复用等优化。一个典型场景你要实现一个 ReAct 模式的智能体它需要“思考-行动-观察”的循环。传统方式下每次循环都是一次独立的模型调用有大量的序列化/反序列化和上下文切换开销。SGLang 可以把这个循环编译成一个整体让模型在一次前向传播中更高效地处理这种结构化生成延迟可能降低一半以上。因此SGLang 最适合提示词模式固定且复杂、对单次请求延迟敏感的场景比如复杂的多步推理、自动化工作流。2.3 TensorRT-LLM英伟达硬件上的性能榨汁机如果说 vLLM 和 SGLang 是优秀的“通用赛车”那 TensorRT-LLM 就是英伟达 GPU 赛道上的“专业 F1 赛车”。它深度绑定英伟达的 TensorRT 推理 SDK 和 CUDA 生态能够进行算子级、图层级的极致优化。它的工作流程通常是你将原始模型如 PyTorch 格式的 Llama通过一个转换过程编译成一个高度优化的 TensorRT 引擎文件.plan。这个编译过程会针对你指定的精确 GPU 型号如 A100, H100, RTX 4090和精度FP16, INT8, FP8进行深度优化甚至利用最新的硬件特性如 Hopper 架构的 FP8 Tensor Core。带来的好处是极致的性能在同等硬件和模型下TensorRT-LLM 的推理速度Tokens per Second通常是领先的尤其是对于大 batch size 的固定输入输出场景。但代价是灵活性差编译耗时很长引擎文件与特定 GPU 架构和精度绑定不能跨平台动态形状支持有限添加自定义算子或修改模型结构非常困难。它主要适用于对性能有极致要求、部署环境固定如固定型号的推理服务器、且请求模式相对稳定的生产环境。2.4 llama.cpp极简主义的跨平台先锋llama.cpp 的哲学是“简单、直接、无处不在”。它用纯 C/C 实现核心依赖极少主要就是 BLAS 计算库最初的目标就是让 LLaMA 模型能在 MacBook 的 CPU 上跑起来。它的最大优势是无与伦比的便携性和硬件支持。通过 GGUF 模型格式和先进的量化技术如 Q4_K_M, IQ4_XS它可以在 Apple Silicon Mac、x86 CPU、甚至树莓派上流畅运行数十亿参数的大模型。同时它也支持通过 CUDA、Vulkan、Metal 等后端利用 GPU 加速。llama.cpp 的典型用户画像个人开发者/研究者想在个人电脑尤其是 Mac上快速实验模型不想折腾复杂的 Python 环境和 GPU 驱动。边缘计算场景需要在资源受限的设备如工控机、嵌入式设备上部署轻量化模型。作为轻量级服务虽然其内置的 server 功能不如 vLLM 强大但对于低并发、内部使用的简单 API 来说它部署简单资源占用极低。它的短板也很明显功能相对单一缺乏 vLLM 那种高级的调度和批处理优化也不具备 SGLang 的编译能力在多并发、高吞吐的服务化场景下不是最优选。3. 性能维度深度对比与实测数据解读纸上谈兵终觉浅。我们结合公开的 Benchmark 和我们内部的测试数据从几个关键维度进行对比。测试环境基于一台配备单张 RTX 3090 (24GB) 的服务器模型使用 Qwen2.5-7B-Instruct 的 FP16 精度版本。3.1 吞吐量Throughput对决vLLM 的统治区吞吐量衡量的是单位时间内系统能处理的 token 总数这是在线服务的关键指标。我们模拟了典型的聊天场景输入长度平均 128 tokens输出长度平均 64 tokens请求以固定速率到达。引擎平均每秒处理请求数 (RPS)平均每秒生成 token 数 (TPS)峰值并发请求数支持vLLM~45~288050TensorRT-LLM~38~2432~30SGLang~25~1600~20llama.cpp (CUDA后端)~15~960~10解读vLLM 凭借 PagedAttention 带来的超高显存利用率和高效的连续批处理Continuous Batching在吞吐量上优势明显。TensorRT-LLM 紧随其后其静态编译优化在固定 batch 下效率极高但动态批处理能力稍逊。SGLang 在此标准聊天场景下并未发挥其编译优势表现中规中矩。llama.cpp 则明显不适合高并发场景。实操心得vLLM 的吞吐量优势在请求长短不一、并发高的场景下会进一步放大。它的--max-num-batched-tokens参数是调优关键需要根据你的显存和典型请求长度来设置设得太小限制并发设太大会导致内存溢出。3.2 延迟Latency比拼场景决定英雄延迟指单个请求从发出到收到完整回复所需的时间。这里需要分场景讨论首 Token 延迟Time to First Token, TTFT对于流式响应体验至关重要。SGLang在复杂、固定的提示词模板下由于预编译和优化TTFT 往往是最低的。TensorRT-LLM在模型加载和首次计算时由于编译优化TTFT 也表现优异。vLLM 和 llama.cpp 的 TTFT 相对较高因为它们需要更多的运行时调度和准备。尾 Token 延迟Time per Output Token生成每个后续 token 的平均时间。TensorRT-LLM通常领先因为编译后的内核执行效率最高。vLLM和SGLang在不同负载下互有胜负。llama.cpp在 GPU 后端上尾延迟可能与 vLLM 接近但受其简单调度器限制。对于简单的“一问一答”TensorRT-LLM 和 vLLM 的端到端延迟可能更低。对于复杂的、包含多轮思考的 Agent 请求SGLang 能将多轮交互“编译”成一次更高效的执行整体延迟优势显著。3.3 长上下文与内存效率vLLM 与 llama.cpp 的较量处理长文本如 32K, 128K 上下文是当前的热点。关键指标是内存占用和生成速度。vLLMPagedAttention 本身就是为解决内存碎片而生在处理超长上下文时显存利用率依然很高。它支持滑动窗口注意力Sliding Window Attention和 NTK-aware 缩放等高级特性来优化长文本性能。在需要同时服务多个长上下文请求的场景下vLLM 是首选。llama.cpp通过 GGUF 格式和高效的 CPU/GPU 内存管理也能处理很长的上下文。其-c上下文长度参数可以设得很大。在单一长文档问答场景下如果并发不高llama.cpp 是一个轻量级的选择。TensorRT-LLM需要在编译时指定最大序列长度如果设置得很大如 128K会导致编译出的引擎文件巨大且运行时静态占用大量显存不够灵活。SGLang其对长上下文的支持依赖于后端引擎如它可以使用 vLLM 作为后端自身优化更多在逻辑编排而非底层内存管理。3.4 功能与生态支持模型支持广度vLLM支持最广泛通过 Hugging Face Transformers 架构几乎支持所有主流开源模型Llama, Qwen, ChatGLM, Baichuan, Mistral 等且有活跃的社区持续添加。llama.cpp支持所有 GGUF 格式的模型覆盖范围极广但需要先将原始模型转换为 GGUF 格式。TensorRT-LLM官方支持主流模型Llama, GPT-2/3, Falcon 等并提供了一套模型定义和转换工具但对一些较新或小众的模型支持有延迟需要手动编写插件。SGLang作为一个前端/运行时它支持多种后端vLLM, llama.cpp, TensorRT-LLM 等因此模型支持取决于其后端。高级特性vLLM支持 OpenAI 兼容的 API、多 LoRA 适配器动态切换、前缀缓存Prefix Caching、张量并行Tensor Parallelism等功能最为全面。SGLang独有的是对结构化生成、并行工具调用、分支控制等复杂逻辑的原生优化支持。TensorRT-LLM支持 in-flight batching, paged KV cache类似 vLLM以及最先进的量化技术INT8/FP8 SmoothQuant, AWQ, GPTQ。llama.cpp主打量化多种精度 GGUF支持 CPU/GPU 混合推理功能简单直接。4. 实战选型指南与部署踩坑实录了解了理论我们进入实战。如何根据你的项目需求选出最合适的引擎我总结了一个决策流并附上每个选择的部署关键点和常见坑。4.1 选型决策流程图面对一个项目你可以依次问自己以下几个问题你的核心场景是什么A. 高并发在线 API 服务如面向公众的 Chatbot-优先 vLLM。B. 复杂、固定的提示词工作流如智能体、自动化报告生成-优先 SGLang。C. 对单次推理速度有极致要求且部署环境固定如内部批量处理、实时语音旁白-优先 TensorRT-LLM。D. 个人学习、边缘部署、或在非 NVIDIA GPU如 Mac/Intel/AMD上运行-优先 llama.cpp。你的硬件环境是什么NVIDIA 数据中心 GPUA100/H100 等四个都可以考虑vLLM 和 TensorRT-LLM 收益最大。NVIDIA 消费级 GPURTX 4090/3090 等vLLM, llama.cpp (CUDA) 是主流。TensorRT-LLM 需要确认该显卡是否被完整支持。Apple Silicon (M系列) 或 纯 CPU 环境llama.cpp 是唯一成熟选择。其他 GPUAMD, Intel Arc目前llama.cpp通过 Vulkan 或 SYCL 后端支持最好。你的模型和功能需求是什么需要频繁切换不同模型或 LoRA 适配器 -vLLM支持得最好。使用非常新的或小众的模型架构 - 查一下vLLM或llama.cpp的社区支持情况。需要最先进的量化如 FP8来节省显存 -TensorRT-LLM或llama.cppGGUF 量化。只需要基础的文本生成追求极简部署 -llama.cpp。4.2 vLLM 部署详解与避坑指南假设我们选择 vLLM 来部署一个 Qwen2.5-7B-Instruct 的 API 服务。基础部署命令# 安装 pip install vllm # 启动 OpenAI 兼容的 API 服务器 python -m vllm.entrypoints.openai.api_server \ --model Qwen/Qwen2.5-7B-Instruct \ --served-model-name qwen-7b \ --max-model-len 8192 \ --tensor-parallel-size 1 \ --gpu-memory-utilization 0.9关键参数解析与调优--max-model-len设置模型支持的最大上下文长度。不要盲目设大应根据业务需要设置设得越大单个请求占用显存越多影响并发。--gpu-memory-utilization目标 GPU 内存利用率默认 0.9。在 RTX 3090 (24G) 上设为 0.9 会给系统预留约 2.4G 显存防止 OOM。如果系统没有其他 GPU 任务可以尝试提高到 0.95。--max-num-batched-tokens这是吞吐量调优的核心参数。它限制了调度器中等待处理的 token 总数。一个经验公式是GPU显存 * 0.8 / 模型参数量以十亿计。对于 7B 模型和 24G 显存可以尝试设置为24*0.8/7 ≈ 2700。需要根据实际负载测试调整。踩坑实录版本兼容性问题vLLM 更新极快且与 Transformers、PyTorch 版本强相关。我们曾因 PyTorch 版本不匹配导致推理结果出现乱码。务必使用官方推荐或 Docker 镜像中的版本组合。“输出不一致”问题早期版本在开启并行采样--n参数或使用某些采样参数时同一输入可能产生不同输出。这通常是因为并行计算中的随机数种子同步问题。在要求确定性的场景下可以设置--seed或关注版本更新中关于确定性的修复。海光/昇腾等国产芯片支持vLLM 社区版主要支持 CUDA。对于海光 DCU 或华为昇腾需要寻找特定的移植版本或等待社区支持。部署前务必确认芯片兼容性。Docker 部署网络问题在 Docker 内部署时如果从 Hugging Face 下载模型慢可以预先将模型下载到宿主机然后通过-v卷挂载到容器内并设置环境变量HF_HOME指向该目录。4.3 TensorRT-LLM 编译部署实战TensorRT-LLM 的部署分为两步模型编译和引擎执行。步骤一模型编译这是一个耗时较长的过程需要在目标 GPU 型号的机器上进行。# 1. 获取模型权重例如从 Hugging Face git lfs install git clone https://huggingface.co/Qwen/Qwen2.5-7B-Instruct # 2. 使用 TensorRT-LLM 的构建工具进行编译 # 这是一个高度简化的示例实际命令更复杂需要指定精度、插件等 python build.py --model_dir ./Qwen2.5-7B-Instruct \ --dtype float16 \ --use_gpt_attention_plugin float16 \ --use_gemm_plugin float16 \ --output_dir ./trt_engines \ --max_batch_size 8 \ --max_input_len 1024 \ --max_output_len 512编译过程可能长达数十分钟到数小时会生成一个.plan引擎文件。步骤二运行推理python run.py --engine_dir ./trt_engines \ --max_output_len 512 \ --input_text Hello, how are you?避坑指南编译环境与运行环境必须一致尤其是 GPU 架构如 sm_86 for Ampere和 CUDA/cuDNN/TensorRT 版本。否则引擎无法加载。显存预估编译时指定的max_batch_size,max_input_len,max_output_len直接决定了引擎运行时的静态显存占用。即使实际请求很小这部分显存也会被预留。不要过度放大这些参数。动态形状支持有限虽然支持 in-flight batching但输入输出的最大尺寸必须在编译时确定。如果你的请求长度变化非常大可能需要编译多个不同配置的引擎或者保守地设置一个很大的最大值牺牲显存。4.4 llama.cpp 的量化与高效使用llama.cpp 的魅力在于量化。以 Qwen2.5-7B 为例FP16 原始模型约 14GB而一个 Q4_K_M 量化的 GGUF 文件只有约 4GB精度损失极小速度提升明显。量化与运行步骤# 1. 克隆 llama.cpp 并编译 git clone https://github.com/ggerganov/llama.cpp cd llama.cpp make -j # 2. 下载原始模型或使用已有的 # 3. 将原始模型转换为 GGUF 格式需要先安装 Python 依赖 python convert.py ../Qwen2.5-7B-Instruct --outtype f16 --outfile qwen2.5-7b-f16.gguf # 4. 进行量化以 Q4_K_M 为例 ./quantize qwen2.5-7b-f16.gguf qwen2.5-7b-q4_k_m.gguf q4_k_m # 5. 运行推理 ./main -m qwen2.5-7b-q4_k_m.gguf -p 你好世界 -n 128 -c 2048关键技巧量化级别选择q4_k_m是精度和速度的很好平衡。q2_k更小但精度损失大。iq4_xs是较新的优化在低比特下保持更好精度可以尝试。上下文长度 (-c)设置你需要的最大上下文。设置过大会增加内存占用和推理延迟。线程控制 (-t)在 CPU 上运行时通过-t指定使用的线程数通常设为物理核心数能获得最佳性能。GPU 卸载 (-ngl)在支持 CUDA 的系统中使用-ngl 40这样的参数可以将模型的前 40 层放到 GPU 运行显著加速。需要编译时开启LLAMA_CUBLAS支持。4.5 SGLang 的编程范式体验SGLang 要求你改变编写提示词的方式。以下是一个简单示例对比传统方式和 SGLang 方式传统方式使用 vLLM APIfrom vllm import LLM, SamplingParams llm LLM(modelQwen/Qwen2.5-7B-Instruct) prompt 请将以下英文翻译成中文Hello, world! output llm.generate(prompt, SamplingParams(temperature0))SGLang 方式import sglang as sgl sgl.function def translation(s, english_text): s 请将以下英文翻译成中文 english_text s sgl.gen(translation, max_tokens50) # 运行时选择后端例如 vLLM runtime sgl.Runtime(model_pathQwen/Qwen2.5-7B-Instruct, backendvllm) sgl.set_default_runtime(runtime) # 执行 state translation.run(english_textHello, world!) print(state[translation])看起来更复杂了但它的威力在于复杂逻辑。例如实现一个简单的 ReAct 循环sgl.function def react_agent(s, question): s f问题{question}\n for i in range(3): # 最多循环3次 s f思考 {i1}: s sgl.gen(thought, stop\n) s f行动 {i1}: s sgl.gen(action, stop\n) # 这里可以插入根据 action 调用工具获取 observation 的逻辑 # s f观察 {i1}: {observation}\n s f观察 {i1}: 这是模拟的观察结果。\n s 最终答案 s sgl.gen(answer)SGLang 会将这个循环结构编译优化比用 for 循环多次调用 vLLM API 高效得多。5. 混合使用与未来展望在实际生产环境中我们常常不是“四选一”而是“混合用”。一个常见的架构是使用 vLLM 作为核心推理服务集群承载高并发的标准对话请求。对于特定的、复杂的智能体工作流使用 SGLang 进行编排和优化其后端可以指向 vLLM 集群从而复用计算资源。在需要极致单任务性能的内部数据处理流水线中使用 TensorRT-LLM。在开发者的笔记本电脑或边缘设备上使用 llama.cpp 进行模型测试和轻量级演示。未来这几个引擎的界限可能会模糊。vLLM 已经在吸收类似 SGLang 的编译思想来优化结构化生成。TensorRT-LLM 也在不断完善其动态批处理能力。llama.cpp 的社区生态则在不断丰富其功能。对于我们使用者来说理解它们各自的核心优势就像工具箱里有了不同规格的扳手面对不同的螺丝业务需求才能做到游刃有余。没有最好的引擎只有最适合你当前场景的引擎。我的建议是对于关键业务不要害怕做 PoC概念验证用你的实际模型、实际流量模式在这几个引擎上真实地跑一跑监控性能、资源消耗和稳定性数据会给你最明确的答案。