pip, the huggingface_hub package, llama.cpp (prebuilt release or built from source), free disk space equal to the model file plus headroom, a Hugging Face account (free)The guide uses placeholders like <org>/<model>-GGUF for repository IDs and file names. Repository IDs and file names change weekly, so copy the real values from the model page you open — never from this text.

What to do: prepare the machine before touching any model.
llama.cpp binaries or WSL2 (Windows Subsystem for Linux — a real Linux kernel running inside Windows).pip. Check the version your tooling supports in the documentation; this guide states no version number on purpose..gguf file you plan to download (the file itself plus cache). Check with df -h.Why: every failure later in this guide — 401 errors, out-of-memory kills, truncated downloads — is cheaper to prevent here than to debug at step 3.
How to check:
python3 --version
pip --version
df -h .
which git && which curl
Expected: three version lines and paths to git and curl. Any "command not found" means install that package first.
Then create an isolated environment and install the client:
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -U huggingface_hub
huggingface-cli --help
Example: on a fresh Ubuntu box the last command prints a usage block starting with usage: huggingface-cli <command> [<args>]. On newer releases of the library the binary is renamed to hf; if huggingface-cli is not found, run hf --help and use hf download wherever this guide says huggingface-cli download — check the documentation for your installed version.
python3 --version returns a linehuggingface-cli --help (or hf --help) prints usagedf -h . shows free space greater than 2× your target fileIf you have never run a model on your own hardware before, start with the beginner walkthrough How to run AI models locally on your PC: a beginner's guide and come back here for the download and quantization details.
What to do: locate a repository that ships a .gguf file and pick one quantization level.
Why: a Hugging Face repository is a folder, not a single file. Most repositories hold the original weights (.safetensors) divided into many shards; those are for training and for GPU servers, not for a laptop. GGUF is a single-file format designed for local inference: the weights, the tokenizer and the metadata live in one file that llama.cpp can memory-map. Quantization is the process of storing each weight in fewer bits, which shrinks the file at some cost in answer quality.
Open https://huggingface.co/models and set:
1. Task → Text Generation.
2. Search field → GGUF.
3. Sort → Most downloads.
4. Size filter → your parameter range (a 7B model is roughly a quarter of the memory of a 30B model; bigger means slower and hungrier).
Then open a repository and switch to the Files and versions tab. You will see a list of .gguf files with their sizes in GB.
| File suffix | Bits per weight | What you get |
|---|---|---|
| `Q2_K` | ~2 | Smallest file, most visible quality loss |
| `Q3_K_M` | ~3 | Small; degradation shows up on reasoning tasks |
| `Q4_K_M` | ~4 | Frequently used middle ground |
| `Q5_K_M` | ~5 | Closer to the original, larger |
| `Q6_K` | ~6 | Near-original |
| `Q8_0` | 8 | Almost lossless, large |
| `F16` | 16 | Unquantized reference |
K marks the k-quant family; S, M and L are small/medium/large mixes inside that family — M is the usual pick. Choose the largest quant that fits in your memory.
Example: you open a repository, see model-Q4_K_M.gguf at a given size in the file list, and your machine has more free RAM than that number. That file is your candidate; note the exact name, you will pass it to --include in step 2.
How to check: the Files and versions tab lists at least one file ending in .gguf, and the repository is not marked "gated" (a lock icon next to the name). Gated repositories require you to accept the license on the model page with your account logged in.

What to do: authenticate, download only the file you need, then serve it.
Why: downloading one .gguf instead of the whole repository saves tens of gigabytes and avoids pulling the .safetensors shards you will never load. Serving the model over HTTP gives you an OpenAI-compatible endpoint, so existing client code works unchanged.
Authenticate once:
huggingface-cli login
Paste the token from step 0 when prompted. The token is stored locally; subsequent downloads use it automatically. This is what makes gated repositories work.
Download a single file:
huggingface-cli download <org>/<model>-GGUF \
--include "*Q4_K_M.gguf" \
--local-dir ./models
--include is a glob filter — only matching files are fetched. --local-dir puts them in a plain folder instead of the shared cache, which makes the next command shorter.
If the CLI fails, the same file is reachable over plain HTTP using the repository URL pattern:
curl -L -H "Authorization: Bearer $HF_TOKEN" \
-o ./models/<model>-Q4_K_M.gguf \
"https://huggingface.co/<org>/<model>-GGUF/resolve/main/<model>-Q4_K_M.gguf"
Start the server (from the llama.cpp build directory):
./llama-server \
-m ./models/<model>-Q4_K_M.gguf \
-c 4096 \
--host 127.0.0.1 \
--port 8080
-c 4096 sets the context window in tokens (the amount of text the model can see at once). Larger context costs more RAM.--host 127.0.0.1 binds to localhost only. Do not expose the port to the internet without an auth proxy.-ngl <N> offloads N layers to the GPU. -ngl 0 forces CPU only; on a GPU machine raise it until memory is full. For deep GPU offload and quantization trade-offs see How to Run a 125B-Parameter LLM on an RTX 4090: Quantization, Offload and 100 Tokens/s.The binary is called llama-server in current builds and server in older ones — check the documentation of the release you downloaded.
Example: the terminal prints model metadata (architecture, parameter count, quantization type) followed by a line announcing the listening address, e.g. listening on http://127.0.0.1:8080. The process stays in the foreground; leave it running and open a second terminal.
How to check: in the second terminal run curl -s http://127.0.0.1:8080/health. Expected body: {"status":"ok"}. A connection refused error means the server is not up — read the first terminal's output.

What to do: send one chat request and one completion request, and read the timing block the server logs.
Why: a running port proves nothing about generation quality. You want to confirm three things: the model loads, it produces coherent text, and the throughput matches your hardware expectations.
curl -s http://127.0.0.1:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "local",
"messages": [{"role": "user", "content": "Reply with the single word: OK"}],
"max_tokens": 16
}'
Expected: a JSON object where choices[0].message.content contains OK, and usage reports prompt and completion token counts. The model field value is arbitrary for a single-model server.
Then the same endpoint from Python, which is how most applications will call it:
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8080/v1", api_key="not-needed")
r = client.chat.completions.create(
model="local",
messages=[{"role": "user", "content": "Summarise the GGUF format in one sentence."}],
max_tokens=64,
)
print(r.choices[0].message.content)
Finally, look at the server terminal. After each request it prints prompt-eval and eval timings in tokens per second. That number is your baseline: if you re-run with a higher -ngl or a larger quant, compare against it.
Example: the first curl returns within a couple of seconds on CPU for a small model; the Python snippet prints one English sentence about single-file packaging. If you get an empty content and finish_reason: "length", your max_tokens is too small for the model to finish its first sentence.
How to check: all three of these hold — /health returns ok, the curl response contains a non-empty content, the server log shows a tokens-per-second figure after the request. That is a working local model.
Problem. Download fails with a permission error on a gated model
401 Client Error: Unauthorized for url: https://huggingface.co/<org>/<model>/resolve/main/<file>.ggufhuggingface-cli login and repeat the download. For raw curl, confirm the variable is set: echo $HF_TOKEN must print a token, not an empty line.Problem. The model loads but the server exits with a tensor shape error
llama_model_load: error loading model: check_tensor_dims: tensor 'blk.0.attn_q.weight' has wrong shapellama.cpp build is older than the GGUF format version used by the file, or the file is truncated because the download was interrupted.llama.cpp release and rebuild, then verify the file size matches the size shown on the model page (ls -lh ./models). If it is smaller, delete it and download again — huggingface-cli download resumes incomplete transfers.Problem. Generation dies immediately on a GPU machine
ggml_backend_cuda_buffer_type_alloc_buffer: allocating <N> MiB on device 0: cudaMalloc failed: out of memory-c context do not fit in VRAM.-c 2048), reduce offload (-ngl to a smaller number so more layers stay on the CPU), or switch to a smaller quant such as Q3_K_M. Restart and re-check /health.You now have a single .gguf file downloaded from a filtered Hugging Face search and served locally on 127.0.0.1:8080 through an OpenAI-compatible API. Next, benchmark two quantization levels on the same prompt and keep the smaller one if the answers stay usable, then compare other open-weight families as described in How to Run Meta's New Open Model Locally and Compare It with DeepSeek and Qwen.
Do I need a GPU to run a GGUF model?
No. llama.cpp runs on CPU; -ngl 0 forces that mode. A GPU only raises tokens per second and lets you fit larger quants, because the whole file must fit in memory either way.
What is the difference between GGUF and safetensors?
Safetensors is a general weight-storage format, usually split across many shards and loaded by training or serving frameworks. GGUF is a single self-contained file with weights, tokenizer and metadata, built for local inference.
Which quantization should I pick first?
Start with Q4_K_M. If the model answers poorly on your task, move up to Q5_K_M or Q6_K while it still fits in memory; if it does not fit at all, move down to Q3_K_M.
Can I convert my own fine-tuned model to GGUF?
Yes — llama.cpp ships a conversion script that takes a Hugging Face-format directory and writes a GGUF file, followed by a separate quantize step. Script names and flags change between releases, so check the documentation in the repository you cloned.