Local AI

llama.cpp Is More Than a GGUF Runner: A Local Inference Stack Emerges

Why llama.cpp is evolving from a GGUF model runner into a broader local inference stack spanning servers, scheduling, KV caches, and speculative decoding.

Approximately 11 min read

For a long time, the easiest way to describe llama.cpp was simple:

It runs quantized LLMs locally.

That description is becoming incomplete.

llama.cpp still does the thing that made it famous: load compact GGUF models and run them efficiently on consumer hardware. But look at what now surrounds that core.

There is an OpenAI-compatible inference server. There are Anthropic-compatible message routes, continuous batching, multimodal inference, tool calling, structured outputs, speculative decoding, model routing, multiple GPU split strategies, quantized KV caches, CPU/GPU hybrid execution, direct Hugging Face model loading, and backends spanning CUDA, Metal, Vulkan, HIP, SYCL, WebGPU and more.

And in 2026, the project began formalizing semantic releases around v0.1.0.

The more interesting story is therefore not:

llama.cpp finally has a version number.

It is:

llama.cpp is starting to look less like a model runner and more like a local inference platform.

That distinction matters because local AI is no longer primarily a file-loading problem.

It is becoming a systems problem.

The old mental model: GGUF plus a fast runtime

The original llama.cpp value proposition was unusually clear.

Take a large language model, convert or quantize it into a compact representation, and make it practical to run on hardware that was never designed as an AI server.

That created the ecosystem many local-AI users recognize today:

Hugging Face model
        ↓
      GGUF
        ↓
Q4 / Q5 / Q6 / IQ quantization
        ↓
    llama.cpp
        ↓
CPU / GPU / Apple Silicon

The important innovations were model portability, quantization, and highly optimized inference on commodity hardware.

That is still foundational.

But llama.cpp’s current README describes its goal more broadly: LLM and VLM inference with minimal setup and high performance across a wide range of hardware, locally and in the cloud.

Its supported backend list now includes CUDA, HIP, Metal, Vulkan, SYCL, OpenCL, WebGPU, RPC and several architecture-specific paths.

That is already more infrastructure than the phrase “GGUF loader” suggests.

The first platform layer is hardware abstraction

One of llama.cpp’s biggest advantages is not that it has the fastest implementation for every GPU.

It is that the same inference stack can target an unusually wide range of machines.

A single project covers configurations such as:

x86 CPU
Apple Silicon
NVIDIA CUDA
AMD HIP
generic Vulkan GPU
Intel SYCL
CPU + GPU hybrid
multi-GPU
remote RPC devices

For local AI, that matters enormously.

Datacenter inference frameworks can reasonably assume something close to:

Linux
+
NVIDIA GPU
+
large VRAM
+
CUDA

A local inference runtime cannot.

It has to survive:

8 GB laptop GPU

24 GB gaming GPU

MacBook unified memory

older AMD card

CPU-only mini PC

two mismatched GPUs

model larger than VRAM

llama.cpp has increasingly turned those differences into runtime configuration rather than separate software ecosystems.

Its server exposes device selection, automatic GPU-layer fitting, layer/row/tensor multi-GPU splitting, tensor placement overrides and controls for moving Mixture-of-Experts weights onto CPU memory.

That starts to resemble an inference scheduler.

Model loading is becoming model management

The old workflow looked roughly like:

llama-cli -m model.gguf

That still works.

But the official quick start now looks more like this:

llama cli -hf ggml-org/Qwen3.5-0.8B-GGUF

and:

llama serve -hf ggml-org/Qwen3.5-0.8B-GGUF

The runtime can resolve and download a model directly from Hugging Face, select a quantization, automatically fetch multimodal projection files when available, cache the model and expose it through a server.

That might sound like a convenience feature.

It is actually an architectural shift.

There is a large difference between:

runtime accepts a model file

and:

runtime knows how to discover,
download,
cache,
configure,
load,
unload
and serve models

The second is platform behavior.

Recent llama-server work goes even further with router mode and per-model configuration. Instead of launching one manually configured process per GGUF, a server can manage multiple model definitions, inherited configuration and model-specific settings.

That is not simply inference anymore.

It is model lifecycle management.

The server is no longer an accessory

One of the clearest signs of llama.cpp’s evolution is llama-server.

The official server documentation now describes a fairly complete inference service.

It includes OpenAI-compatible chat, responses and embedding routes, Anthropic-compatible messages, reranking, parallel decoding, continuous batching, multimodal requests, monitoring endpoints, JSON-schema-constrained output, tool calling, speculative decoding and a built-in web UI.

That changes the architectural role of llama.cpp.

A few years ago the likely stack was:

application
    ↓
Python wrapper
    ↓
llama.cpp
    ↓
GGUF

Increasingly it can be:

application
        ↓
OpenAI-compatible API
        ↓
llama-server
        ↓
scheduler / cache / decoding engine
        ↓
GGML backend
        ↓
CPU / CUDA / Metal / Vulkan / ...

That second diagram looks much closer to a modern inference framework conceptually, even though llama.cpp’s target hardware and design priorities remain very different from datacenter-first systems.

KV cache is becoming a first-class runtime resource

A mature inference engine cannot think only about model weights.

For long-context and concurrent workloads, the KV cache can become one of the most important consumers of memory.

llama.cpp exposes independent cache types for K and V.

Current server options include formats such as:

F32
F16
BF16
Q8_0
Q5
Q4
IQ4

That is important because model quantization and KV-cache quantization solve different problems.

You can have:

Q4 model weights
+
F16 KV cache

or:

Q4 model weights
+
Q8 KV

or:

Q4 model weights
+
Q4 KV

depending on how much context, memory and quality you need.

And the work is still moving.

A current llama.cpp PR proposes adding q3_K as a CUDA KV-cache format specifically to squeeze more context into limited VRAM. The proposal reports a roughly 24% smaller cache than q4_0 and roughly 78% smaller than f16 under its stated format assumptions, together with preliminary quality and throughput measurements on Qwen3 27B.

Those figures are contributor-reported and the PR is not the same thing as a shipped default.

The more important point is architectural:

KV memory is now being optimized as a subsystem, not treated as incidental storage.

That is inference-engine engineering.

Hybrid execution is becoming more sophisticated than “offload some layers”

One of llama.cpp’s defining capabilities has always been the ability to run a model that does not completely fit in VRAM.

The simplest form is layer offloading:

GPU:
some transformer layers

CPU RAM:
remaining layers

But modern model architectures make the problem more complicated.

Mixture-of-Experts models introduce another possibility:

attention / dense components
        → GPU

some or all expert weights
        → CPU

The server now has explicit controls for CPU MoE placement and partial expert offload.

That becomes increasingly important as local users attempt models whose total parameter count is enormous but whose active parameter count per token is much smaller.

The inference engine therefore has to reason about more than:

Does the model fit?

It increasingly has to reason about:

Which tensors should live where?

That is another platform characteristic.

Speculative decoding is becoming its own subsystem

Perhaps the strongest evidence comes from speculative decoding.

Originally, speculative decoding was conceptually simple:

small draft model
        ↓
guess several tokens
        ↓
large target model verifies them together

llama.cpp now has work spanning several increasingly specialized approaches.

MTP — Multi-Token Prediction — can use auxiliary prediction heads embedded in or distributed with a model rather than requiring an unrelated small draft model.

The llama.cpp MTP implementation has been tested with newer Qwen-family models, multimodal inputs and multi-GPU execution. In the development results attached to the MTP work, Qwen3.6-27B showed large speedups when draft acceptance was high, but the exact gain changed significantly with workload, sampling and hardware.

That variability matters.

MTP is not a universal multiplier.

Then there is EAGLE3.

Then DFlash.

Then DSpark.

Now DFlash2 is being proposed.

At this point “speculative decoding” is no longer one checkbox.

It is becoming a framework.

DFlash shows where this is heading

DFlash is interesting because it changes the economics of drafting.

Traditional autoregressive draft models still generate proposed tokens sequentially.

DFlash attempts to produce a block of candidate tokens in a more parallel way.

That gives the target model more work to verify at once and can reduce the number of expensive serial decoding steps.

But performance varies dramatically by model and workload.

The llama.cpp DFlash development results illustrate exactly why inference optimization is difficult: some workloads show very large gains, while certain MoE configurations show much smaller gains or even regressions.

The correct abstraction therefore is not:

speculative decoding = faster

It is:

draft architecture
+
acceptance rate
+
target architecture
+
batch behavior
+
backend kernels
+
memory cost
=
actual speedup

That is the kind of equation inference frameworks have to manage.

DFlash2 makes the trend even clearer

As of this writing, DFlash2 support is not yet merged into llama.cpp.

PR #27342 remains open.

That distinction matters.

But the proposed implementation is a useful signal of where the runtime is going.

DFlash2 adds a grouped dynamic depthwise-convolution component and a candidate selector on top of the earlier DFlash approach.

The contributor reports a small test using Qwen3.8-27B Q4_K_M on an Apple M5 Pro. Autoregressive decode measured 10.42 tokens/s in that test, while several DFlash2 configurations were reported around 18.4–19.3 tokens/s, or roughly 1.77–1.85× faster.

This is not a general benchmark.

Eight GSM8K problems are nowhere near enough to establish universal performance.

And the code is still an open PR.

But notice what the work is modifying:

draft distributions
sampling
candidate selection
verification
model metadata
speculative state
runtime scheduling

That is no longer merely implementing a transformer forward pass.

It is building a decoding engine.

Modern model architectures are forcing llama.cpp to evolve

The models themselves are also becoming harder to run.

The classic transformer runtime assumed something close to:

attention
+
MLP
+
repeat

Modern open models increasingly include combinations of:

MoE

sliding-window attention

linear/recurrent layers

compressed attention

multimodal projectors

MTP heads

speculator models

hybrid recurrent + attention state

Speculative decoding makes this especially difficult.

With a pure-attention model, rejected speculative tokens can often be removed from a position-addressable KV cache.

A hybrid recurrent model may contain state that cannot simply be handled as “delete tokens 120–124.”

llama.cpp has therefore needed checkpointing and rollback mechanisms for speculative inference on hybrid architectures.

That is a subtle but important transition.

A model loader asks:

Can I deserialize these tensors?

An inference platform asks:

Can I preserve the semantics of this architecture while batching, speculating, rolling back, offloading and quantizing its runtime state?

Those are very different engineering problems.

v0.1.0 matters — but not because llama.cpp is suddenly stable

The new semantic-versioning process is easy to overinterpret.

v0.1.0 does not mean:

llama.cpp is now stable 1.0 software

It is still a 0.x release.

The project’s own release documentation also shows that the release-management system is still being formalized.

But the new process is meaningful.

llama.cpp now explicitly defines:

breaking public C API change
→ MAJOR

backward-compatible feature/model/API
→ MINOR

bug fix without API change
→ PATCH

It has a manual release workflow, annotated semantic-version tags, release builds without the -dev suffix, and documented distribution paths.

That matters because once external applications depend on your API, CLI and model behavior, release contracts become infrastructure.

The version number is therefore best treated as a marker of project maturation, not proof that the runtime has reached a frozen or compatibility-stable state.

llama.cpp is not becoming vLLM

This distinction is important.

Calling llama.cpp an inference platform does not mean it has become a drop-in replacement for every other inference engine.

vLLM and SGLang are heavily oriented toward datacenter GPU serving:

high concurrency
large NVIDIA deployments
throughput
continuous scheduling
distributed serving

llama.cpp’s center of gravity remains different:

heterogeneous hardware
local machines
edge devices
consumer GPUs
Apple Silicon
CPU execution
partial offload
extreme quantization
portable deployment

There is overlap.

That overlap is growing.

But the design priorities are not identical.

A 16-GPU datacenter inference service and a Mac mini running a local coding model do not optimize the same constraints.

The interesting development is that llama.cpp increasingly offers platform-level features while preserving its heterogeneous-hardware identity.

That distinction is especially visible when comparing llama.cpp with a patched high-performance vLLM setup on a single RTX 4090: both are inference stacks, but they start from very different hardware assumptions and operational goals.

It is also not the same layer as Ollama or LM Studio

Another useful distinction is between an inference platform and an end-user product.

Tools such as Ollama and LM Studio focus heavily on model UX:

download model
start model
chat
manage library
expose endpoint

llama.cpp increasingly implements some of those conveniences itself, including direct model retrieval, a server and a web interface.

But its most important role remains lower in the stack.

It owns things such as:

tensor representation
quantized kernels
backend scheduling
KV cache
GPU offload
speculative decoding
architecture implementation

That gives higher-level products something to build on.

A useful analogy is not:

llama.cpp is becoming another desktop model manager.

It is closer to:

llama.cpp is becoming the runtime layer on which many local-AI experiences can be built.

What would make llama.cpp a mature inference platform?

There is still a lot of distance between “platform is forming” and “platform is mature.”

The biggest test may actually be stability rather than another 15% kernel optimization.

External developers need predictable APIs.

CLI options need manageable deprecation policies.

Model architectures need regression testing.

Speculative-decoding methods need common abstractions instead of accumulating special-case paths.

Backend behavior needs to remain consistent across CUDA, Metal, Vulkan and CPU.

Router mode needs operational maturity.

Versioned releases need useful compatibility expectations.

And new techniques such as DFlash2 need to survive real-world evaluation before becoming default assumptions.

That is why v0.1.0 is interesting.

Not because the work is finished.

Because release management becomes much more important once other software begins to treat your runtime as infrastructure.

Unusual weight formats and sparse structures make these runtime choices more consequential. The 1-bit and ternary model overview follows that pressure from the model side.

Sources and further reading

Continue reading