localaiforum
Log in
Guide › Running & serving

Inference engines compared

The engine is the program that turns weights into tokens: it loads the file, runs the transformer forward pass, and usually speaks HTTP on top. The good news is that almost every engine runs the same model at roughly the same speed on the same hardware — engine choice is about workflow, format support, and concurrency, not raw tok/s. The bad news is the same: benchmark-shopping between them is mostly wasted effort.

The field

Engine What it is Formats Hardware reach Built for
llama.cpp C/C++ inference core with a built-in server GGUF CPU, CUDA, ROCm, Metal, Vulkan — the broadest reach The foundation; runs nearly everywhere
Ollama llama.cpp wrapped with a model library, CLI, and REST GGUF Whatever llama.cpp does Zero-friction desktop use
LM Studio Polished GUI plus an OpenAI-compatible server GGUF (and MLX on Mac) Windows/macOS/Linux GUI People who want buttons, not flags
vLLM Python serving engine: paged attention, continuous batching safetensors CUDA (plus some ROCm/TPU support) Datacenter-grade concurrent serving
SGLang Serving engine with RadixAttention prefix caching safetensors CUDA Fast structured output; agents sharing prefixes
exllamav2 GPU-only loader tuned for decode speed EXL2, GPTQ CUDA only Maximum single-user tok/s on one consumer NVIDIA GPU
MLX Apple's array framework; mlx-lm runs models on it MLX Apple silicon The fast practical route on recent Macs
transformers (HF) The reference implementation everything is ported from safetensors CPU, CUDA Correctness checks, experiments, training plumbing

One lineage note: Ollama and LM Studio both run llama.cpp under the hood. Comparing them to llama.cpp is comparing packaging, not inference.

Also worth knowing: llama.cpp ships more than a server — quantization and conversion tools, a benchmark harness, and bindings for a dozen languages.

Deep cuts

vLLM was born from the paged-attention insight (see concurrency): treat GPU memory like an OS treats RAM, and far more requests fit. It is the default answer to "I have a GPU server and real traffic."

SGLang caches prefixes across requests (RadixAttention): if 40 agents share the same two-page system prompt, the prompt is processed once, not 40 times. It is also known for fast constrained decoding — see structured output.

exllamav2 is the sharp edge for exactly one niche: a single user on a single NVIDIA GPU who wants the most tok/s per bit of quantization. The server story and hardware breadth are thin; the niche is real.

MLX is Apple's ML framework, built for unified memory. As of this writing mlx-lm often beats llama.cpp's Metal path on larger models — close enough that on a Mac it is worth trying both (more in Apple silicon).

transformers is the slow, faithful reference: when a quantized engine does something odd, running the same model through it answers "is this the engine or the model?" It is also the plumbing under fine-tuning tooling (see fine-tuning).

Choose by need

You are... Start with
Chatting at your own desk Ollama or LM Studio
Scripting from the shell (pipes, cron, small tools) Ollama's REST API, or llama-server
Building an app backend with light traffic llama-server — one process, zero ops
Serving many concurrent users vLLM or SGLang
Running agent fleets that share long system prompts SGLang or vLLM; see agents
An all-Mac household Ollama/LM Studio first; MLX if you want more speed

Two notes on the table:

  • "Start with" is not "settle for" — every desktop engine reads the same GGUF, so trying a second one costs five minutes, not a migration.
  • When you do compare, hold everything constant: same model, same quant, same prompt, model already warm.

The format split mirrors the desktop/server split

GGUF versus safetensors (see model formats) is not just a container preference — it decides your engine. GGUF is the single-file, pre-quantized, runs-anywhere format, and the entire desktop ecosystem (llama.cpp, Ollama, LM Studio) is built on it. safetensors is the sharded-tensor format of the Hugging Face ecosystem; the high-throughput server engines (vLLM, SGLang, transformers) consume it, usually quantized on the fly (AWQ/GPTQ variants) rather than pre-packed.

So the real decision tree is short: desktop and single-user → GGUF engines; server and concurrent → safetensors engines. Everything else is detail.

When something "cannot run," check the format first — half of "engine X cannot run model Y" is a GGUF/safetensors mismatch, not a capability gap.

Overhead is not the story

On identical hardware with an identical quant, engines land within roughly 10–20% of each other for single-stream decode — often because they share a backend. What actually moves your experienced speed by multiples, not percent:

  • Whether the model is already loaded — a cold load costs seconds to a minute.
  • Whether the whole conversation is resent every turn — context cost, see tokens.
  • Whether requests queue behind each other — see concurrency.
  • Whether layers sit on the GPU — see engine knobs.
Same GPU, same 8B Q4_K_M, single stream (illustrative, not specs):
llama.cpp / Ollama / LM Studio    ~130–145 tok/s   (same engine underneath)
exllamav2 EXL2 ~4bpw              ~160–180 tok/s   (loader tuned for decode)

Same GPU, 8 concurrent chat streams:
llama-server serial queue         each stream waits; total throughput flat
vLLM                              all streams near single-stream speed

Pick the engine that matches your workflow, then spend your energy on I/O patterns instead of engine benchmarks.

One file, many engines

A GGUF you downloaded for Ollama also runs in llama.cpp directly and in LM Studio — engines do not convert or re-download; you point them at the same file (Ollama can import a local path with a one-line Modelfile). The same holds server-side for safetensors between vLLM and SGLang. Practical consequence: there is no file-level vendor lock, and being wrong about an engine costs you minutes.

That is why this page keeps pushing workflow over benchmarks: when your needs change, the models you already downloaded move with you.

When to graduate from Ollama

Ollama's defaults are excellent until they are not. Move to a serving engine when:

  • You need sustained concurrency beyond a handful of streams (see concurrency).
  • You want prefix caching across many agents sharing a system prompt (SGLang).
  • You must serve AWQ/GPTQ safetensors quants directly from the HF ecosystem.
  • You are load-testing a product feature before shipping it.
  • You need multi-GPU tensor parallelism to fit one big model across cards.

Until one of those is true, the convenience is worth more than the throughput.

Related: Model formats · Engine knobs · Serving an endpoint · Choosing a model