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.
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; cached, batch and context-window cells checked 12 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. "Cached input" is the price of input tokens the provider has already seen in an earlier prompt with the same start; "batch input" is the price through the provider's batch interface, which returns results later instead of at once.
Model (as written in MODELS) | Input | Cached input | Batch input | Output | Context window | Notes |
|---|---|---|---|---|---|---|
groq:openai/gpt-oss-20b (course default) | $0.075 | $0.037 | $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.075 | $0.60 | 131,072 tokens, up to 65,536 output | ||
google_genai:gemini-3.5-flash-lite (course default) | $0.30 | $0.03, plus $1.00 per 1,000,000 tokens per hour of storage | $0.15 | $2.50 | 1,048,576 tokens, up to 65,536 output | Output price includes thinking tokens |
google_genai:gemini-3.8-flash (stronger) | $0.75 | $0.075, plus $0.50 per 1,000,000 tokens per hour of storage | $0.375 | $3.75 | 1,048,576 tokens, up to 65,536 output | Listed prices until 31 December 2026; from 1 January 2027, $1.50 input, $0.15 cached (storage $1.00 an hour), $0.75 batch and $7.50 output |
ollama:llama3.2:3b and ollama:llama3.2:1b | $0 | $0 | No fee per token; you pay for the machine |
Groq's cached price is its model pages' own figure: they list $0.037 for openai/gpt-oss-20b and $0.075 for openai/gpt-oss-120b (checked 12 October 2026), and its prompt caching page describes the rule as "a 50% discount for cached input tokens". Half of $0.075 is $0.0375; the course uses the listed $0.037. Groq's pages list no batch price for these models, so those cells are empty.
Prompt caching, in short. Both providers cache the start of a prompt automatically when it repeats, but neither promises it. Groq's prompt caching page (checked 12 October 2026) says the minimum cacheable prefix "varies by model, ranging from 128 to 1024 tokens", and gives two expiry times for unused caches: "2 hours" in one section and "a few hours" in another. Google's context caching page (last updated 9 October 2026, checked 12 October 2026) lists a minimum of 4,096 tokens for Gemini 3.8 Flash and names no minimum for Gemini 3.5 Flash-Lite. These rules change often; check the pages before you rely on them.
Sources: Groq, "Supported models" (https://console.groq.com/docs/models), the model pages for openai/gpt-oss-20b (https://console.groq.com/docs/model/openai/gpt-oss-20b) and openai/gpt-oss-120b (https://console.groq.com/docs/model/openai/gpt-oss-120b), "Prompt caching" (https://console.groq.com/docs/prompt-caching) and "Rate limits" (https://console.groq.com/docs/rate-limits); Google, "Gemini Developer API pricing" (https://ai.google.dev/gemini-api/docs/pricing, last updated 9 October 2026), the model pages for Gemini 3.5 Flash-Lite and Gemini 3.8 Flash (https://ai.google.dev/gemini-api/docs/models) and "Context caching" (https://ai.google.dev/gemini-api/docs/caching). 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.
Extra libraries for this course
Lessons that need more than the setup cell install it in their own cell, just before first use, at the versions below. The versions were checked on PyPI on 9 October 2026 and pinned, so a lesson behaves the same when a library changes. Each lesson installs only the slice it needs.
| Library | Version | Used for | First needed |
|---|---|---|---|
sentence-transformers | 6.1.0 | Embedding models and cross-encoder rerankers, run locally | Module 1 |
langchain-huggingface | 1.2.3 | The same models behind LangChain's embeddings interface | Module 1 |
langchain-core | 1.6.8 | LangChain's Document, loader and retriever interfaces, without the rest of LangChain | Module 2 |
langchain-text-splitters | 1.1.3 | LangChain's text splitters | Module 3 |
langchain-classic | 1.0.8 | ParentDocumentRetriever and CacheBackedEmbeddings, LangChain's older chains and retrievers | Module 3 |
rank-bm25 | 0.2.2 | BM25 keyword search | Module 1 |
nltk | 3.10.3 | Word stemming for BM25 | Module 6 |
chromadb | 1.5.9 | Chroma, an embedded vector store | Module 1 |
langchain-chroma | 1.1.0 | Chroma behind LangChain's vector store interface (optional: no lesson uses it) | |
faiss-cpu | 1.15.1 | FAISS vector indexes | Module 5 |
hnswlib | 0.8.0 | A stand-alone HNSW index | Module 5 |
qdrant-client | 1.19.1 | Qdrant, run in local mode inside the notebook | Module 4 |
lancedb | 0.40.0 | LanceDB, an embedded vector store | Module 5 |
sqlite-vec | 0.1.9 | Vector search inside SQLite | Module 5 |
pgserver | 0.1.4 | A real PostgreSQL with pgvector, installed from pip (Python 3.9 to 3.12) | Module 5 |
psycopg[binary] | 3.3.6 | PostgreSQL from Python | Module 5 |
pgvector | 0.5.1 | The pgvector types for psycopg | Module 5 |
beautifulsoup4 | 4.15.0 | Reading HTML | Module 2 |
trafilatura | 2.3.1 | Extracting the main text of a web page | Module 2 |
pypdf | 6.20.0 | Reading PDF text | Module 2 |
pdfplumber | 0.11.10 | PDF text with positions, and tables | Module 2 |
pypdfium2 | 5.14.0 | Fast PDF text, and pages as images | Module 2 |
fpdf2 | 2.8.9 | Writing the course's test PDF | Module 2 |
pytesseract | 0.3.13 | OCR with the Tesseract engine (installed in Colab with !apt-get install -y tesseract-ocr) | Module 2 |
python-docx | 1.2.0 | Reading and writing Word files | Module 2 |
python-pptx | 1.0.2 | Reading and writing PowerPoint files | Module 2 |
openpyxl | 3.1.5 | Reading and writing Excel files | Module 2 |
docling | 2.137.0 | Layout-aware parsing with layout and vision models | Module 2 |
datasketch | 2.0.0 | MinHash near-duplicate detection | Module 2 |
pydantic | 2.14.0 | Validated records (DocumentRecord) | Module 2 |
pytest | 9.1.1 | Running the labs' tests | Module 1 |
tiktoken | 0.14.0 | Counting tokens with openai/gpt-oss-20b's tokeniser | Module 8 |
networkx | 3.7 | Graphs of linked documents (already in Colab; the lesson pins it) | Module 10 |
opentelemetry-sdk | 1.45.1 | OpenTelemetry tracing spans | Module 12 |
opentelemetry-exporter-otlp-proto-http | 1.45.1 | Sending spans to a trace collector (your own computer only, not run in the course) | Module 12 |
fastapi | 0.143.0 | The capstone web service | Module 14 |
uvicorn | 0.54.0 | The server that runs the FastAPI service | Module 14 |
httpx | 0.28.1 | HTTP client used by FastAPI's TestClient | Module 14 |
Colab already has NumPy, pandas, scikit-learn, PyTorch and Hugging Face transformers (the last two also come with sentence-transformers), so lessons import them without installing. pytest was checked on PyPI on 12 October 2026; the rest are the versions the lessons pin. The repository's pyproject.toml (Module 1 lab) lists every library the finished hollin/ package imports, at these versions, so CI installs one list; Module 14's requirements.txt adds only what the service alone needs (uvicorn, httpx, psycopg[binary], pgvector).
For example, the first retrieval lesson starts with:
%pip install -q sentence-transformers==6.1.0 rank-bm25==0.2.2 chromadb==1.5.9The embedding model the course uses, BAAI/bge-small-en-v1.5, and the reranker, cross-encoder/ms-marco-MiniLM-L6-v2, are downloaded from Hugging Face the first time a lesson loads them (about 130 MB and 90 MB). They need no key and run on Colab's CPU. Module 9's grounding checks also download cross-encoder/nli-deberta-v3-base (about 740 MB), pinned to revision 6c749ce3425cd33b46d187e45b92bbf96ee12ec7. Single lessons name and load other models once, for comparison only: BAAI/bge-reranker-base, Snowflake/snowflake-arctic-embed-xs, mixedbread-ai/mxbai-embed-xsmall-v1, intfloat/multilingual-e5-small, sentence-transformers/all-MiniLM-L6-v2, sentence-transformers/paraphrase-MiniLM-L3-v2, answerdotai/answerai-colbert-small-v1, rasyosef/splade-mini and ibm-granite/granite-docling-258M.
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 rag-course
cd rag-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 ipykerneland the course's extra libraries, at the versions in the table above:
pip install sentence-transformers==6.1.0 langchain-huggingface==1.2.3 langchain-core==1.6.8 langchain-text-splitters==1.1.3 langchain-classic==1.0.8 rank-bm25==0.2.2 nltk==3.10.3 chromadb==1.5.9 faiss-cpu==1.15.1 hnswlib==0.8.0 qdrant-client==1.19.1 lancedb==0.40.0 sqlite-vec==0.1.9 pgserver==0.1.4 "psycopg[binary]==3.3.6" pgvector==0.5.1 beautifulsoup4==4.15.0 trafilatura==2.3.1 pypdf==6.20.0 pdfplumber==0.11.10 pypdfium2==5.14.0 fpdf2==2.8.9 pytesseract==0.3.13 python-docx==1.2.0 python-pptx==1.0.2 openpyxl==3.1.5 docling==2.137.0 datasketch==2.0.0 pydantic==2.14.0 pytest==9.1.1 tiktoken==0.14.0 networkx==3.7 opentelemetry-sdk==1.45.1 opentelemetry-exporter-otlp-proto-http==1.45.1 fastapi==0.143.0 uvicorn==0.54.0 httpx==0.28.1Module 2's OCR step also needs the Tesseract engine itself, which pip does not install: brew install tesseract on macOS, sudo apt install tesseract-ocr on Ubuntu (Tesseract's installation page, https://tesseract-ocr.github.io/tessdoc/Installation.html, checked 12 October 2026, lists Debian packages and other systems).
Keys 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-06-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 loads FAISS next to an embedding model from Module 5 on; its own tests ran on a Mac with both set. You do not need this in Colab.
From notebook cells to a project
In a job you would not keep code in notebook cells. The course grows one repository, hollin-answers, with a single package called hollin/. The Module 1 lab starts it: the setup cell becomes hollin/llm.py with the llm object created once and the ask() guard (the HOLLIN_PROVIDER environment variable switches provider without editing the file), the shared data becomes hollin/data.py, and a tests/ folder holds the checks as pytest tests. Each module adds its piece inside the same package (hollin/ingest/, hollin/chunk/, hollin/stores/ and so on), and Module 14's capstone wraps it in a FastAPI service as hollin/api/. In Colab the repository lives in your Google Drive (the Module 1 lab mounts it), so it survives between sessions; each later lab writes an earlier module's file only when it is missing, as an exact copy of that module's file. Labs that must run in a temporary folder for testing create hollin/ there with the same layout and say so. The project page (course-guide/03) lists which module adds which file.
PostgreSQL versions
The course's PostgreSQL code (Module 5 and the Module 14 capstone, with the pgvector extension) runs on PostgreSQL 16 to 18. Nothing in the lessons depends on the difference.
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 |