Benchmarking Local LLM Servers: llama.cpp, llamafile, LM Studio, and Ollama

TL;DR · AI 摘要
配置优化对本地LLM服务器性能影响显著,不同平台的设置可带来最高63%的性能提升。
核心要点
- 启用CUDA graphs可使L40S解码速度提升16.8%(0.8B模型)
- Vulkan shader工具链使Steam Deck 9B模型提示处理加速63%
- 四款工具共享llama.cpp核心,性能差异主要来自配置而非引擎
结构提纲
按章节快速跳转。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- 本地LLM服务器性能对比
- 测试平台
- Mac Studio M4
- Steam Deck
- Linux L40S
- 关键配置
- CUDA graphs
- Vulkan shader
- 性能发现
- 配置影响>引擎选择
- 共享llama.cpp内核
金句 / Highlights
值得收藏与分享的关键句。
启用CUDA graphs使L40S 0.8B模型解码速度提升16.8%
Vulkan shader工具链使Steam Deck 9B模型提示处理加速63%
四款工具共享llama.cpp内核,性能差异小于5%(固定权重环境下)
对 llama.cpp、llamafile、LM Studio 和 Ollama 的基准测试:吞吐量表现对比
技术内容
本地 LLM 服务器基准测试:llama.cpp、llamafile、LM Studio 和 Ollama
本地 LLM 服务器基准测试在 Mac、Linux 和 Steam Deck 平台上评估了 llama.cpp、llamafile、LM Studio 和 Ollama 的表现。研究发现,构建标志和配置可带来高达 63% 的性能提升,而底层引擎由于共享 llama.cpp 核心,表现相似。
#### Davide Eynard, Anushri Gupta
2026 年 9 月 17 日
—
12 分钟阅读
本地运行 LLM 不仅仅是选择模型。服务工具起着关键作用,因为它决定了提示的处理速度、令牌的生成速度以及模型部署的难易程度。我们使用 exp-llama-benchy(依赖 llama-benchy 的基准测试工具)对四种流行的本地服务器(llama.cpp、LM Studio、Ollama 和我们自己的 llamafile)进行了测试,测量了这些差异。
我们的测试在 Mac Studio M4(使用 Metal GPU 加速)、配备 NVIDIA L40S(CUDA)的 Linux 服务器以及 Steam Deck(Vulkan)上进行。我们测试了三种 Qwen 模型规模:0.8B、9B 和 27B(由于内存限制,Steam Deck 上跳过了 27B 模型),并测试了从 1,024 到 8,192 个令牌的提示解析以及生成 32 或 64 个令牌输出的性能。
这不是最终排名。这是一份实用快照,展示了这些工具在三种不同环境中使用相同模型权重时的表现,试图理解每个服务器的“独门秘技”所在。
我们的发现
- 最大的加速来自配置而非引擎选择。在 llamafile 构建中启用 CUDA 图表使 L40S 在 0.8B 模型上的解码速度提升了 16.8%。新的 Vulkan 着色器工具链使 Steam Deck 在 9B 模型上的提示处理速度提升了高达 63%,推测解码草稿长度在不同平台间切换,Metal 平台使用草稿 2,CUDA 平台使用草稿 4。
- 所有四个服务器共享相同的核心。它们都通过 llama.cpp 内部实现 GGUF 服务,这就是为什么在权重和环境固定后,它们的提示处理性能相差仅几个百分点,为什么上述设置比选择哪个服务器更重要。
- 大多数解码差距是固定的主机开销,而非 GPU 工作。这几乎是每个令牌的固定成本(Mac 上约 0.4 毫秒,L40S 上 1.8 毫秒,Steam Deck 上 5.4 毫秒),因此在快速模型上,相同开销会表现为较大的百分比,而在慢速模型上则表现为较小的百分比。
测试设置
我们测试了三种环境:
kg-card-begin: html
环境
硬件
操作系统
测试模型
Mac Studio
M4 Max,64 GB 统一内存
macOS Tahoe 26.6.2
Qwen3.5 0.8B,Qwen3.5 9B,Qwen3.8 27B
Steam Deck
Steam Deck OLED,AMD Van Gogh APU,16 GB 共享内存
Steam OS 3.8.16(构建 20260716.1)
Qwen3.5 0.8B,Qwen3.5 9B
Linux L40S 系统
32 核 Intel Xeon Gold 6338,1 块 NVIDIA L40S 48 GB VRAM
Ubuntu 24.04.3 LTS
kg-card-end: html
软件版本在所有三台机器上完全相同:llama.cpp b10441(提交 0177dcc73),llamafile 0.10.6(提交 42ff11b),Ollama 0.34.0,LM Studio 运行时 2.28.2(metal / cuda12 / vulkan),llama-benchy 0.4.0。
每个运行时都从 lmstudio-community 获取相同的 GGUF 文件:llama.cpp 和 llamafile 直接加载它们;Ollama 通过从这些文件构建的标签提供它们;LM Studio 则通过显式的模型密钥固定到相同的 GGUF。0.8B 测试使用了 Q8 类量化文件,而 9B 测试使用了 Q4_K_M 量化。每个模型都加载了 16,384 个令牌的上下文长度,完全卸载 GPU,并且对于 27B 模型我们启用了推测解码(草案长度为 2,这是 LM Studio 的默认值)。我们刻意保留了每个运行时自身的批处理默认值。
我们测量的指标
基准测试报告了两个吞吐量指标,单位均为每秒令牌数:
- 提示处理(PP)衡量服务器在文本生成开始前处理输入提示的速度。
- 令牌生成(TG)衡量服务器在处理完提示后生成输出令牌的速度。
在处理长文档、大型代码库、代理或长对话历史时,提示处理速度最为关键。而在交互式聊天中,用户等待响应出现时,令牌生成速度更为重要。基准测试使用了四种提示大小(1,024、2,048、4,096 和 8,192 个令牌),并使用 32 和 64 个输出令牌进行文本生成测量。
我们在图表中看到的每个数据点都是 15 次 llama-benchy 运行的结果。第一次仅用于预热并被忽略;其余 14 次中,最快的 2 次和最慢的 2 次被丢弃,中间的 10 次取平均值。误差条表示所有 14 次预热后运行的 ±1 个标准差。每次运行前都会重启服务器,因此权重和 KV 缓存都是冷启动的,四个服务器在每个模型评估中交替运行,因此机器状态的缓慢漂移不会偏向于率先运行的服务器。
测量在客户端进行,有一个例外:LM Studio 在 macOS 上的解码时间取自引擎自身的计时。原因是 LM Studio 在 macOS 上以突发方式释放输出流,导致客户端数据与服务器端数据不一致。
Linux / NVIDIA L40S
在 NVIDIA L40S 上,提示处理速度接近。差异体现在令牌生成速度上:
Linux 服务器,NVIDIA L40S(CUDA)。上图行是提示处理,下图行是 64 个令牌输出时的令牌生成,按提示长度划分。数值越高越好。每个数据点是 15 次运行的截尾平均值(排除预热运行,丢弃最快的 2 次和最慢的 2 次,取中间 10 次的平均值);误差条表示 14 次预热后运行的 ±1 个标准差。每个图表的 y 轴独立设置,不从零开始。
对于这种显著差距的一个假设是主机端存在固定的每令牌成本,而非 GPU 工作差异。作为百分比,快速模型(67%)差距显著,而慢速模型(18%)差距较小,但我们通过测量每令牌的绝对值(单位为毫秒)验证了这一点,并确认它在不同模型间几乎恒定:L40S 上约为 1.8 毫秒,Mac 上约为 0.4 毫秒,Steam Deck 上约为 5.4 毫秒。
这个实验也是构建标志击败所有引擎差异的地方:此前,llamafile 的 CUDA 后端编译时未启用 CUDA 图表。启用后,0.8B 模型的解码速度提升了 16.8%,9B 模型提升了 6.5%,27B 模型提升了 4.3%。
Mac Studio
在 Metal 上,提示处理速度惊人地一致。在所有三个模型中,llama.cpp、llamafile 和 Ollama 在每个提示长度上的表现都在彼此 ±3% 范围内。例外情况是 LM Studio 在较小的模型上,这很可能又是固定成本导致的。
Mac Studio(Apple M4 Max,Metal)。上排为提示处理,下排为64个标记输出时的标记生成,按提示长度划分。数值越高越好。每个数据点为15次运行的截尾均值(排除预热阶段,去掉最快和最慢的2次运行,取中间10次的平均值);误差条表示预热后14次运行的标准差±1倍。每个面板的y轴独立,且不从零开始。LM Studio生成在服务器端进行,其余在客户端进行。
Metal环境下,草稿长度的影响最为显著:在Ollama库默认的4个标记推测解码下,27B解码的性能实际上比完全不使用推测还差(≈15 vs 23.4 tok/s)。当草稿长度为2时,性能提升至24-25 tok/s。而在L40S上,草稿长度4反而比草稿长度2性能提升高达16%。结论是不存在通用的“最佳”设置。
Steam Deck
Deck在所有机器中表现出最显著的性能差异,且几乎所有差异都源于着色器编译器的选择。
Steam Deck(AMD Van Gogh APU,Vulkan)。上排为提示处理,下排为64个标记输出时的标记生成,按提示长度划分,适用于0.8B和9B模型。数值越高越好。每个数据点为15次运行的截尾均值(排除预热阶段,去掉最快和最慢的2次运行,取中间10次的平均值);误差条表示预热后14次运行的标准差±1倍。每个面板的y轴独立,且不从零开始。
Steam Deck上有四条折线图:llama.cpp和llamafile在提示处理和生成方面均领先,Ollama位于其下,LM Studio则明显落后,尤其在9B生成方面。
我们通过直接测试而非推断验证了这一点。基于相同的llamafile/llama.cpp提交版本,使用两种不同版本的Vulkan着色器库(Ubuntu 24.04的shaderc 2023.8 vs LunarG Vulkan SDK的2026.03),性能提升如下:
- 提示处理:+25.9%(0.8B),+63.3%(9B)
- 解码:+18.2%(9B),−0.6%(0.8B)
LM Studio在图表中的性能劣势源于其预装运行时的特性,而非引擎本身。与其它方案不同,用户无法通过自行调整解决该问题,因为运行时是预先构建好的。
为何提示处理曲线呈现三种不同形态
在解读图表时,我们惊讶地发现三种环境下的提示处理曲线差异显著:在L40S上,吞吐量随提示长度增加而上升;在Mac上,吞吐量先上升后下降;在Deck上,吞吐量主要呈下降趋势。有趣的是,这并非三种不同行为,而是对同一条曲线的三种不同视角。
模型预填充时间公式为t(n) = c + a·n + b·n²:固定请求成本(c)、线性项(矩阵乘法,a·n)和二次项(注意力机制,b·n²)。吞吐量n/t(n)在n* = √(c/b)时达到峰值。低于该点时,固定成本仍在摊销,吞吐量持续上升;高于该点后,注意力机制主导性能。
拟合测量的0.8B曲线数据:
| 机器 | c(固定成本) | b(注意力) | 峰值n* | n=8,192时注意力占比 | |--------------|----------------|------------------|------------|----------------------| | L40S / CUDA | 52 ms | 0.071 ns/tok² | ~27,000 | 1.4% | | M4 Max / Metal | 19 ms | 2.46 ns/tok² | ~2,800 | 14.4% | | Steam Deck / Vulkan | 288 ms | 70.2 ns/tok² | ~2,000 | 40.1% |
L40S的峰值位置超过我们测试的最长提示长度三倍以上,因此我们始终只看到上升阶段。Deck在8,192个标记时已达到40%的注意力限制。
各运行时自身的权重:Apple硅上的MLX
在上述所有内容中,权重均被固定,这是比较引擎最公平的方式,但并非人们通常运行这些工具的方式。在苹果芯片上,Ollama 和 LM Studio 都提供 MLX(苹果自己的模型权重标准,而非 GGUF)版本,除非明确选择 GGUF 变体,否则通常默认使用 MLX 构建。因此,我们认为仅展示每个运行时在其首选工件(包括最大 27B 模型)上的性能是公平的:
提示处理有所改善,且两者提升幅度相同:Ollama 在 1,024 个 token 提示下提升 9.9%,LM Studio 提升 10.7%;在 8,192 个 token 时分别提升约 6% 和 9%。这是比较中清晰的部分:无混淆因素,且两个运行时都大致提升了 10%。
Apple M4 Max,Qwen 27B:每个运行时在共享的 GGUF 与自身 MLX 构建之间的对比。数值越高越好;误差条为 ±1 标准差。这两列使用不同的刻度和不同的权重,因此应单独阅读,而非相互比较。GGUF 是共享的 draft-2 配置。注意:在 MLX 上,Ollama 自动启用推测解码,而 LM Studio 没有启用,因此生成面板并未测量相同的内容。llama.cpp 和 llamafile 未出现在此图中,因为它们没有 MLX 路径。
生成部分才是关键所在,也是两者可比性终止的地方。这两个 MLX 数值之间的差距并非源于 MLX:Ollama 的 MLX 运行时会自动启用具有自适应草稿深度的推测解码,而 LM Studio 的 MLX 完全不进行草稿生成。
这些数据需要特别注意两点。这些工件的权重并不相同:LM Studio 的 MLX 构建是 4 位仿射(group size 64,15 GB),Ollama 的标签报告为 nvfp4(18.2 GB),共享的 GGUF 是 Q4_K_M(17.7 GB)。此外,这个实验回答的是“每个运行时在默认配置下的速度”,而非“哪个引擎更快”。llama.cpp 和 llamafile 未出现,因为它们都没有 MLX 路径,这一点本身在选择 Mac 工具时值得考虑。
这些结果在实际中的意义
没有一种通用的服务器适用于所有场景,但原因比“视情况而定”更具体。在控制权重、构建标志、着色器工具链和后台负载后,四个引擎在提示处理上的性能差异仅在百分之几以内,而大部分解码差异是固定的每 token 主机侧成本。导致我们数据变化数十个百分点的因素,实际上是编译器标志、着色器工具链和推测解码设置。
我们的实际建议并非“为每个服务器进行基准测试”。总体而言,可以总结为以下几点建议:
- 检查服务器的构建方式,而不仅仅是它使用的是哪种引擎。在 Deck 上,相同引擎通过不同方式编译的性能差异可达 1.6 倍。
- 根据平台匹配推测解码设置,因为最佳值会在 Metal 和 CUDA 之间切换。
- 如果你关心模型性能,请留意机器上运行的其他程序。
- 将提示处理与生成分开,并关注你实际使用的提示长度。
一如既往,根据你需要解决的任务做出自己的选择:对于长文档摘要,提示处理可能主导总延迟;对于聊天或代码补全,token 生成通常更明显。仅在与部署环境相似的硬件上对模型和服务器组合进行基准测试,并记住不同设置下的结果可能无法预测你的实际体验。
性能始于可用性
限制
这些结果比较的是实际应用场景而非完全受控的后端实现,因此需要说明一些注意事项。
报告的数值经过了裁剪。每个数据点是14次预热后运行中中间10个值的平均值,其中最快的2次和最慢的2次被剔除;误差条表示所有14次运行的标准差。虽然裁剪能稳定中心估计值,但会隐藏尾部数据,因此图表低估了偶尔出现的异常值。
测时工作在客户端进行,有一个例外。由于LM Studio在macOS上的解码是以引擎自身的计时方式测量的(在那里输出是以突发方式释放的,客户端测得的数据与服务器端不一致),因此该系列数据的测量方式与其他系列不同。
基准测试测量的是服务器运行后的吞吐量,尚未测量首次生成令牌的时间、端到端延迟、模型加载时间、内存使用情况、功耗或并发请求数。这些因素可能会影响实际排名。
LM Studio和Ollama的多个配置中存在较高的方差,也值得进一步研究。特别是,在L40S上,短文本和长文本生成测试有时会产生不同的速度,而llama.cpp和llamafile则相对稳定。
下一步计划
下一轮测试应包括Windows系统以及更多macOS和Linux硬件。我们还希望将测试范围扩展到吞吐量以外,包括首次生成令牌时间、模型加载和启动时间、内存和功耗等指标。
最后,这些测试仅覆盖了Qwen系列模型。Llama、Gemma、Mistral和专家混合模型的测试结果将有助于区分通用服务器行为与模型特定效应。
结论
本次基准测试最明确的结果也是最缺乏吸引力的:所有服务器最终都建立在llama.cpp之上,因此只有当引擎为特定平台或模型引入临时优化(如llamafile对CPU推理的优化、MLX对Metal的优化,或ds4对少量临时模型的优化)时,才能取得领先优势。除此之外,影响我们数据数十个百分点的因素是配置:一个编译器标志、一个着色器工具链、一个推测解码设置。
更广泛的结论比任何单一结果都更重要:本地LLM性能取决于模型、工作负载和平台。有用的比较必须将提示处理与令牌生成分开,报告方差,记录环境,并避免将结果简化为单一分数。它应更关注为什么某个引擎表现最佳,而非仅仅关注哪个引擎表现最好。
exp-llama-benchy工具为重复这些测试并将其扩展到更多硬件、模型和操作系统提供了基础。
Mozilla AI 团队在 Mac、Steam Deck 和 NVIDIA 设备上对四款本地 LLM 服务器(llama.cpp、llamafile、LM Studio 和 Ollama)进行了基准测试,试图找出哪款速度最快。
结果证明,这根本就是个错误的问题。当他们固定模型和硬件后,四款服务器的性能差距仅在百分之几以内,因为它们本质上都基于相同的 llama.cpp 核心。
真正影响性能的是构建方式而非服务器选择。llamafile 编译时遗漏的一个编译器标志导致性能损失了 17%。而 Steam Deck 上更新的图形工具链则带来了 60% 的性能提升。相同代码,不同构建配置,性能差异巨大。
对本地运行模型的用户建议:不要纠结于选择哪个工具,而应重点检查其编译方式。完整的测试数据、三台设备的对比结果以及我们发布的修复方案都在文章中。链接如下:
GitHub - mozilla-ai/exp-llama-benchy: 使用 llama-benchy 进行对比基准测试的工具
使用 llama-benchy 进行对比基准测试的工具 - mozilla-ai/exp-llama-benchy
GitHub
mozilla-ai