Index Ai Academy
Phase 6 · Modern LLM engineering · Inference

Running open models locally

Download, quantize and run a model on your own machine.

About 30 minutes · A free account opens the whole lesson

Create a free account Try part of it here

Already have an account? Sign in to open this lesson

Why it matters

Some AI companies let you download their trained models. Llama, Qwen, Gemma, Mistral and DeepSeek are well-known examples. You can run them on your own computer, and your data never leaves it. For some jobs a laptop-sized model is good enough. It costs nothing per word, keeps things private and works offline. You can work out what fits on which machine and how fast it will run. You can read what the license allows. Then "can we run this ourselves?" becomes a five-minute calculation instead of a guess.

What you'll be able to do

  • Estimate whether a model fits on a machine, and how fast it will run, from its size and quantization
  • Run an open model locally with Ollama and call it from Python
  • Read the parts of a model card and license that matter for business use
  • Decide when a local open model beats a hosted API, and when it doesn't

What it covers

  1. Open weights, not always open source
  2. Will it fit?
  3. How fast will it run?
  4. Four machines, three models
  5. Worked example: choosing a model for a 36 GB laptop
  6. Running one
  7. Local or hosted?

Open weights, not always open source

A trained model is a huge list of numbers called weights (also called parameters). An "open" model is one whose weights you can download. Anyone can then run it, and adjust it with more training (fine-tuning).

Think of a restaurant that sells you a jar of its famous sauce. You can take it home, use it and even add your own spices. But you don't get the recipe, the shopping list or the kitchen notes. Most open models are like that. They publish the weights. They don't publish the training data or the full training code. So open weights is the more accurate name.

Every open model comes with a license: the rules for using it. Some are permissive. Apache 2.0, used for many Qwen and Mistral models, lets you use the model for almost anything. Others are custom licenses with conditions. Meta's Llama license is one example. Companies with more than 700 million monthly users need a separate license from Meta. It also comes with an acceptable-use policy, a list of things you may not use the model for. Always read the license before you build a product on a model.

Where models live

Models are shared on the Hugging Face Hub, a website that works like an app store for models. Each model has a model card: a page of documentation. It tells you:

  • what the model was trained to do, and what it's not meant for;
  • its context length, the most text it can read at once;
  • its scores on standard tests, called benchmarks;
  • its known limits;
  • its chat template, the exact format for messages (from the base-vs-chat lesson);
  • its license.

The same model usually appears in several quantized versions made by other people. Quantized means its weights are stored in fewer bits, as you saw in the quantization lesson. A common file format is GGUF, with levels named like Q8_0 (about 8 bits per weight) and Q4_K_M (about 4 to 5 bits per weight).

Quick check
You want to use an open model in a paid product. Where do you find out whether that's allowed?
  1. The chat template
  2. The number of downloads on the Hub
  3. The license, listed on the model card
  4. The model's benchmark scores
Show the answer

The license, listed on the model card

The license sets the rules for use. Some allow almost anything; others add conditions, such as Llama's extra license for very large companies.

Will it fit?

Packing for a trip, you check one thing first: does everything fit in the suitcase? A model is the same. Its weights must fit in the computer's memory, with some room to spare.

You already know how to work out the size of the weights. Each weight takes a number of bits (single 0s and 1s), and 8 bits make one byte. A gigabyte (GB) is a billion bytes. In a name like "8B", the B means billion parameters.

GB of weights=parameters×bits per weight8×1,000,000,000\text{GB of weights} = \frac{\text{parameters} \times \text{bits per weight}}{8 \times 1{,}000{,}000{,}000}

In plain words: multiply the number of weights by the bits each one takes. Divide by 8 to get bytes. Divide by a billion to get gigabytes.

The weights aren't the only thing in memory. Two more items need room:

  • the KV cache, the model's short-term memory of the conversation so far (from Phase 5). Longer conversations need more of it;
  • the runtime, the program running the model, which needs about 1 GB.

Try an 8B model at Q4_K_M, which uses about 4.8 bits per weight:

  • 8 billion × 4.8 = 38.4 billion bits.
  • 38.4 billion ÷ 8 = 4.8 billion bytes, which is 4.8 GB.
  • Add about 1 GB of KV cache and 1 GB for the runtime: 6.8 GB in all.

Here is the same sum in Python:

params = 8e9          # 8 billion weights
bits = 4.8            # Q4_K_M, including its scales
weights_gb = params * bits / 8 / 1e9
print(weights_gb)
print(weights_gb + 1.0 + 1.0)
It runs right here in your browser, with nothing to install.

It prints 4.8, then 6.8. (8e9 is Python's short way to write 8 followed by nine zeros.)

Try it now

The formula from this section, with about 1 GB for the runtime. Negative room to spare means it won't fit.

Quick check
A model has 14 billion parameters. Roughly how much memory do its weights need at Q4_K_M (about 4.8 bits per weight)?
  1. About 28 GB
  2. About 8.4 GB
  3. About 3.5 GB
  4. About 56 GB
Show the answer

About 8.4 GB

14 billion × 4.8 ÷ 8 ≈ 8.4 billion bytes, so about 8.4 GB. You still need room for the KV cache and the runtime on top.

How fast will it run?

To write each new token (a word or piece of a word), a typical model reads every one of its weights from memory. Picture a cook who must read the whole recipe book before adding each ingredient. A thicker book means slower cooking.

So speed depends on memory bandwidth: how many gigabytes the chip can read from memory each second.

top speed (tokens per second)=bandwidth (GB per second)GB of weights\text{top speed (tokens per second)} = \frac{\text{bandwidth (GB per second)}}{\text{GB of weights}}

In plain words: divide how fast the machine reads memory by how much it has to read for each token. That gives the most tokens per second you can hope for.

Take the same 4.8 GB model on a laptop that reads 100 GB per second. 100 ÷ 4.8 is about 21. So the model writes at most about 21 tokens per second.

weights_gb = 4.8      # the 8B model at Q4_K_M
bandwidth = 100       # GB the laptop reads per second
print(round(bandwidth / weights_gb))

It prints 21. This is an upper limit. Real speeds are usually 60–80% of it.

Quick check
A laptop reads 400 GB per second. A 27B model at Q4_K_M takes 27 × 4.8 ÷ 8 = 16.2 GB. Predict what this prints.
print(round(400 / (27e9 * 4.8 / 8 / 1e9)))
  1. 400
  2. 16
  3. 25
  4. 83
Show the answer

25

400 ÷ 16.2 ≈ 24.7, which rounds to 25. So at most about 25 tokens per second.

Four machines, three models

Now put both sums together. The code below checks three model sizes on four real machines. Two are laptops. The other two are GPUs, chips built to do many sums at once, which makes them good at running models. Each model is tried in three formats: full 16-bit, Q8_0 and Q4_K_M. For every combination that fits, it prints the top speed in tokens per second ("tok/s").

A few things to know before you run it:

  • "Memory the model can use" is less than the machine's total. The operating system and other apps need the rest. On a 16 GB laptop the code assumes about 10 GB is free for the model.
  • The KV cache figures are rough guesses for about 8,000 tokens of conversation. Bigger models need more.
  • The bits per weight include the scales: small extra numbers that quantized formats store next to the weights (from the quantization lesson).
models = {"8B": (8e9, 1.0), "27B": (27e9, 2.0), "70B": (70e9, 2.5)}   # parameters, rough KV cache (GB) for 8K tokens
formats = {"16-bit": 16, "Q8_0": 8.5, "Q4_K_M": 4.8}                  # bits per weight, including scales
machines = {                                                          # memory the model can use (GB), bandwidth (GB/s)
    "16 GB MacBook Air (M3)": (10, 100),
    "36 GB MacBook Pro (M3 Max)": (27, 400),
    "24 GB gaming GPU (RTX 4090)": (22, 1008),
    "80 GB datacenter GPU (H100)": (78, 3350),
}
for machine, (memory, bandwidth) in machines.items():
    print(machine)
    for name, (params, kv_gb) in models.items():
        options = []
        for fmt, bits in formats.items():
            weights_gb = params * bits / 8 / 1e9
            if weights_gb + kv_gb + 1.0 <= memory:            # + ~1 GB for the runtime
                options.append(f"{fmt} ~{bandwidth / weights_gb:.0f} tok/s")
        print(f"  {name:>4}: {', '.join(options) if options else 'does not fit'}")

The speeds are upper limits, but the overall picture is right.

  • An 8B model at 4-bit runs on an ordinary laptop. On the 16 GB MacBook Air it's the only option that fits, at up to about 21 tokens per second.
  • A 27B model needs more. It fits at Q4_K_M on the high-memory laptop or the gaming GPU, at about 25 and 62 tokens per second.
  • A 70B model needs a lot more. Of these four, only the datacenter GPU fits it. Otherwise you need two consumer GPUs or a Mac with 64 GB or more.

Apple Silicon Macs are popular for this. Their GPU (the chip that runs the model) shares the machine's large main memory, called unified memory. A gaming GPU has its own, smaller memory, but reads it much faster.

Tip: a rule of thumb from practice. For a fixed amount of memory, a bigger model at 4-bit usually beats a smaller model at 16-bit. Still test both on your own task.

Worked example

Worked example: choosing a model for a 36 GB laptop

A team has the 36 GB MacBook Pro from above: about 27 GB free, reading 400 GB per second. They want room for a longer conversation, so they allow 1.5 GB of KV cache. They're choosing between a 14B and a 32B model, each at Q8_0 or Q4_K_M. Before you run it, guess which options fit.

memory, bandwidth, kv_gb = 27, 400, 1.5
for name, params, bits in [("14B Q8_0", 14e9, 8.5), ("14B Q4_K_M", 14e9, 4.8), ("32B Q8_0", 32e9, 8.5), ("32B Q4_K_M", 32e9, 4.8)]:
    weights_gb = params * bits / 8 / 1e9
    total = weights_gb + kv_gb + 1.0
    if total <= memory:
        print(f"{name:<11} {total:5.1f} GB of {memory}: fits, up to ~{bandwidth / weights_gb:.0f} tokens/s")
    else:
        print(f"{name:<11} {total:5.1f} GB of {memory}: does not fit")
In the lesson you can change this and run it.

Three options fit. The 32B model at Q8_0 needs 36.5 GB, so it doesn't. The 14B model at Q4_K_M is the fastest, at up to about 48 tokens per second. The 32B model at Q4_K_M is the slowest, at up to about 21, but it's the bigger model. By the rule of thumb, it's likely to give better answers. Real speed is usually 60–80% of the limit, so expect roughly 12 to 17 tokens per second from it. The right choice depends on the job. Test both on a sample of your own work.

Running one

Ollama is the easiest way to start. It's a free program that downloads quantized models, runs them, and answers requests from other programs on your computer. Other popular options are:

  • LM Studio, a desktop app with a chat window;
  • llama.cpp, the engine underneath many of these tools;
  • MLX, Apple's framework for Apple Silicon Macs;
  • vLLM, for serving models on GPUs to many users.

In a terminal on your own machine, two commands get you chatting:

ollama pull qwen2.5:7b          # downloads a 4-bit build, about 4.7 GB
ollama run qwen2.5:7b           # chat in the terminal

The first downloads the model. The second starts a chat. Ollama also runs a small local server: a program that waits for requests and sends back replies. Your Python code can talk to it. This code can't run inside the academy, because the academy can only reach its practice API.

import requests

reply = requests.post("http://localhost:11434/api/chat", json={
    "model": "qwen2.5:7b",
    "messages": [
        {"role": "system", "content": "You write product copy for an outdoor brand."},
        {"role": "user", "content": "Write a one-sentence description of a lightweight two-person tent."},
    ],
    "stream": False,
}).json()
print(reply["message"]["content"])

Here is what each part does:

  • localhost means "this computer". 11434 is the port, a numbered door Ollama listens on. So the request never leaves your machine.
  • messages is the conversation: a system message that sets the role, then the user's request.
  • "stream": False asks for the whole reply at once, instead of word by word.

Ollama also offers a second web address, called an endpoint, that copies OpenAI's format. So many existing tools can use a local model if you change one web address. You don't need to format the chat template yourself. Ollama reads it from the model's files and applies it for you.

Quick check
Your code sends its request to http://localhost:11434. Where does the text of your request go?
  1. To Hugging Face, which hosts the model
  2. Nowhere outside your own computer: localhost means this machine
  3. To Ollama's company servers
  4. To whichever AI provider is cheapest
Show the answer

Nowhere outside your own computer: localhost means this machine

localhost is your own computer, and 11434 is the port Ollama listens on. The model runs on your machine, so the data stays there.

Local or hosted?

A hosted API is a model that runs on a provider's computers. You send text over the internet and pay per token. Here's how the two choices compare:

Reason to run locallyReason to use a hosted API
Data can't leave your machines (privacy, contracts, regulation)You need the strongest models; frontier models are mostly hosted
Very high, steady volume makes hardware cheaper than per-token pricesVolume is low or spiky; you pay only for what you use
Offline use, or no dependence on a vendor's availability and changesNo hardware, updates or security to manage
You need to fine-tune deeply or control the exact model versionBuilt-in features: tool use, search, long context, batch discounts

Frontier models are the newest, most capable models from the big labs. There are also middle grounds. You can rent GPUs in the cloud and run an open model on them. Or you can use providers that host open models behind an API.

Whichever you choose, test it on your own task. A model that tops a leaderboard (next lesson) may not be the best at writing your product copy.

For marketers: a local 7–8B model suits private, high-volume, simple jobs. Examples: tagging customer feedback that can't be sent to a third party, first drafts of routine copy, and pulling fields out of documents. For nuanced writing and analysis, a frontier hosted model is usually still worth its price.

Practice what you just read

  • 5 code examples you can edit and run
  • a practice exercise that checks your code
  • a 5-question quiz
  • 5 review cards for spaced repetition

Create a free account

Try a quiz question

What does 'open weights' usually mean?

  1. The trained weights are downloadable under some license; training data and code may not be
  2. The model is free for any use, with no conditions, since its license gives up all rights
  3. The model's training data is public, so that anyone can check or repeat how it was trained
  4. The model can only be used through an API, but the provider publishes how its weights were set

Answer it at the end of the lesson to see if you're right, and why.

Before this lesson