Part V · Build it
Lab 0: set up your workbench
Every lab in Part V runs on your own computer: Python, three packages and one small file that talks to a model. This lab installs them, chooses which model answers, and proves that everything works before you spend anything.
Each lab is written once and runs three ways: against Claude, against a free model on your own computer, or against a scripted stand-in that needs nothing at all. Setting up the switch now makes every later lab one command, and the stand-in lets you read and test any lab's code without a key or a bill.
What you will build
- A Python virtual environment with the labs' packages.
- A choice of backend, the thing that answers when a lab calls a model: Claude, Ollama or the fake.
- Proof that it works: the test suite passes and a first call prints a reply.
Before you start
- Python 3.10 or newer. Check with
python3 --version; install it from python.org if it is older or missing. - A terminal and a text editor.
- A copy of this book's repository on your computer. Clone it with
git clone https://github.com/aggarwaldev/build-ai-handbook, or download it as a ZIP and unpack it. Its root is the folder that holdsbook/,labs/andtools/; every command below runs from there unless it says otherwise. You can go on reading the book online while the labs run on your computer. - For Claude: an Anthropic account. For Ollama: a few gigabytes of free disk and, ideally, 8 GB of memory or more.
Run this lab without installing anything:
Open in Colab Launch on Binder Open in CodespacesColab needs a Google account and Codespaces a GitHub account. Binder needs no account, but can take a few minutes to start. The notebook follows this page step by step; tick the checklist here, in the book, to keep your progress.
Step 1: Python and a virtual environment
A virtual environment is a private copy of Python with its own packages. It keeps the labs' packages apart from everything else on your computer, so versions cannot clash, and deleting the folder undoes the whole install.
# from the repository root
python3 --version # 3.10 or newer
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
python -m pip install -r labs/requirements.txt
Once the environment is active, python means its Python, and your prompt usually shows (.venv). A new terminal starts outside it, so run the source line again in each one. The folder .venv/ is listed in .gitignore, so it never reaches a commit.
labs/requirements.txt lists three packages:
anthropic, the official Python SDK for the Claude API;numpy, for vectors from Lab 3 on;pytest, which runs every lab's tests.
Everything else the labs use is in Python's standard library. The projects in chapters 15, 20, 30 and 41 list their own extra packages in their folders.
Step 2: choose who answers
Every lab talks to a model through one function, chat() in labs/common/llm.py. Which model answers is chosen by the environment variable LLM_BACKEND, so the same lab code runs three ways:
| Backend | LLM_BACKEND | Needs | Costs | Good for |
|---|---|---|---|---|
| Claude | anthropic | an API key | per token (table below) | strong answers; tools and agents work well |
| Ollama | ollama | Ollama installed and a model pulled | nothing | privacy, offline work, free experiments |
| Fake | fake | nothing | nothing | reading a lab's code path, tests, checking a lab end to end before you pay |
You can switch at any time, even between two commands. If LLM_BACKEND is not set, the labs use Claude when ANTHROPIC_API_KEY is set, and the fake backend otherwise, with a one-line note so it is never a surprise:
$ LLM_BACKEND= ANTHROPIC_API_KEY= python labs/01-first-call/first_call.py "hi"
llm: no ANTHROPIC_API_KEY and no LLM_BACKEND, so using the fake backend
reply [fake model] I received 1 message; no system prompt. You said: hi
stop_reason end
tokens 8 in, 16 out
latency 0.000 s
model fake (fake backend)
cost $0
the same tokens on claude-haiku-5-5 would cost $0.000009
Option A: Claude
- Sign in to the Anthropic Console, the web dashboard for the Claude API, at platform.claude.com, and add billing.
- Set a spending limit first. In the Console's settings, set a monthly spend limit you are comfortable with, such as $5. The labs cost cents (table below), so a low limit costs you nothing, and it caps the damage if a loop runs away.
- Create an API key and give it a name you will recognise, such as
handbook-labs. The Console shows the key once; copy it straight into the next step. - Put the key in your shell, not in a file in the repository:
In Windows PowerShell the first line isexport ANTHROPIC_API_KEY="paste-your-key-here" # this terminal only export LLM_BACKEND=anthropic # optional: the default when a key is set$env:ANTHROPIC_API_KEY = "paste-your-key-here". To keep it across terminals, put theexportline in your shell's start-up file (~/.zshrcor~/.bashrc), which lives outside the repository.
The labs read the key from the environment and from nowhere else, so it never needs to be in a file in the repository. Anyone who has your key can spend your money. If a key ever reaches a commit, a chat, a screenshot or a shared file, delete it in the Console and create a new one; deleting the commit is not enough, because copies may already exist.
The default model is claude-haiku-5-5, the smallest and cheapest. To use another, set LLM_MODEL, for example export LLM_MODEL=claude-sonnet-5-5. Three facts about current Claude models matter in the labs:
- They fix their own sampling and reject a temperature, so the shared adapter leaves it out for Claude (chapter 16).
- They think before they answer. The thinking counts toward
max_tokensand is billed as output (chapter 16). - An
effortsetting (low,medium,high) trades depth of thinking against time and cost.
Option B: Ollama
Ollama runs open-weight models on your own computer behind a small local API. It is free, and nothing you send leaves your machine.
- Install it from ollama.com (macOS, Windows and Linux).
- Download a model:
ollama pull llama3.2. This is the labs' default, a model of about 3 billion parameters and a download of about 2 GB. - Make sure the server is running. The desktop app runs it for you; otherwise start it with
ollama servein another terminal. - Choose it:
export LLM_BACKEND=ollama.
A larger model answers better if your computer has the memory: ollama pull llama3.1:8b, then export LLM_MODEL=llama3.1:8b. If Ollama runs on another machine, set OLLAMA_HOST to its address. Expect small local models to be weaker than Claude: they follow an output format less reliably and are noticeably weaker at choosing and calling tools, which matters from Lab 5 on. Comparing the two on the same lab is a useful experiment in itself.
Option C: the fake backend
export LLM_BACKEND=fake, and nothing else. The fake backend answers with scripted replies: by default it repeats the start of your last message, and a lab can install its own rules that imitate a model's behaviour, as Lab 2 does. Every test in labs/ uses it (labs/conftest.py sets it), so the tests need no key, no network and no money, and give the same result every time.
Use it to read a lab's code path, to run its tests and to check a lab end to end before you pay for a real run. Do not read anything into its answers: it is not a model, and numbers it produces measure the plumbing only.
The settings in one table
| Variable | Example | What it does |
|---|---|---|
LLM_BACKEND | anthropic, ollama, fake | who answers |
LLM_MODEL | claude-sonnet-5-5, llama3.1:8b | which model inside the backend; the defaults are claude-haiku-5-5 and llama3.2 |
ANTHROPIC_API_KEY | your key | the Claude backend's key |
OLLAMA_HOST | http://localhost:11434 | where Ollama listens; this example is the default |
Step 3: prove it works
First the tests. They run on the fake backend whatever you chose, so this step costs nothing:
cd labs
python -m pytest
cd ..
The last line should say how many tests passed and none failed. Some tests in the chapter projects are skipped when PyTorch or the MCP SDK is not installed; that is expected.
Then one real call through the backend you chose:
python labs/01-first-call/first_call.py "Say hello in five words"
On the fake backend the output is this:
reply [fake model] I received 1 message; no system prompt. You said: Say hello in five words
stop_reason end
tokens 14 in, 21 out
latency 0.000 s
model fake (fake backend)
cost $0
the same tokens on claude-haiku-5-5 would cost $0.000012
On Claude or Ollama the reply line is a real greeting and the token counts, latency and model name are the model's own. They vary from run to run and from model to model, so yours will not match anyone else's. Check three things: stop_reason is end, the model line names the model you meant, and on Claude the cost line is a fraction of a cent. Lab 1 explains every line.
If it does not work
| You see | What it means |
|---|---|
No module named 'anthropic' or 'numpy' | The virtual environment is not active in this terminal, or the install did not run. Activate it and run the pip install line again. |
llm: no ANTHROPIC_API_KEY and no LLM_BACKEND, so using the fake backend | You meant to use Claude, but the key is not set in this terminal. Environment variables belong to one shell session. |
set ANTHROPIC_API_KEY, or use LLM_BACKEND=ollama or fake | LLM_BACKEND=anthropic is set but there is no key. |
error: anthropic: ... with a 401 code | The key is wrong or was deleted. Create a new one. |
ollama is not answering at http://localhost:11434 | The Ollama server is not running. Start the app or run ollama serve. |
ollama 404: ... (did you `ollama pull llama3.2`?) | The model named by LLM_MODEL (or the default) has not been downloaded. |
What the labs cost
Model providers charge per token, with one price for the tokens you send and a higher one for the tokens the model writes (chapter 16). For claude-haiku-5-5 the prices are $0.10 per million input tokens and $0.50 per million output tokens, and on Claude the output includes the model's thinking. A call that sends 1,000 tokens and gets 600 back costs
1,000 × $0.10 / 1,000,000 + 600 × $0.50 / 1,000,000 = $0.0001 + $0.0003 = $0.0004
Every lab prints the cost of its own calls from the token counts the provider reports. On Ollama and the fake backend it also prints what the same token counts would cost on claude-haiku-5-5, so you can budget before you switch. The estimates below assume the lab's steps are run once on Claude with the default model; each lab page says how its figure was worked out.
| Lab | Calls in the steps | Estimated cost on claude-haiku-5-5 |
|---|---|---|
| Lab 0: set up your workbench | one check call | under $0.001 |
| Lab 1: your first model call | about 20 | about $0.008 |
| Lab 2: a prompt test bench | 30 per run, six runs | about $0.005 a run, $0.03 in all |
| Lab 3: RAG from scratch | one per question | about $0.0003 a question, allowing for thinking |
| Lab 4: measure your retrieval | none | $0 |
| Lab 5: tools and an agent loop | about 5 per run | about $0.0013 a run, at most $0.011 |
| Lab 6: build an MCP server | none | $0 |
| Lab 7: guardrails you can test | one per question | about $0.00004 a question, at most $0.001 |
| Lab 8: an LLM judge you can trust | 80 per run | about $0.0035 a run, at most $0.085 |
| Lab 9: tracing and cost | 4 in the demo | about $0.00014 a run, at most $0.0026 |
| Lab 10: capstone, a small assistant | 2 per question; 40 per evaluation | about $0.00044 a question; about $0.0083 an evaluation, at most $0.043 |
Ollama and the fake backend cost nothing. Larger Claude models cost more per token: claude-sonnet-5-5 is $2 and $10 per million, 20 times Haiku's prices, and claude-opus-5-5 is $4 and $20, 40 times. Prices change, so check the pricing page before you budget.
Checklist
- Python 3.10 or newer is installed.
- A virtual environment is created and active.
- The packages in
labs/requirements.txtare installed. - I chose a backend and set
LLM_BACKEND. - My Claude key is in my shell, not in a file, or my Ollama model is pulled.
- If I use Claude, a monthly spend limit is set in the Console.
python -m pytestinlabs/passes.- My first call printed a reply with
stop_reason end.
Self-check
You exported your key in one terminal, opened another, and the labs say they are using the fake backend. Why?
Environment variables belong to the shell session that set them. Export the key again in the new terminal, or put the export line in your shell's start-up file.
Why do the tests use the fake backend even when a key is set?
Tests must be free, offline and repeatable: the same input must give the same result every time. A real model costs money, needs the network and can answer differently on each run. labs/conftest.py sets LLM_BACKEND=fake before any test runs.
A lab scores lower on Ollama than on Claude. Is the lab broken?
Not necessarily. A 3-billion-parameter model on a laptop is far smaller than a hosted model and follows instructions and formats less reliably. Compare like with like: the same lab, the same cases, one backend changed.
Where should an API key live, and what do you do if it leaks?
In an environment variable set by your shell, never in a file in the repository. If it leaks, delete it in the Console and create a new one; removing it from a commit does not remove the copies.
Further reading
- Virtual Environments and Packages (Python tutorial) docs beginner
What a virtual environment is, and how to create, activate and install into one. - Models overview docs beginner
The current Claude models, their names and what each is suited to. - Pricing docs beginner
Per-token prices for every Claude model, the figures behind the cost table above. - API errors docs intermediate
What each HTTP error code from the Claude API means and which ones are worth retrying. - Ollama documentation docs beginner
Installing Ollama, pulling models and the local API the labs call. - anthropics/anthropic-sdk-python docs intermediate
The official Python SDK that the Claude backend uses.