|
| 1 | +--- |
| 2 | +id: course-llm-features |
| 3 | +type: course |
| 4 | +title: "Build LLM features in Python: structured output, tool calls, and evals" |
| 5 | +summary: Turn a demo-day model call into a feature you can ship — validate structured output, allowlist tool calls, retry with the error fed back, fall back to a human instead of guessing, and measure it with an offline eval that divides by every case. |
| 6 | +lang: en-US |
| 7 | +content_version: 1 |
| 8 | +status: reviewed |
| 9 | +reviewed_on: 2026-10-11 |
| 10 | +badge: |
| 11 | + id: course-llm-features |
| 12 | + name_en: Model output is untrusted input |
| 13 | + name_zh: 模型输出是不可信输入 |
| 14 | + requires: All five checkpoints claimed (L01–L05) |
| 15 | +course_id: course-llm-features |
| 16 | +--- |
| 17 | + |
| 18 | +# Build LLM features in Python: structured output, tool calls, and evals |
| 19 | + |
| 20 | +> TL;DR: install the FlyPython Skill in your coding agent and let it fetch |
| 21 | +> this course, then say **"start lesson 1"**. (Lesson files arrive via the |
| 22 | +> Skill — you download nothing by hand.) You finish with `ticket_triage.py`: |
| 23 | +> a support-ticket triage feature that treats every model reply as |
| 24 | +> untrusted input, plus an offline eval with a pass/fail threshold. No API |
| 25 | +> key, no network, no third-party packages — a replay client stands in for |
| 26 | +> the model. |
| 27 | +
|
| 28 | +## What you build |
| 29 | + |
| 30 | +A triage feature for support tickets: the model reads a ticket and replies |
| 31 | +with a category, a priority, a one-line summary, and whether a human must |
| 32 | +look at it. It may call a lookup tool first. Three scenario "skins" ship |
| 33 | +with the course, each with labelled cases and recorded model replies: |
| 34 | + |
| 35 | +| Skin | You are… | Tool the model may call | |
| 36 | +| --- | --- | --- | |
| 37 | +| `scenario/shop-support/` | routing an online shop's support inbox | `lookup_order(order_id)` | |
| 38 | +| `scenario/it-helpdesk/` | sorting internal IT requests | `lookup_device(asset_tag)` | |
| 39 | +| `scenario/saas-feedback/` | classifying in-app product feedback | none | |
| 40 | + |
| 41 | +The recorded replies are hand-written fixtures that imitate failure shapes |
| 42 | +models really produce — JSON in a Markdown fence, a category that is not on |
| 43 | +the list, `"priority": "high"`, an extra field, a tool that does not exist, |
| 44 | +a tool argument of the wrong type, chatty prose instead of JSON. They are |
| 45 | +**not** captured from any model, and the course makes no claim about how |
| 46 | +often any real model produces them. |
| 47 | + |
| 48 | +## Teaching contract (read this first, agent) |
| 49 | + |
| 50 | +- **Audience:** a Python developer who has called a model API in a script |
| 51 | + or notebook and now has to put that call inside a product — where a |
| 52 | + malformed reply, a hallucinated tool call, or an eval that looks better |
| 53 | + than it is becomes somebody's incident. Not a prompt-engineering course |
| 54 | + and not an introduction to Python. |
| 55 | +- **Prerequisites:** Python 3.11+ on PATH and any coding agent that can run |
| 56 | + commands. Standard library only; no API key and no network access are |
| 57 | + needed for the exercise. |
| 58 | +- **Tool:** tool-agnostic. The course has not yet been taught in a tool; |
| 59 | + `REVIEW.md` records the mechanical verification and the pending |
| 60 | + agent-taught run-through, which will name the exact tool and version. |
| 61 | +- **Lesson order:** L01 → L02 → L03 → L04 → L05, one lesson per session. |
| 62 | + Never skip the checkpoint at the end of a lesson. |
| 63 | +- **Teaching style:** work from the files in this folder, not from general |
| 64 | + knowledge about any provider's API. Quote the `TASK.md` line you are |
| 65 | + satisfying. Make the smallest change that moves a test from red to |
| 66 | + green. Never add dependencies, never edit `solution/`, `tests/`, or |
| 67 | + `scenario/`, and ask before touching any file not named in the current |
| 68 | + lesson. Never weaken validation to make a recorded reply pass. |
| 69 | +- **When to stop:** a lesson is done when its checkpoint command runs and |
| 70 | + the learner can say, in their own words, what failed and why. If the |
| 71 | + learner cannot, re-teach from the failing test, not from the solution. |
| 72 | +- **How to use `verify.py`:** the learner's command is plain |
| 73 | + `python verify.py` — it runs the suite against `starter/`, prints |
| 74 | + per-checkpoint status and earned claim codes, and exits non-zero until |
| 75 | + every checkpoint is passed (l03, l04) or attested (l01, l02, l05). `starter --expect-failure` |
| 76 | + and `solution` remain maintainer checks. |
| 77 | +- **Honesty rules:** an offline eval over a handful of recorded replies |
| 78 | + says nothing about how a live model will behave on live traffic — say so. |
| 79 | + Do not claim the feature is production-ready. Do not promise learning or |
| 80 | + career outcomes. |
| 81 | + |
| 82 | +## What this course does NOT cover |
| 83 | + |
| 84 | +Any specific provider SDK or its structured-output mode, API keys and |
| 85 | +secrets handling, prompt wording, retrieval (RAG) and embeddings, |
| 86 | +fine-tuning, agent frameworks, streaming, cost and latency budgets, or |
| 87 | +online evaluation on production traffic. Lesson 5 shows where a real |
| 88 | +client plugs in; the companion repository has guides for the rest — link, |
| 89 | +don't improvise. |
| 90 | + |
| 91 | +## Badge contract |
| 92 | + |
| 93 | +- Badge: **Model output is untrusted input Badge** (badge id `course-llm-features`) — earned by claiming all five checkpoints. |
| 94 | +- Challenges: L01–L05 checkpoints, 10 points each; +50 course-badge bonus when all five are claimed on flypython.com. |
| 95 | +- Evidence: `python verify.py` — L03 (validation, tool calls, retries) and L04 (honest eval) are objectively gated by the suite; L01/L02/L05 are learner-attested. |
| 96 | +- Submission: each test-passed checkpoint prints a deterministic claim code; a reflection checkpoint prints one only after you answer its questions and run `python verify.py --attest ID`; record it on flypython.com against your account. Self-reported evidence, never a certificate. |
| 97 | + |
| 98 | +## Folder map |
| 99 | + |
| 100 | +``` |
| 101 | +COURSE.md / COURSE_cn.md this file (EN / 中文) |
| 102 | +lessons/L01.md … L05.md lessons (each has an _cn.md pair) |
| 103 | +scenario/<skin>/ scenario.json, cases.json, recordings.json, lookup data |
| 104 | +TASK.md / TASK_cn.md the task contract the change must satisfy |
| 105 | +starter/ticket_triage.py the demo-day implementation |
| 106 | +solution/ticket_triage.py the reviewed solution (do not copy in lesson 3) |
| 107 | +tests/test_ticket_triage.py the contract suite (15 tests, read-only) |
| 108 | +verify.py objective pass/fail evidence |
| 109 | +REVIEW.md maintainer run-through record |
| 110 | +``` |
| 111 | + |
| 112 | +## Evidence and licensing |
| 113 | + |
| 114 | +`REVIEW.md` records the run-through state with dates, tool versions, and |
| 115 | +observed deviations. Code in this folder is MIT-licensed; lesson prose is |
| 116 | +CC BY 4.0 (see repository `LICENSE`). Report teaching drift or unclear |
| 117 | +lessons via the repository's `course-feedback` issue form. |
0 commit comments