[KongchangAI]
· 3 min read· 1,628 words

vLLM vs Ollama vs llama.cpp: The Ultimate LLM Inference Engine Selection Guide

vLLM vs Ollama vs llama.cpp: The Ultimate LLM Inference Engine Selection Guide

Starting from the physical principles of inference, this article compares the mechanisms, performance, and hardware matching of vLLM, Ollama, and llama.cpp, and provides tiered selection recommendations.

The article points out that autoregressive generation consists of a compute-intensive Prefill stage and a bandwidth-intensive Decoding stage, which is the physical root of the performance differences among the three engines. vLLM uses PagedAttention to reduce KV Cache VRAM waste from 60%-80% to below 4%, and with continuous batching reaches 1850+ tok/s at 32 concurrency, making it the only engine aimed at multi-tenant APIs. llama.cpp achieves the fastest single-user speed with pure C/C++ and GGUF K-quants (115 tok/s for an 8B model) and lets a 70B model run within 42GB. Ollama is a Go wrapper around llama.cpp with only a 3%-5% performance gap, in exchange for single-command startup and an OpenAI-compatible API. The article concludes with selection conclusions for three tiers: individual, Mac/edge, and enterprise production.

When enterprises start moving large models from "calling APIs" to "self-hosting," the first unavoidable architectural decision is choosing an inference engine. vLLM, Ollama, and llama.cpp are often discussed side by side in the community, but they actually serve three completely different deployment scenarios. This guide starts from the physical principles of inference and breaks down the technical mechanisms, performance differences, and hardware matching strategies of the three.

vLLM vs Ollama vs llama.cpp inference engine comparison

First, understand the two stages of inference

Any autoregressive Transformer generation process is divided into two stages with completely different characteristics, and this is the prerequisite for understanding the differences between engines.

The Prefill stage (prompt ingestion) is compute-intensive. The engine processes the entire input prompt in parallel at once, such as a 4,000-token code repository context. At this point, GPU Tensor Cores are fully saturated, and performance is measured in TFLOPS.

The Decoding stage (token-by-token generation) is memory-bandwidth-intensive. Each generated token requires reading the entire model weight matrix from VRAM into the processor cache. Therefore, the ceiling on generation speed is memory bandwidth (GB/s), not compute power. This also explains why, when consumer-grade GPUs run large models, the bottleneck often appears in bandwidth rather than FLOPS. Techniques such as speculative decoding emerged precisely to bypass this bottleneck.

KV Cache is key to understanding the Decoding bottleneck. During autoregressive generation, each time a new token is generated, the attention mechanism needs to compute against the Key and Value vectors of all previous tokens. Without caching, the K/V of the entire prefix would need to be recalculated at every step, with complexity growing quadratically. KV Cache keeps these intermediate results resident in VRAM, so each step only needs to compute and append the K/V of the new token, reducing complexity to linear. But the cost is that VRAM usage expands linearly with context length and concurrency—for a 70B model under long context, the KV Cache itself may consume tens of GB of VRAM. This is precisely the core contradiction that vLLM's PagedAttention aims to solve: the VRAM management efficiency of KV Cache directly determines how many concurrent requests a single GPU can handle.

vLLM: Built for high-concurrency production environments

vLLM originates from UC Berkeley research on PagedAttention (Kwon et al.), with the core goal of solving the severe VRAM waste problem in traditional inference services.

The key innovation of PagedAttention

Traditional serving systems reserve contiguous VRAM blocks for each request's KV Cache and allocate them according to the maximum possible context length. Since the vast majority of requests are far shorter than the upper limit, 60% to 80% of VRAM is wasted through fragmentation.

PagedAttention draws on the idea of virtual memory paging in operating systems, dividing the KV Cache into fixed-size physical blocks (pages). Key and Value tensors are dynamically written to non-contiguous memory locations, reducing VRAM waste to below 4%. This directly enables larger batch sizes and near-full VRAM utilization.

Combined with Continuous Batching, vLLM can achieve throughput of 1850+ tok/s under 32 concurrent users. This is the only engine among the three designed for multi-tenant API serving. Its shortcomings are also clear: the PagedAttention kernel is deeply tied to NVIDIA CUDA and AMD ROCm, with only experimental support on Apple Silicon.

The difference between Continuous Batching and traditional static batching deserves elaboration. Static batching requires all requests in a batch to start and finish at the same time; short requests must wait for long requests to complete before resources are released, leaving the GPU largely idle at the tail of the batch. Continuous Batching reschedules after each iteration (each generated token): completed requests exit immediately and release their slots, while newly arrived requests can join in the same step. This keeps the GPU at a high utilization rate at all times. It is the architectural reason why vLLM's throughput far exceeds the other two under high concurrency, and it also explains why its throughput grows approximately linearly with concurrency, whereas Ollama's sequential request queue and llama.cpp's slot-based batching quickly hit their ceilings.

llama.cpp: Squeezing every last drop of hardware performance

Created by Georgi Gerganov and maintained by the open-source community, llama.cpp is the benchmark for low-level hardware utilization. Written in pure C/C++ with zero external runtime dependencies, it can run on x86 AVX-512, ARM NEON, Apple Silicon Metal, and NVIDIA CUDA.

GGUF and K-Quantization

llama.cpp pioneered the GGUF file standard, packaging model weights, tokenizer vocabulary, and quantization scaling coefficients into a single binary file. Its K-quants series (Q4_K_M, Q5_K_M) uses mixed-precision matrix compression, enabling a 70B-parameter model to run within 42GB with negligible degradation in reasoning capability.

In single-user scenarios, llama.cpp's raw speed is actually the fastest of the three—an 8B model reaches about 115 tok/s on an RTX 4090 with first-token latency of about 12ms, thanks to native Metal/AVX paths. The tradeoff is limited concurrency: at 32 concurrent requests, throughput is only about 210 tok/s.

Quantization is the technique of compressing model weights from higher bit widths such as FP16 to lower bit widths such as 4-bit or 5-bit, directly determining whether a model can fit into limited VRAM. The cleverness of K-quants lies in mixed precision: sensitive matrices such as attention output layers retain higher bit width, while less influential layers are aggressively compressed, and scaling coefficients are stored per block to preserve dynamic range. The M in Q4_K_M stands for medium, a balanced tier in the 4-bit mixed scheme. llama.cpp also supports offloading some layers to the CPU at runtime (--n-gpu-layers), allowing inference via system memory when VRAM is insufficient, albeit with a sharp drop in speed—which is also why it thrives on Mac unified memory architecture.

Ollama: A wrapper layer that prioritizes developer experience

Ollama builds a Go abstraction layer on top of llama.cpp, turning "running local models" into an experience similar to Docker.

  • Single-command startup: ollama run llama3.3:70b automatically downloads optimized GGUF weights, allocates GPU VRAM layers, and opens an interactive terminal.
  • Declarative Modelfile configuration: system prompts, temperature, and stop tokens can all be defined like a Dockerfile.
  • Local REST API (port 11434): provides an OpenAI-compatible /v1/chat/completions endpoint that can directly connect to MCP servers and local multi-agent frameworks such as LangGraph, CrewAI, and AutoGen.

In terms of performance, the gap between Ollama and bare llama.cpp is between 3% and 5%, because it essentially compiles llama.cpp as the underlying execution binary. An 8B model runs at about 105 tok/s with first-token latency of 22ms; the extra latency comes from the HTTP daemon.

Performance and feature comparison

DimensionvLLMOllamallama.cpp
Single-user 8B speed~95 tok/s~105 tok/s115 tok/s
32-concurrency throughput1850+ tok/s~195 tok/s~210 tok/s
First-token latency18ms22ms12ms
VRAM efficiency96%85%88%
Core languagePython + C++/CUDAGo (wraps llama.cpp)Pure C/C++
Native model formatsSafeTensors, AWQ, GPTQ, FP8GGUFFull GGUF K-Quants series
Concurrency architectureContinuous iterative batchingSequential request queueSlot-based serving batching
Apple MetalExperimental/limitedFull accelerationMetal performance benchmark
Target scenarioCloud GPU clusters and APIsLocal IDE coding assistantEdge devices and Mac workstations

How to configure hardware: from a single GPU to a cluster

Single developer (RTX 4090, 24GB VRAM): Choose Ollama or llama.cpp. An 8B model at FP16 without quantization can reach 95+ tok/s, and a 32B model with Q4_K_M quantization can fit into 20GB of VRAM.

Multi-GPU workstation: When using dual GPUs for tensor parallelism, you need to confirm the motherboard's PCIe lane bifurcation strategy. The actual inference difference between PCIe 4.0 x8/x8 and x16/x16 is worth verifying in advance.

Apple Mac Studio (128GB unified memory): Choose llama.cpp or Ollama. 70B-parameter models (Llama 3.3 70B, Qwen 2.5 72B) with Q4_K_M quantization can run fully in unified memory at 22+ tok/s.

Enterprise production API cluster (multiple A100/H100 80GB GPUs): Deploy vLLM with tensor parallelism enabled (TP=2 or TP=4). Before going live, it is recommended to compare GPU costs across platforms such as RunPod, Modal, and AWS. Among them, RunPod suits teams that need stable GPU capacity without turning infrastructure management into a second full-time job, Modal has an advantage in elastic serverless on-demand scaling, while large-scale production systems usually still require AWS EC2/EKS due to SOC2 compliance and VPC isolation requirements.

Build a private coding assistant

Routing code generation to a local Ollama instance saves on SaaS subscriptions and prevents proprietary codebases from leaking. It takes three steps:

  1. Run ollama run qwen2.5-coder:7b in the terminal to pull the coding model;
  2. Install the open-source Continue extension in VS Code, JetBrains, or Cursor;
  3. In config.json, set the provider to ollama and the model to qwen2.5-coder:7b.

FAQ

Is Ollama slower than bare llama.cpp? The gap is minimal. Since Ollama uses llama.cpp as its underlying execution binary, the raw token generation speed difference is within 3% to 5%.

Can vLLM run on a Mac? Experimental CPU and Metal backends exist, but its PagedAttention kernel is essentially optimized for NVIDIA CUDA and AMD ROCm. On Apple Silicon, llama.cpp and Ollama remain clearly better choices.

Final selection recommendations

The three engines are not substitutes for one another; each occupies a different operational tier: individual developers use Ollama for a zero-maintenance private coding assistant; Mac or edge device users use llama.cpp to squeeze every drop of unified memory bandwidth; enterprise engineering teams use vLLM on Kubernetes or cloud clusters to serve production APIs, relying on PagedAttention for unmatched concurrent throughput. Figure out your deployment scenario first, and the choice becomes almost uniquely determined.

#vLLM#Ollama#llama.cpp#LLM inference engine#PagedAttention#GGUF quantization#GPU deployment
Share:

Related articles