Running Models Locally 🏠
You do not always need someone else's server. Open models now run on a decent laptop: private, free per use, offline. Here is when that is the right call, and how.
Why run a model yourself?
A cloud model is someone else's computer. That is often exactly right: you get the most capable models with zero setup. But it means your data leaves your machine, you pay per token, and you need a connection. Running an open-weight model locally flips all three.
| Cloud model (Lessons 54-59) | Local model | |
|---|---|---|
| Capability | The frontier: the very best models | Very good and improving fast, but a step behind the best |
| Privacy | Data goes to the provider | Nothing leaves your machine, ever |
| Cost | Per token; adds up with volume | Free per use after the hardware you already own |
| Offline | No | Yes, works on a plane or in a bunker |
| Setup | One pip install | Download a model file (gigabytes), run a local server |
| Hardware | None; it is their problem | Yours; more RAM and a GPU help a lot |
Ollama: the easy way in
Ollama is the simplest way to run open models. Install it, pull a model, and it runs a local server on your machine that speaks a familiar API. Downloading a model is one command:
# install Ollama from ollama.com, then:
ollama pull llama3.2 # download an open model (a few GB)
ollama run llama3.2 # chat with it right in the terminal
# it now serves an API at http://localhost:11434
That is genuinely it. You are now running a capable language model with no account, no key, no bill, and no data leaving your laptop. The models are open-weight releases from Meta (Llama), Mistral, Google (Gemma), Alibaba (Qwen) and others, and there are small ones (a few gigabytes, runs on a laptop) up to large ones (needs a serious GPU).
Talking to it from Python
# Ollama exposes a simple local HTTP API. requests (Lesson 42) is all you need.
import requests
def ask_local(prompt, model="llama3.2"):
"""Send a prompt to a model running locally via Ollama."""
response = requests.post(
"http://localhost:11434/api/chat",
json={
"model": model,
"messages": [{"role": "user", "content": prompt}],
"stream": False,
},
timeout=120, # local models can be slow on modest hardware
)
response.raise_for_status()
return response.json()["message"]["content"]
# print(ask_local("Explain recursion in one sentence."))
print("Same chat shape as the cloud: messages in, a reply out. Just a different URL.")
Look at the shape: a list of messages, a reply out. It is the same mental model as the cloud API, which is the whole point. Ollama even offers an OpenAI-compatible endpoint, so much cloud code runs against it by changing only the base URL and dropping the key.
# Ollama also has its own tidy Python library (pip install ollama)
import ollama
def chat_local(messages, model="llama3.2"):
"""A local chat that streams, mirroring Lesson 56's cloud version."""
stream = ollama.chat(model=model, messages=messages, stream=True)
reply = ""
for chunk in stream:
piece = chunk["message"]["content"]
reply += piece
print(piece, end="", flush=True)
print()
return reply
# Same streaming feel as the cloud, running entirely on your machine.
print("Local streaming chat: identical ergonomics, zero data leaving the room.")
The honest limitations
Do not oversell local models to yourself. On genuinely hard reasoning, long coding tasks, or subtle instructions, the best cloud models are still clearly ahead, and a small model on a laptop can be frustrating.
But the gap narrows every few months, and for a huge range of everyday tasks, summarising, drafting, classifying, answering questions about your own documents, a local model is already completely sufficient. The right question is never 'is local as good as the frontier'. It is 'is local good enough for this task', and surprisingly often it is.
| Task | Local model? |
|---|---|
| Summarise an email, draft a reply | Yes, easily |
| Classify or tag text in bulk | Yes, and it is free per item |
| Answer questions about your private notes (RAG) | Yes, and beautifully private |
| Anything with confidential data | Yes, this is local's home turf |
| Hard multi-step reasoning or debugging | Use a frontier cloud model |
| Long, complex agentic tasks | Frontier cloud model, for now |
| Offline, on a plane, in a secure facility | Local is your only option, and it works |
The hybrid pattern: use both
You do not have to choose once and forever. A smart assistant routes: cheap, private, local for the easy majority of tasks, and a frontier cloud model for the hard minority. This is exactly the "pick the right tool" thinking from Base Camp 4 and the performance lesson (Lesson 51), applied to models.
def route(task_difficulty, is_private):
"""Choose local or cloud based on the task. A real router might ask a
cheap model to judge difficulty, or use rules like these."""
if is_private:
return "local" # sensitive data never leaves
if task_difficulty == "hard":
return "cloud-frontier" # worth the cost and the round trip
return "local" # the cheap, private default
for difficulty, private in [("easy", False), ("hard", False), ("easy", True), ("hard", True)]:
choice = route(difficulty, private)
print(f"{difficulty:5} / private={private!s:5} -> {choice}")
easy / private=False -> local
hard / private=False -> cloud-frontier
easy / private=True -> local
hard / private=True -> local
Note the bottom row: a hard and private task stays local even though local is weaker, because the privacy requirement outranks the capability preference. Encoding that priority in your router, rather than always reaching for the best model, is what makes an assistant trustworthy.
Running models efficiently is a systems problem: memory layout, quantisation, squeezing a model into limited RAM. A lot of the fast local-inference tooling (llama.cpp and friends) is written in C and C++ for exactly the reasons Base Camp 4 gave: you need predictable speed and tight control over memory. If that appeals, it is the same instinct that leads people next door to the Rusty School.
Make your code model-agnostic
Write a single ask function that talks to either a cloud model or a local one depending on a flag, returning text either way. This is the abstraction that lets the rest of your Jarvis not care where the model lives.
Reveal solution
def ask(prompt, backend="local"):
"""One interface, two backends. The caller never has to know which."""
if backend == "local":
import requests
r = requests.post(
"http://localhost:11434/api/chat",
json={"model": "llama3.2",
"messages": [{"role": "user", "content": prompt}],
"stream": False},
timeout=120,
)
r.raise_for_status()
return r.json()["message"]["content"]
if backend == "cloud":
import anthropic
client = anthropic.Anthropic()
resp = client.messages.create(
model="claude-sonnet-5", max_tokens=1024,
messages=[{"role": "user", "content": prompt}],
)
return resp.content[0].text
raise ValueError(f"unknown backend: {backend}")
# The rest of Jarvis calls ask(prompt, backend) and stays blissfully unaware.
print("One function, two worlds. Swap backend without touching anything else.")This is the same lesson as Lesson 32's duck typing and Lesson 37's injection: code to an interface, not an implementation. Now you can develop against a free local model and switch to a frontier one for the hard cases, changing one argument.
When is local the answer?
For each, argue for local or cloud.
- A startup processing millions of documents a day.
- A doctor summarising patient notes.
- A hobbyist's home automation assistant.
- A student who wants the single best answers for hard homework.
Reveal solution
- Mixed, leaning local at scale. At millions a day, per-token cloud costs are enormous, so running open models on their own servers can save a fortune, if the tasks are within local capability. The hardest cases might still go to the cloud.
- Local, on a controlled machine. Patient data is exactly what must not be casually sent to a third party. Local (or a specially contracted, compliant cloud service) is the responsible path, with careful handling of the notes themselves.
- Local. Free per use, private, works when the internet is down, and home-automation tasks are well within a small model's ability. Close to a perfect fit.
- Cloud frontier. When you specifically want the very best reasoning on hard problems, that is what the frontier models are for. (Though the honest advice for homework is to use it to understand, not to answer for you; Lesson 62 and Lesson 10's note both say why.)