Setup: Colab, Your Model Provider, and Running Locally
This takes about ten minutes. You do it once.
1. Choose a provider
The course works with three ways of reaching a language model. You only need one. You switch by changing one word in the setup cell.
| Provider | What it is | Where you run it | Cost |
|---|---|---|---|
| Groq | A cloud service that runs open models very fast | Google Colab, or your own computer | Free plan with daily limits |
| Google Gemini | Google's own models, through an API | Google Colab, or your own computer | Free tier with limits |
| Ollama | A program that runs a model on your own machine | Your own computer, in a code editor | Free; you supply the computer |
If you are using Colab, choose Groq or Gemini. They need a free key and nothing else.
If you want Ollama, work on your own computer in an editor such as VS Code. Ollama runs the model on your machine, so no key is needed and nothing you type leaves your computer. Section 5 shows the local setup.
Free plans limit how many requests you can send per minute and per day. If you hit a limit you get an error with the number 429. Wait a minute and try again, or switch provider.
Model names change. The names below were checked against each provider's documentation in October 2026. If a call fails with "model not found", open the provider's model list (links below) and put a current name into the setup cell. Nothing else in the lesson needs to change.
2. Get a key (Groq or Gemini)
Groq
- Go to console.groq.com and sign in.
- Open API Keys and create a key.
- Copy it. You will not be shown it again.
Model list: console.groq.com/docs/models
Google Gemini
- Go to aistudio.google.com and sign in.
- Choose Get API key and create a key.
- Copy it.
Model list: ai.google.dev/gemini-api/docs/models
3. Store the key safely in Colab
Never paste a key into a code cell. Notebooks get shared, and a key in a shared notebook is a key someone else can spend.
- Open colab.research.google.com and create a new notebook.
- In the left sidebar, click the key icon (Secrets).
- Add a secret. The name must be exactly
GROQ_API_KEY(for Groq) orGOOGLE_API_KEY(for Gemini). The value is your key. - Turn on Notebook access for it.
The secret is remembered across notebooks. For each new notebook you only switch access on.
4. The setup cell
Every lesson that calls a model begins with these two cells. Paste them, set PROVIDER, and run.
The course uses LangChain, a widely used Python library for building applications on language models. One of the things it does is give every provider the same interface, so the rest of your code does not care which one you chose. Later modules also use LangGraph, its companion library for building multi-step workflows and agents.
%pip install -q -U langchain langgraph langchain-groq langchain-google-genai langchain-ollamaimport os
from langchain.chat_models import init_chat_model
PROVIDER = "groq" # "groq" or "gemini" in Colab; "ollama" on your own computer
MODELS = {"groq": "groq:openai/gpt-oss-20b", "gemini": "google_genai:gemini-3.5-flash-lite", "ollama": "ollama:llama3.2:3b"}
KEY = {"groq": "GROQ_API_KEY", "gemini": "GOOGLE_API_KEY", "ollama": None}[PROVIDER]
if KEY and KEY not in os.environ:
from google.colab import userdata # keys live in Colab's Secrets panel
os.environ[KEY] = userdata.get(KEY)
llm = init_chat_model(MODELS[PROVIDER], temperature=0, max_retries=6)print(llm.invoke("Reply with the single word: ready").text)If it prints ready (or something close), you are set up.
Code walkthrough
%pip install ...installs the libraries once per notebook.langchainandlanggraphare the frameworks; the threelangchain-...packages are the connectors for each provider.PROVIDER = "groq"is the one word you change to switch provider.MODELSnames the model for each provider asprovider:model-name. This is the only place model names appear, so when a name changes you edit one line.KEYis the name of the secret the provider needs. Ollama needs none.- The
ifblock runs only in Colab when the key is not already set: it copies your key from the Secrets panel into an environment variable, which is where LangChain looks for it. init_chat_model(...)creates the model object,llm.temperature=0asks for the most consistent output.max_retries=6makes the client wait and try again when the provider says "too many requests" (a 429); Groq's free plan allows 8,000 tokens a minute, which a long block can pass. It does not retry a reply the provider rejected as malformed: see "When the provider rejects a reply" below.llm.invoke(...)sends one message and returns a reply;.textis the reply as a string.
Why one cell works for three providers
init_chat_model reads the part before the colon (groq, google_genai, ollama) and builds the right connector. All connectors offer the same methods: .invoke() to get a reply, .stream() to get it piece by piece, and so on. Your code talks to llm and never mentions the provider again.
This is also how real teams avoid being locked to one provider: the provider is a setting, not something written all through the code.
The connectors are not identical underneath. One difference the course meets: with structured output, Groq applies strict=True and the Gemini connector ignores it without a warning (seen in the course's runs, October 2026), so code always validates the reply itself.
When the provider rejects a reply
Sometimes a provider refuses the model's own reply with an error instead of returning it. In the course's test runs on 12 October 2026, Groq did this a few times with openai/gpt-oss-20b: an answer that should have been JSON came back empty, or the model called a tool it was never given. max_retries does not help, because the request itself was fine. The course handles it the same way everywhere: try once more, and if that also fails, say so plainly instead of crashing.
def ask(model, messages):
"""Returns (reply, None), or (None, reason) after two refusals."""
for attempt in range(2): # one retry: the next reply is usually fine
try:
return model.invoke(messages), None
except Exception as err:
last = err
return None, f"provider_error: {type(last).__name__}"Code walkthrough
asksends the messages and returns the reply with no reason, or no reply with a reason.- On an error it tries once more; after a second error it gives up and names the error, for example
provider_error: BadRequestError.
Lessons use this shape: a pipeline step that gets no answer returns a clear "no answer" result with the reason provider_error, and the next step handles it, so one bad reply never stops a notebook.
Prices and limits (checked 9 October 2026)
This is the course's one table of model prices and limits. Lessons that count cost say "prices from course-guide/02" and use these numbers; when a provider changes them, this table changes and the lessons follow. Prices are US dollars per 1,000,000 tokens on each provider's paid plan.
Model (as written in MODELS) | Input | Output | Context window | Notes |
|---|---|---|---|---|
groq:openai/gpt-oss-20b (course default) | $0.075 | $0.30 | 131,072 tokens, up to 65,536 output | Groq's rate-limits page lists 30 requests a minute, 1,000 a day, 8,000 tokens a minute and 200,000 a day for this model |
groq:openai/gpt-oss-120b (stronger) | $0.15 | $0.60 | 131,072 tokens, up to 65,536 output | |
google_genai:gemini-3.5-flash-lite (course default) | $0.30 | $2.50 | Output price includes thinking tokens | |
google_genai:gemini-3.8-flash (stronger) | $0.75 | $3.75 | Listed price until 31 December 2026; $1.50 and $7.50 from 1 January 2027 | |
ollama:llama3.2:3b and ollama:llama3.2:1b | $0 | $0 | No fee per token; you pay for the machine |
Sources: Groq, "Supported models" (https://console.groq.com/docs/models) and "Rate limits" (https://console.groq.com/docs/rate-limits); Google, "Gemini Developer API pricing" (https://ai.google.dev/gemini-api/docs/pricing). Free plans change often and your own limits are on each provider's console page; these are the most likely numbers in this course to go out of date.
Cached input and batch prices (checked 9 October 2026; rules rechecked 13 October 2026)
Module 2 prices prompt caching and batch jobs, so the course also records the discounted rates. US dollars per 1,000,000 tokens, paid plans.
| Model | Cached input | Batch | Source and rule |
|---|---|---|---|
groq:openai/gpt-oss-20b | $0.037 | Half the normal price | Groq caches automatically, with no code change and no extra fee, and only on an exact prefix match. Groq states that the caching discount does not stack with the batch discount: batch tokens are billed at the batch rate whether or not they hit the cache |
groq:openai/gpt-oss-120b | $0.075 | Half the normal price | As above |
google_genai:gemini-3.5-flash-lite | $0.03 (context caching); $0.02 in a batch job | $0.15 input, $1.25 output | No minimum cache length listed for this model |
google_genai:gemini-3.8-flash | $0.075 (context caching); $0.0375 in a batch job | $0.375 input, $1.875 output | Until 31 December 2026; $0.15 cached, $0.75 and $3.75 batch from 1 January 2027. Minimum cache length 4,096 tokens |
The rules behind those rates (checked 13 October 2026):
| Rule | Groq | Gemini |
|---|---|---|
| Shortest prompt that can be cached | 128 to 1,024 tokens, depending on the model (the page gives the range, not a figure per model) | 4,096 tokens for Gemini 3.8 Flash; none listed for 3.5 Flash-Lite |
| How long a cached prefix lives | 2 hours without use (the same page also says "a few hours") | Set by you when you create the cache |
| Batch completion window | Any window from 24 hours to 7 days; 50% off synchronous prices | 24 hours (checked 12 October 2026, not refetched) |
Sources: Groq, "openai/gpt-oss-20b" (https://console.groq.com/docs/model/openai/gpt-oss-20b), "openai/gpt-oss-120b" (https://console.groq.com/docs/model/openai/gpt-oss-120b), "Prompt caching" (https://console.groq.com/docs/prompt-caching) and "Batch" (https://console.groq.com/docs/batch); Google, "Gemini Developer API pricing" (https://ai.google.dev/gemini-api/docs/pricing) and "Context caching" (https://ai.google.dev/gemini-api/docs/caching). Groq reports cached tokens in the response's usage, under prompt_tokens_details, as cached_tokens. A cost function that bills those tokens at the full input price overstates the bill; Module 2 shows the difference.
Other hosted models (checked 13 October 2026)
Module 12 reads images and audio, which the default text models do not. These are the only other hosted models the course calls.
| Model | Price | Limits | Notes |
|---|---|---|---|
groq:qwen/qwen3.8-27b (vision) | $0.80 input, $4.00 output per 1,000,000 tokens | 131,072 tokens of context, up to 16,384 output; each image counts as 2,048 input tokens; at most 3 images a request | Preview model, so it may change or be withdrawn. Lessons set reasoning_format="hidden" to get only the final answer |
Groq whisper-large-v3-turbo (speech to text) | $0.04 per hour of audio | Billed for at least 10 seconds a request | |
Groq whisper-large-v3 (speech to text) | $0.111 per hour of audio | Billed for at least 10 seconds a request |
Sources: Groq, "qwen/qwen3.8-27b" (https://console.groq.com/docs/model/qwen/qwen3.8-27b) and "Speech to text" (https://console.groq.com/docs/speech-to-text).
Open models downloaded from Hugging Face
Some lessons download a small open model and run it in the notebook, with no key. Where a lesson pins a revision (a fixed commit of the model's files), the pin is here, so a changed upload cannot change your results.
| Model | Pinned revision | First used | What it is for |
|---|---|---|---|
HuggingFaceTB/SmolLM2-135M-Instruct | 12fd25f77366fa6b3b4b768ec3050bf629380bac | Module 1 | The small open model the course opens up and fine-tunes. Load it in float32 on a CPU: bfloat16 was about ten times slower in the course's runs |
HuggingFaceTB/SmolLM2-135M | 93efa2f097d58c2a74874c7e644dbc9b0cee75a2 | Module 1 (Lesson 3) | The base model before instruction tuning, compared with the Instruct model |
HuggingFaceTB/SmolLM2-360M-Instruct | a10cc1512eabd3dde888204e902eca88bddb4951 | Module 1 (Lesson 5) | A larger SmolLM2, compared on the 24 dev tickets |
Qwen/Qwen2.5-0.5B-Instruct | 7ae557604adf67be50417f59c2c2f167def9a775 | Module 1 (Lesson 5) | A small open model from a second family, compared on the 24 dev tickets |
BAAI/bge-small-en-v1.5 | 5c38ec7c405ec4b44b94cc5a9bb96e735b38267a | Module 4 (Lesson 3) | English embeddings for help-centre search, memory and the semantic cache |
sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 | e8f8c211226b894fcb81acc59f3b34ba3efd5f42 | Module 9 | Multilingual embeddings that catch training rows copying a test ticket in other words, in any of the five languages |
protectai/deberta-v3-base-prompt-injection-v2 | 90c9989b1a342275dd0d1a95aad283c04e075671 | Module 11 | A prompt-injection classifier, about 740 MB. Its model card says the project is archived |
HuggingFaceTB/SmolVLM-256M-Instruct | 7e3e67edbbed1bf9888184d9df282b700a323964 | Module 12 | A small local vision model |
openai/whisper-tiny.en | 87c7102498dcde7456f24cfd30239ca606ed9063 | Module 12 | Local speech to text. On an Apple Silicon Mac pass device="cpu": it fails on the MPS device |
microsoft/speecht5_tts with microsoft/speecht5_hifigan | 30fcde30f19b87502b8435427b5f5068e401d5f6 and bb6f429406e86a9992357a972c0698b22043307d | Module 12 (Lesson 3 and lab) | Makes the test voice messages (MIT licence) |
Running your own model: GPU prices and server defaults (checked 13 October 2026)
Module 13 Lesson 2 compares per-token prices with renting a GPU. These are listed prices in US dollars per GPU per hour, on demand, and the most likely numbers on this page to change.
| GPU | Provider | Price per hour |
|---|---|---|
| L4, 24 GB | RunPod | $0.59 |
| L40S, 48 GB | RunPod | $1.09 |
| H100 SXM, 80 GB | RunPod | $3.99 |
| H100 SXM, 80 GB | Lambda | $4.29 (one GPU; $3.99 to $4.19 per GPU in 2, 4 and 8 GPU instances) |
Sources: RunPod, "Pricing" (https://www.runpod.io/pricing) and Lambda, "Pricing" (https://lambda.ai/pricing), both fetched 13 October 2026. RunPod's page shows the prices above in its table, but lower Community Cloud prices in its embedded data (for example $0.44 for an L4); the course uses the table.
Server defaults the lessons rely on, from each project's own documentation on 13 October 2026:
| Server | Default |
|---|---|
| vLLM | Listens on port 8000. --gpu-memory-utilization defaults to 0.92 (92% of GPU memory) |
llama.cpp llama-server | Listens on port 9931 (the README's --port default; older releases used 8080) |
| Ollama | Listens on port 11434 |
Sources: vLLM, "Engine arguments" (https://docs.vllm.ai/en/latest/configuration/engine_args.html); llama.cpp, server README (https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md). vLLM needs a CUDA GPU, so it is not run in this course; Lesson 2 gives its commands as local instructions.
Extra libraries, by module (checked 9 to 13 October 2026)
The setup cell covers every lesson that only calls a model. Some lessons need one more library. Those lessons install it in their own cell, just before first use, with the version pinned so that your run matches the course's. Every pin below was checked on pypi.org on the date the lesson was written; all exist on 13 October 2026. "First used" is the first module that installs or imports it.
| Library | Pinned install | First used | Also used in | What it is for |
|---|---|---|---|---|
| pytest | pytest==9.1.1 | Module 1 (lab) | Every module lab | Running the repository's tests |
| tokenizers | tokenizers==0.23.3 | Module 1 | Modules 2, 3, 7, 11 | Training TinyLM's byte pair encoding tokeniser |
| PyTorch | already in Colab; locally torch==2.14.1 | Module 1 | Every module that loads a model with transformers | Building, training and opening TinyLM; running small open models |
| transformers | transformers==5.19.0 | Module 1 | Modules 2 to 5, 9 to 14 | Reading published model configs; small open models; the injection classifier; vision and speech models |
| tiktoken | tiktoken==0.14.0 | Module 1 (Lesson 5) | Modules 2, 4 to 8, 10, 12, 13, 15 | Counting tokens offline. Its o200k_harmony encoding is the one tiktoken maps to the gpt-oss models |
| rank-bm25 | rank-bm25==0.2.2 | Module 2 (Lesson 3) | Modules 7, 14, 15 | Keyword search over the help centre |
| sentence-transformers | sentence-transformers==6.1.0 | Module 4 (Lesson 3) | Modules 7, 9, 13, 15 | Local embeddings for search, memory, data checks and semantic caching, no key |
| mcp | mcp==2.3.0 | Module 8 | The official Model Context Protocol SDK | |
| peft | peft==0.21.2 | Module 9 | LoRA adapters | |
| accelerate | accelerate==1.15.0 | Module 9 | Training on whatever device is present | |
| trl, datasets | trl==1.14.2 datasets==5.1.0 | Module 9 (Lesson 4) | Preference training (trl pinned to 1.14.2: 1.15.0's DPO trainer needs a Triton kernel and fails on CPU, checked 12 October 2026) | |
| bitsandbytes | bitsandbytes==0.50.2 | Module 9 (Lesson 3) | 4-bit loading for the QLoRA cell. Colab T4 GPU only; it is not run on a CPU | |
| scikit-learn | already in Colab; locally scikit-learn==1.9.1 | Module 9 | Module 10 | Classical baselines and agreement statistics |
| scipy | already in Colab (1.18.1 on 12 October 2026); locally scipy==1.18.1 | Module 10 | Module 12 | Confidence intervals and tests; reading and resampling audio |
| pypdf | pypdf==6.20.0 | Module 12 | Reading text from born-digital PDFs | |
| fpdf2, pdfplumber, pytesseract | fpdf2==2.8.9 pdfplumber==0.11.10 pytesseract==0.3.13 | Module 12 (Lesson 2) | Making test invoices, reading PDF tables, and calling the Tesseract OCR program. Tesseract itself is a system program: apt-get in Colab (version 4.1.1 there), brew on a Mac; the course's OCR numbers come from Tesseract 5.5.3 | |
| sentencepiece | sentencepiece==0.2.2 | Module 12 (Lesson 3) | Module 12 (lab) | The tokeniser the SpeechT5 voice model needs |
| fakeredis | fakeredis==2.39.0 | Module 13 | A Redis stand-in for caching and quotas in a notebook | |
| fastapi, httpx | fastapi==0.143.0 httpx==0.28.1 | Module 13 (lab) | The web service and its TestClient | |
| opentelemetry-sdk | opentelemetry-sdk==1.45.1 | Module 13 (Lesson 4) | Standard tracing spans | |
| opentelemetry-exporter-otlp-proto-http | opentelemetry-exporter-otlp-proto-http==1.45.1 | Module 13 (Lesson 4, local only) | Sending spans to a local collector | |
| vllm | vllm==0.31.0 | Module 13 (Lesson 2, local GPU only, not run) | A serving engine for your own model | |
| uvicorn, redis and the LangChain packages | uvicorn==0.54.0 redis==8.1.0 langchain==1.4.3 langchain-groq==1.1.3 langchain-google-genai==4.4.0 langchain-ollama==1.1.0 | Module 13 (lab, requirements-service.txt) | The container's fixed versions. Notebooks install the LangChain packages unpinned with -U (the setup cell) |
Unpinned installs to know about: Module 1 Lessons 3 and 4 and the incident file pin transformers but install torch (and, in Lesson 3, huggingface_hub) without versions, so the copies already in Colab are used; Module 6's incident file installs langchain-core without a version. The repository's pyproject.toml from the Module 1 lab is complete for the whole course: it lists every notebook library in this table at its pinned version (the setup-cell packages, torch, pydantic, numpy, scipy and scikit-learn unpinned), leaving out only bitsandbytes, vllm, the OTLP exporter and the container's own pins in requirements-service.txt, and pytest==9.1.1 as the test extra. The notebook cells still install each library just before first use.
A lesson writes the install as, for example:
%pip install -q tiktoken==0.14.0If pip reports a version conflict in Colab, keep the pinned library and let pip choose its dependencies. On your own computer, add the libraries you need to the pip install line in section 5.
5. Running on your own computer (required for Ollama)
You can run every lesson locally with any provider. For Ollama it is the way to do it.
Install
- Python 3.10 or newer from python.org. Check with
python --version(on some systemspython3 --version). - A code editor. VS Code with the Python and Jupyter extensions is a good choice. Cursor, PyCharm and others work the same way.
- Ollama, if you are using it, from ollama.com/download. After installing, download the course's default model once, in a terminal:
ollama pull llama3.2:3bThat is a download of about 2 GB. The model runs acceptably on a recent laptop with 8 GB of memory or more. A small local model makes more mistakes than the cloud models. That is useful for this course: several "break it" steps are easier to see on a small model.
Create a project folder
In a terminal:
mkdir llms-course
cd llms-course
python -m venv .venvSwitch the virtual environment on:
# macOS and Linux
source .venv/bin/activate
# Windows (PowerShell)
.venv\Scripts\Activate.ps1Then install the libraries:
pip install -U langchain langgraph langchain-groq langchain-google-genai langchain-ollama pydantic python-dotenv ipykernelKeys on your own computer
Ollama needs no key. For Groq or Gemini, create a file named .env in the project folder:
GROQ_API_KEY=paste-your-key-here
GOOGLE_API_KEY=paste-your-key-hereand add these two lines at the very top of the setup cell:
from dotenv import load_dotenv
load_dotenv()Never share the .env file or commit it to Git.
Run the lessons
Open the folder in your editor and create a new notebook file, for example module-07-lesson-1.ipynb. Select the .venv Python when asked. A notebook in VS Code works like Colab: paste each code block into a cell and run it.
Set PROVIDER = "ollama" in the setup cell. You can skip the %pip install cell, because you installed the libraries already.
On a Mac: FAISS and PyTorch together
On macOS, loading FAISS and PyTorch in the same Python process can crash with an OpenMP error, because each brings its own copy of the OpenMP library. If you see it, set two environment variables in the terminal before you start Python, Jupyter or your editor:
export KMP_DUPLICATE_LIB_OK=TRUE
export OMP_NUM_THREADS=1The first tells OpenMP to accept the second copy; it is a workaround, not a fix. The second keeps OpenMP to one thread, which is slower on large indexes but fine for the small ones in this course. This course trains TinyLM with PyTorch but does not load FAISS in its lessons, so you only need this if you add a FAISS index of your own. You do not need it in Colab.
From notebook cells to a project
In a job you would not keep code in notebook cells. The course grows one repository, a single package called supportdesk/. Module 1 starts it: the shared data becomes supportdesk/data.py, the setup cell becomes supportdesk/llm.py with the llm object created once, TinyLM goes in supportdesk/tinylm.py, and a tests/ folder holds the checks as pytest tests. Every later module adds its piece to the same package, Module 13 puts it behind a web service in a container, and the Module 15 capstone collects everything in it. Labs that must run in a temporary folder for testing create supportdesk/ there with the same layout and say so. The project page (course-guide/03) lists which module adds which file.
6. When something goes wrong
| What you see | What it means | What to do |
|---|---|---|
SecretNotFoundError | The secret is missing or misnamed | Check the name is exactly GROQ_API_KEY or GOOGLE_API_KEY |
NotebookAccessError | The secret exists but this notebook cannot read it | Turn on Notebook access for the secret |
ModuleNotFoundError: google.colab | Running locally with no key set | Create the .env file and add the two load_dotenv lines |
AuthenticationError (401) | The key is wrong or was deleted | Create a new key and update the secret |
NotFoundError (404) mentioning the model | The model name is out of date | Put a current model name in MODELS |
RateLimitError (429) | You hit the free plan's limit | Wait a minute, or switch PROVIDER |
| A connection error with Ollama | Ollama is not running | Open the Ollama app, or run ollama serve in a terminal |
| Ollama says the model is not found | The model has not been downloaded | Run ollama pull llama3.2:3b |