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.

Why do this first

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 holds book/, labs/ and tools/; 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 Codespaces

Colab 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:

BackendLLM_BACKENDNeedsCostsGood for
Claudeanthropican API keyper token (table below)strong answers; tools and agents work well
OllamaollamaOllama installed and a model pullednothingprivacy, offline work, free experiments
Fakefakenothingnothingreading 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

  1. Sign in to the Anthropic Console, the web dashboard for the Claude API, at platform.claude.com, and add billing.
  2. 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.
  3. 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.
  4. Put the key in your shell, not in a file in the repository:
    export ANTHROPIC_API_KEY="paste-your-key-here"   # this terminal only
    export LLM_BACKEND=anthropic                      # optional: the default when a key is set
    In Windows PowerShell the first line is $env:ANTHROPIC_API_KEY = "paste-your-key-here". To keep it across terminals, put the export line in your shell's start-up file (~/.zshrc or ~/.bashrc), which lives outside the repository.
Never commit a key

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_tokens and is billed as output (chapter 16).
  • An effort setting (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.

  1. Install it from ollama.com (macOS, Windows and Linux).
  2. 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.
  3. Make sure the server is running. The desktop app runs it for you; otherwise start it with ollama serve in another terminal.
  4. 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

VariableExampleWhat it does
LLM_BACKENDanthropic, ollama, fakewho answers
LLM_MODELclaude-sonnet-5-5, llama3.1:8bwhich model inside the backend; the defaults are claude-haiku-5-5 and llama3.2
ANTHROPIC_API_KEYyour keythe Claude backend's key
OLLAMA_HOSThttp://localhost:11434where 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 seeWhat 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 backendYou 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 fakeLLM_BACKEND=anthropic is set but there is no key.
error: anthropic: ... with a 401 codeThe key is wrong or was deleted. Create a new one.
ollama is not answering at http://localhost:11434The 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.

LabCalls in the stepsEstimated cost on claude-haiku-5-5
Lab 0: set up your workbenchone check callunder $0.001
Lab 1: your first model callabout 20about $0.008
Lab 2: a prompt test bench30 per run, six runsabout $0.005 a run, $0.03 in all
Lab 3: RAG from scratchone per questionabout $0.0003 a question, allowing for thinking
Lab 4: measure your retrievalnone$0
Lab 5: tools and an agent loopabout 5 per runabout $0.0013 a run, at most $0.011
Lab 6: build an MCP servernone$0
Lab 7: guardrails you can testone per questionabout $0.00004 a question, at most $0.001
Lab 8: an LLM judge you can trust80 per runabout $0.0035 a run, at most $0.085
Lab 9: tracing and cost4 in the demoabout $0.00014 a run, at most $0.0026
Lab 10: capstone, a small assistant2 per question; 40 per evaluationabout $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.txt are 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 pytest in labs/ 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