Module 8 β AI EngineeringΒΆ
Goal: Use LLMs from Python as engineered, observable, evaluated components β not as magic. By the end of this module you can build, test, and ship an AI feature.
Estimated time: 8β10 hours.
Prerequisites: Modules 1β2 (functions, JSON, HTTP). Module 5 is helpful for the evaluation chapter.
ββββββββββββββββββββββββββββββββββββββ
β NB 27 β LLM fundamentals: β
β the LLM as a next-token loop β
β (tokens, attention, prompting) β
βββββββββββββββββββ¬βββββββββββββββββββ
β
βββββββββββββββββββββ¬ββββββββ΄ββββββββ¬ββββββββββββββββββ
βΌ βΌ βΌ βΌ
NB 28 NB 29 NB 30 NB 31
prompts + embeddings tools + document
structured + RAG agents processing
output
βββββββββββββββββββββ΄ββββββββ¬ββββββββ΄ββββββββββββββββββ
βΌ
NB 32 β evaluation
golden sets, LLM-as-judge,
cost dashboards, regression tests
Notebooks at a glanceΒΆ
# |
Notebook |
β± Time |
Difficulty |
What youβll build |
|---|---|---|---|---|
21 |
|
~75 min |
Intermediate |
The theory floor: tokens, next-token prediction, the Transformer & attention, prompting techniques, hallucinations & knowledge cutoff β told through βHelpaβ |
22 |
|
60β90 min |
Intermediate |
Helpaβs first real code: prompt patterns, safe JSON output, inbox batch classification, keyword RAG (offline MockLLM) |
23 |
|
70β90 min |
Intermediate |
A semantic retriever: TF-IDF + dense embeddings, retrieval@k / MRR benchmark, end-to-end RAG + a Ragas answer-quality eval |
24 |
|
60β80 min |
Intermediate |
A multi-tool support-ops data assistant (call β execute β return loop, safety budget, trace log) |
25 |
|
60β75 min |
Intermediate |
An invoice-extraction pipeline: extract β chunk β LLM-extract β validate β DataFrame |
26 |
|
55β70 min |
Intermediate |
An eval harness: golden set, LLM-as-judge, tracing, cost dashboard, A/B test, regression detection |
Optional appendices at a glanceΒΆ
Appendix |
Notebook |
β± Time |
Focus |
|---|---|---|---|
A1 |
|
30β45 min |
OpenAI / Anthropic / Google / Ollama behind one |
A2 |
|
45β60 min |
FAISS, Chroma, Qdrant, Weaviate, Pinecone, Milvus, pgvector β index families + a 4-question decision rubric |
A3 |
|
45β60 min |
LangChain, LlamaIndex, Haystack, DSPy, smolagents, AutoGen, CrewAI β the same RAG task in each + a 3-question rubric |
Notebook guidesΒΆ
27 Β· LLM Fundamentals β 27_llm_fundamentals.ipynbΒΆ
Module 8 opens with the question every learner asks first: what is an LLM actually doing inside? This is the theory notebook (NB 28β32 are the hands-on ones), built around one mental model β an LLM is a next-token predictor run in a loop (sample β append β repeat) β and one running example: Helpa, an AI customer-support assistant youβve been asked to build for a small SaaS company. Tokens become Helpaβs monthly bill, attention becomes how Helpa reads a question, hallucinations become the support reply that invents a product that doesnβt exist.
The concepts are prerequisite-free (you can read it early, alongside 00c); the light maths in Β§4 and Β§6 lands more easily after the vectors of NB 29, so skim those on a first pass if needed. By the end youβve diagnosed exactly why a βJust LLMβ Helpa hallucinates β and NB 28β30 become the cure.
Learning objectives:
Explain what a Large Language Model is and how it generates text, one token at a time.
Distinguish tokens, parameters, and the training objective (next-token prediction with cross-entropy loss).
Describe the Transformer architecture and the Attention mechanism (Q/K/V) in your own words.
Distinguish pre-training, fine-tuning, and prompting β three different intervention points.
Name five prompting techniques and pick the right one for a given task.
Identify the two structural limitations (hallucinations, knowledge cutoff) and explain why they exist.
Sections: 1 What is a Large Language Model? Β· 2 How LLMs see text: tokens Β· 3 What are parameters? Why βlargeβ? Β· 4 The training objective: next-token prediction Β· 5 The architecture: the Transformer Β· 6 The Attention mechanism Β· 7 Pre-training, fine-tuning, prompting Β· 8 Common prompting techniques Β· 9 Limitation 1 β hallucinations Β· 10 Limitation 2 β knowledge cutoff Β· 11 Mental model β the three levels of LLM usage
Practice: 4 β quick checkpoints Β· 5 π§ͺ practice exercises (incl. a Debug me π) Β· 4 π§ stretch exercises Β· π bonus mini-project: a token-budget calculator.
Files/datasets: none β the next-token loop, temperature dial, and attention demos are toy models built in-notebook with NumPy/matplotlib. No LLM calls at all.
28 Β· AI-Assisted Workflows β 28_ai_workflows.ipynbΒΆ
The bridge between everything youβve learned and what modern AI-driven work looks like β and the notebook where Helpa stops being a thought experiment and becomes Python. One mental model carries the whole lesson: an LLM call is just a function call, reply = f(messages); every pattern (system prompts, JSON output, batch loops, retrieval) is plumbing around that one call.
You write prompts that are reliable, not just clever: the four core prompt patterns, defensive JSON parsing, a KPI report over a classified feedback inbox, and Helpaβs first grounded answer via a tiny keyword-retrieval workflow. The final section shows how to go live with OpenAI or Anthropic β the calling code is identical to the mock.
Learning objectives:
Explain what happens when you βcall an LLMβ β itβs just a function call.
Use the system / user / assistant message structure correctly.
Apply the four core prompt patterns: instructions, few-shot, structured output, chain-of-thought.
Parse JSON output safely with
try / except.Classify and summarise a batch of records and report the results.
Build a tiny retrieval workflow (keyword RAG) and reason about cost, latency, and evaluation.
Sections: 1 An LLM call is just a function call Β· 2 Our offline MockLLM Β· 3 Your first prompt β system + user messages Β· 4 The four core prompt patterns Β· 5 Batch processing β classify a whole inbox Β· 6 A tiny retrieval workflow Β· 7 Cost, latency, evaluation β the engineerβs checklist Β· 8 Going live with a real model
Practice: 4 β quick checkpoints Β· 3 π§ͺ practice exercises Β· 4 π§ stretch exercises Β· π bonus mini-project: an inbox-triage CLI.
Files/datasets: offline MockLLM imported from the repo-root llm_providers.py β no API key, no internet. The customer-feedback batch is defined in-notebook.
29 Β· Embeddings and Semantic Retrieval β 29_embeddings_retrieval.ipynbΒΆ
NB 28βs keyword RAG has a glaring weakness: βhow do I end my plan?β wonβt match a document about βcancelling your subscriptionβ β so Helpa shrugs, or invents an answer. This notebook fixes that with a semantic retriever, under the mental model meaning becomes geometry: embeddings turn texts into arrows, and retrieval is βwhich stored arrow points most like my query arrow?β. One query pair runs through everything: βHow do I cancel my subscription?β vs. its evil twin βHow can I end my plan?β.
You build TF-IDF and dense-embedding retrievers, run a head-to-head evaluation of keyword vs TF-IDF vs dense on the same test set, and finish with an upgraded end-to-end RAG plus a Ragas-style evaluation of the whole pipeline β faithfulness, answer relevancy, context precision/recall, taught with an offline mock judge and real ragas reference code. Every piece of a production-grade RAG system except the vector database (which A2 covers).
Learning objectives:
Explain what an embedding is and what cosine similarity measures.
Build a TF-IDF retriever with scikit-learn (offline, no API calls).
Build an embedding-based retriever with a deterministic offline fallback.
Compute retrieval@k and MRR to evaluate retrievers.
Compare keyword vs TF-IDF vs dense retrieval on the same test set.
Combine retrieval with an LLM β and recognise the failure modes (synonyms, paraphrase, domain jargon).
Evaluate the whole RAG pipeline with Ragas metrics β faithfulness, answer relevancy, context precision/recall.
Sections: 1 What is an embedding? Β· 2 Setup Β· 3 Baseline β keyword overlap (the NB 28 approach) Β· 4 TF-IDF β a stronger lexical baseline Β· 5 Dense embeddings β semantic similarity Β· 6 Plugging in a real embedding model (reference) Β· 7 Evaluating retrievers β retrieval@k and MRR Β· 8 Where keyword wins and dense loses Β· 9 End-to-end RAG with the new retriever Β· 10 Evaluating the whole pipeline β Ragas
Practice: 5 β quick checkpoints Β· 4 π§ͺ practice exercises (incl. a Debug me π) Β· 4 π§ stretch exercises Β· π bonus mini-project: a confidence threshold that refuses out-of-corpus questions gracefully.
Files/datasets: offline throughout β a minimal in-notebook MockLLM plus the deterministic MockEmbedder from the repo-root llm_providers.py; the document corpus is defined in-notebook. Real options (OpenAI embeddings, sentence-transformers) are shown as reference code.
30 Β· Tool Calling and Small Agents β 30_tools_and_agents.ipynbΒΆ
So far the LLM took text and returned text. Here you give it tools β functions it can decide to call β and watch it do multi-step work. The mental model is planner + hands + a while loop: the model is the planner (it only ever asks), your code is the hands (it acts), and the loop is the agent. βTool callingβ, βfunction callingβ, βagentsβ, βReActβ are all brand names for this one machine.
The running example is a support-ops data assistant: a ~100-line program that answers business questions (βhow many tickets in total?β, βwhich channel is cheapest?β) by running pandas queries on its own β assembled one tool at a time, with a safety budget and a debuggable trace.
Learning objectives:
Define a tool with a JSON schema the model can read.
Run the call β execute β return loop manually, step by step.
Build a multi-tool agent that picks the right tool for each question.
Add a safety budget (max steps, max tool calls) to prevent runaway loops.
Log every tool call so you can debug what the agent did.
Recognise when an agent is overkill β and when a single LLM call is enough.
Sections: 1 The tool-calling loop in one picture Β· 2 Setup β a richer MockLLM that understands tools Β· 3 Tool schemas β what the model needs to know Β· 4 One round of tool calling β manually Β· 5 Wrapping the loop in a function Β· 6 Inspecting the trace β debugging an agent Β· 7 A multi-step agent β calculator chain Β· 8 When NOT to use an agent Β· 9 Going live β the real-provider sketch
Practice: 4 β quick checkpoints Β· 4 π§ͺ practice exercises (incl. a Debug me π) Β· 4 π§ stretch exercises Β· π bonus mini-project: a pandas-query tool.
Files/datasets: a tool-aware MockLLM defined in-notebook (offline, no API key); the support_ops DataFrame is generated in-notebook (same shape as NB 13βs table).
31 Β· AI Document Processing β 31_document_processing.ipynbΒΆ
A huge fraction of business work is extracting structured information from unstructured documents β invoices, receipts, contracts, KYC forms. The mental model is an assembly line: a raw document rolls through extract β chunk β LLM-extract β validate β aggregate, and a tidy database row rolls out; validation is the quality-control inspector at the end of the belt.
The running example is an invoice parser: a finance-ops tool that turns a stack of messy free-form invoices into a clean table of (vendor, total, due_date, line_items) records you can sum, group, and bill from β finished off with field-level accuracy against a labelled set and a ranked vendor report.
Learning objectives:
Extract text from a PDF (
pypdf) β and handle multi-page documents.Chunk text into LLM-sized pieces, respecting sentence boundaries.
Use structured-output prompting to extract typed fields.
Validate the modelβs output with JSON Schema and Pydantic-style checks.
Compute field-level accuracy against a labelled set.
Aggregate extracted records into a pandas DataFrame β and recognise the pitfalls (low-confidence fields, missing data, table extraction).
Sections: 1 The shape of every document-processing pipeline Β· 2 Setup Β· 3 Generate a small set of synthetic invoices Β· 4 Chunking β when documents are too big for one prompt Β· 5 Extracting structured fields with the LLM Β· 6 Validating the extracted fields Β· 7 Building the final DataFrame Β· 8 Line-item drill-down Β· 9 Field-level accuracy Β· 10 Common pitfalls
Practice: 3 β quick checkpoints Β· 4 π§ͺ practice exercises (incl. a Debug me π) Β· 4 π§ stretch exercises Β· π bonus mini-project: a βmonthly billing reportβ.
Files/datasets: the invoices are synthesised in-notebook (no external files); an inline invoice-extractor MockLLM keeps it offline. pypdf (and OCR options for scans) appear as reference snippets for real PDFs.
32 Β· AI Evaluation & Observability β 32_ai_evaluation_observability.ipynbΒΆ
You shipped an AI feature in NB 28β31 and the demo answers looked great β but how do you know it still works after someone tweaks a prompt or the provider updates the model? This notebook is βthe difference between hobby AI and production AIβ. Mental model: an eval is a regression test for something that wonβt sit still β a smoke detector bolted to your feature, silent on a good day, the only thing that wakes you up on a bad one.
The running example is an inbox-triage feature that tags customer messages with a sentiment and a topic. Against it you build the whole observability stack: a 12-example golden set, per-class metrics, an LLM-as-judge (with its known biases, validated against human labels), call tracing, a cost dashboard, an A/B test of two prompt variants, and regression detection β assembled into one eval pipeline.
Learning objectives:
Build a golden dataset for an AI feature and re-run it on every change.
Choose the right metric: exact-match, structured-output match, semantic similarity, LLM-as-judge.
Implement call tracing so every prompt + response is logged.
Compute a cost dashboard from a trace log.
Run an A/B test of two prompt variants and reach a defensible verdict.
Detect regression (a new prompt makes things worse on previously-passing examples).
Sections: 1 Why βlook at it and it seems fineβ doesnβt scale Β· 2 Setup β the MockLLM and a tiny golden dataset Β· 3 Run the feature and score it Β· 4 Per-class metrics Β· 5 LLM-as-judge (+ Ragas, the packaged judges for RAG) Β· 6 Tracing β log every call Β· 7 The cost dashboard Β· 8 A/B-testing two prompt variants Β· 9 Regression detection Β· 10 Putting it together β the eval pipeline
Practice: 4 β quick checkpoints Β· 3 π§ͺ practice exercises Β· 4 π§ stretch exercises Β· π bonus mini-project: a pre-commit eval check.
Files/datasets: an inline MockLLM and a 12-example golden set built in-notebook (offline, no API key); the real-provider swap is one line via ../llm_providers.py, documented in appendix A1.
Appendix guidesΒΆ
Appendices are reference-style: demo/survey notebooks without the full exercise scaffolding, and every one runs end-to-end offline β real-library cells fall back to a built-in stand-in or appear as commented reference code.
A1 Β· LLM Providers Guide β A1_llm_providers_guide.ipynbΒΆ
The reference for swapping the courseβs MockLLM for real intelligence. Surveys the four providers wired into the repo-root llm_providers.py β π’ OpenAI, π Anthropic (Claude), π΅ Google (Gemini), π£ Ollama (fully local) β all sharing the same chat() interface, so swapping providers in NB 27β32 (and the NB 48 capstone) is a one-line change. Covers install/auth for each, common model lists, a side-by-side comparison on the same task, back-of-envelope cost estimation, the embedding equivalents for NB 29 (hosted vs sentence-transformers vs MockEmbedder), and production patterns (retries, caching, fallbacks).
Decision guidance: a provider decision table over cost, latency, quality, and data-privacy constraints β plus how to size a local Ollama model to your RAM. 3 β quick checkpoints and 3 exercises (provider-swap drill, cost estimate for your own workload, a local-first dev workflow).
A2 Β· Vector-Store Landscape β A2_vector_stores_survey.ipynbΒΆ
Picks up where NB 29βs hand-rolled NumPy retriever hits its limits (latency, memory, operability) and surveys the vector-store field: index families first (IVF, HNSW, PQ), then FAISS (the workhorse local index, with an HNSW walk-through), Chroma (simplest embedded option), Qdrant (production-flavoured), Weaviate / Pinecone / Milvus (the rest of the field), and pgvector (βthe boring-good choice when you already have Postgresβ) β closing with what LangChain / LlamaIndex / Haystack retrievers actually wrap. Runs offline on the course MockEmbedder; each storeβs real client code is shown as commented reference.
Decision guidance: a 4-question rubric β scale, hosting, filtering, ecosystem β so you can pick a store from constraints instead of hype. 3 β quick checkpoints and 2 exercises (metadata filtering on the FAISS stand-in, recall-vs-k measurement).
A3 Β· RAG & Agent Frameworks β A3_rag_and_agent_frameworks.ipynbΒΆ
NB 29 built RAG by hand and NB 30 built agents by hand β so why do frameworks exist? Answer: when your pipeline grows past hand-rolled and you want batteries β loaders, retrievers, tracing, evaluation, deploy β without writing them yourself. This is a code-level tour of the major frameworks against the same FAQ-with-citations RAG task: a plain-Python baseline, then LangChain (LCEL pipes), LlamaIndex (retrieval-first), Haystack (production pipelines), DSPy (programmatic prompting), and the agent frameworks β smolagents, AutoGen, with CrewAI in the comparison table β plus a note on judging any of them with the same framework-agnostic Ragas eval. Runs offline via MockLLM/MockEmbedder; framework snippets are reference code.
Decision guidance: a 3-question rubric for picking a framework β or not picking one and shipping faster. 3 β quick checkpoints and 2 exercises (translate the baseline to LCEL style, frame an agent task as a state machine).
The 5 disciplines this module trainsΒΆ
Treat the LLM as a function call. Typed inputs, structured outputs, retries, costs.
Always wrap
json.loadsintry/except. Real models occasionally misbehave.Confidence thresholds beat hallucination. Refuse weak retrievals before they become wrong answers.
Tools, not free-form generation. When the answer is computable, compute it β donβt ask the LLM.
Eval set first, prompt iteration second. Otherwise every βimprovementβ is a guess.
How these notebooks workΒΆ
Every notebook runs 100% offline β a deterministic MockLLM (and MockEmbedder) stands in for real providers, so you need no API key, no internet, and no credit card; when you want real answers, the swap is one import via the repo-root llm_providers.py (appendix A1 is the guide). Each lesson opens with a Colab badge and a time/difficulty line, then follows the course rhythm: β Quick exercise (~2 min) checkpoints with collapsible solutions as you go, end-of-lesson π§ͺ practice exercises (β-rated, usually including a βDebug me πβ), π§ stretch exercises, and a π bonus mini-project. The three appendices are optional reference surveys β skip them on a first pass, return when youβre choosing a real provider, vector store, or framework.
Where nextΒΆ
β Module 13 β Production (../13_production/45_from_notebook_to_project.ipynb)
π Finished this module? Test yourself with the Module 8 quiz β five questions, ~10 minutes.