Handbooks  /  Local LLM Stack
Handbook~15 min readInferenceworked math + runnable code
The Local LLM Stack Handbook

Run the model
on your machine.

You can run a capable LLM on your own laptop — no API key, no per-token bill, no data leaving the building. Tools like ollama and llama.cpp make it a one-line command. But whether a given model actually runs on your hardware isn't magic; it's one small equation about memory. Master that formula and you can look at any model — "7B," "70B," "4-bit" — and know instantly whether it'll fit your GPU, and what quantization it'll take to get there. This handbook is that equation and the stack around it.

01

Local means memory

Running an LLM locally is appealing for concrete reasons: privacy (your data never leaves the machine), no per-token cost, offline operation, and full control over the model and its version. The tooling has gotten easy — with ollama you pull and run a model in one command. So the question is rarely "how do I run it?" but "can I run it — will it fit?"

And "fit" is almost entirely about memory. The model's weights have to live in your GPU's VRAM (fast) or your system RAM (slower, CPU inference), alongside the KV cache and some overhead. Compute matters for speed, but memory is the hard wall: if the weights don't fit, the model simply won't load. The good news is that memory is trivially predictable — there's a single formula, and once you know it, hardware planning for local LLMs becomes arithmetic you can do in your head.

The one-sentence version

Whether a model runs locally is set by memory: weight memory = parameters × bits per weight ÷ 8, so quantizing to 4-bit shrinks a 7B model from 14GB to 3.5GB and it fits a consumer GPU.

02

The fit equation

Every weight in a model is a number stored in some number of bits. So the memory for the weights is just: how many weights, times how many bits each, converted to bytes. That's the whole equation — memory = params × bits / 8 — and it tells you nearly everything about what fits.

Work an example. A 7-billion-parameter model at 16-bit (half precision, the usual training format) is 7×10⁹ × 16 / 8 = 14 GB just for weights. That won't fit an 8GB consumer GPU. The same model at 4-bit is 7×10⁹ × 4 / 8 = 3.5 GB — comfortable, with room for the KV cache. A 70B model at 4-bit is 35GB, needing a big GPU or CPU offload. Nothing here is mysterious: read off the parameter count and the bit-width, multiply, divide by eight, and you know. The lever that turns "doesn't fit" into "fits" is the bit-width — which is quantization.

03

Quantization fits it

Quantization stores each weight in fewer bits. A model trained in 16-bit can be compressed to 8-bit, 4-bit, or even lower, and because memory scales linearly with bit-width, dropping from 16 to 4 bits cuts the footprint to a quarter. That's the difference between a model that won't load and one that runs smoothly on a laptop GPU.

Same 7B model, different quantization
fp1616 bits/weight → 14 GB — needs a 16GB+ GPU.
int88 bits/weight → 7 GB — fits many GPUs, near-lossless.
4-bit4 bits/weight → 3.5 GB — fits consumer GPUs; the popular sweet spot.
Trade-offFewer bits = smaller + faster, at a small and usually acceptable quality cost.

There's a quality cost — cruder weights lose a little precision — but modern 4-bit schemes (like the QLoRA-era NF4 and the GGUF K-quants) are remarkably good, and 4-bit is the default for local inference because the trade is usually excellent. Lower still (3-bit, 2-bit) exists for squeezing the largest models onto limited hardware, with steeper quality loss. The practical workflow: pick the largest model whose 4-bit size fits your memory, and step up the bit-width only if you have room to spare and want the last bit of quality.

04

The memory math

The weight-memory formula, with parameters P and bits per weight b:

memoryweights  =  P · b / 8  bytes   ⟹   7B at 4-bit = 7×10⁹ · 4 / 8 = 3.5 GB

Linear in both size and bit-width. Halve the bits, halve the memory; double the parameters, double the memory.

To decide if a model fits, compare weight memory (times an overhead factor for the KV cache, activations, and runtime) against your available VRAM:

fits  ⟺  ( P · b / 8 ) · overhead  ≤  VRAM   (overhead ≈ 1.2 for a rough estimate)

7B 4-bit ≈ 3.5GB × 1.2 = 4.2GB fits an 8GB GPU; 7B fp16 ≈ 16.8GB doesn't. The runnable version below computes model memory, checks the fit, and shows quantization's savings.

RUN IT YOURSELF

Will it fit?

Local LLM planning is one multiplication. Weight memory in GB is parameters (in billions) times bits per weight over 8 — so a 7B model is 14GB at fp16 and 3.5GB at 4-bit. Quantization scales memory linearly, so 4-bit is a quarter of fp16, and that's what turns a model that won't load into one that fits an 8GB GPU (with a bit of overhead for the KV cache). A bigger model needs proportionally more. Change the parameter count, bit-width, or VRAM and see what runs on your machine.

CPython · WebAssembly
05

The stack

The local ecosystem is a few layers, from raw engine to friendly app:

LayerWhat it is
llama.cppThe optimized C/C++ inference engine — runs quantized models on CPU/GPU; defines the GGUF format.
GGUF + quantsThe model file format with many quantization levels (Q4_K_M, Q5, Q8…) — pick the one that fits.
OllamaA convenience layer: pulls models, sets defaults, exposes a CLI and local API in one command.
RuntimesOthers too — MLX (Apple silicon), vLLM (server-grade), LM Studio (GUI) — same memory rules.
Your appTalks to the local API just like a hosted one — swap the base URL, keep the code.

The practical path: use ollama to run a model with one command when you want convenience; drop to llama.cpp (or vLLM for serving) when you want control over quantization, context length, or throughput. On Apple silicon, unified memory means the "VRAM" is your system RAM, so the same formula applies to a larger pool. Whatever the runtime, the memory equation is identical — it's a property of the model and the bit-width, not the tool. And because local runtimes expose an OpenAI-compatible API, pointing an app at a local model is often just changing the base URL, which pairs neatly with routing cheap/private traffic to a local model and hard queries to a hosted one.

06

Pitfalls

The first surprise is forgetting the KV cache and context: the weight formula gives the floor, but a long context grows the KV cache, which also lives in memory — a model that fits at 2K context can OOM at 32K. Budget headroom (the overhead factor), and remember longer context costs more memory, not just more compute. The second is over-quantizing: 2-bit or aggressive 3-bit can degrade quality sharply, so don't chase the smallest file — 4-bit (Q4_K_M-class) is usually the floor for good quality, and if it doesn't fit, prefer a smaller model at 4-bit over a bigger model at 2-bit.

Two more. CPU-only is slow: it works (llama.cpp runs on CPU), but tokens-per-second drops a lot without a GPU — fine for light use, painful for heavy. And expecting frontier quality: a 7B–14B local model is genuinely useful, but it won't match the largest hosted models on the hardest tasks, so match the model to the job (local for privacy, cost, and offline; hosted for peak capability). The whole discipline reduces to the one equation: know a model's size and bit-width, compute the memory, compare to your hardware, and you'll never be surprised by a model that won't load again.

Worth knowing

The weight formula is the floor, not the total. Context length grows the KV cache in the same memory, so a model that loads at 2K context can run out at 32K. Leave headroom, and treat a smaller model at 4-bit as better than a bigger model at 2-bit.

Frequently asked

Quick answers

What do you need to run an LLM locally?

Mainly enough memory: the weights must fit in VRAM or RAM. Weight memory = params × bits per weight ÷ 8, plus KV cache and overhead.

How does quantization help?

Fewer bits per weight shrinks memory linearly — a 7B model is 14GB at 16-bit but 3.5GB at 4-bit, which fits a consumer GPU.

Ollama vs llama.cpp?

llama.cpp is the low-level engine (and GGUF format); ollama is a convenience layer that manages models and exposes a simple API.

Why run locally?

Privacy, no per-token cost, offline use, and control — at the cost of being limited to models that fit your hardware.

Finished this one? 0 / 99 Handbooks done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.