Build LLM features in Python: structured output, tool calls, and evals · Challenge 05

Lesson 5: Apply it to your own LLM feature

Checkpoint l0510 ptsself-reported — code from verify.pyAny coding agent + a recorded model replay (no API key)

Put a real model behind the same seam: a client callable, an output contract, an allowlist, a fallback, and an eval you record once and replay on every change.

Doing this with your agent? One sentence starts the whole course:

Read https://flypython.com/skills/flypython/SKILL.md and start the FlyPython course `llm-features-in-python`.

Lesson 5: Apply it to your own LLM feature

Objective

You apply the pattern — output contract, validated parsing, tool allowlist, retry and fallback, an honest offline eval — to a model call in a project you own, and record what the eval said.

Why this lesson exists

The course used hand-written replies so it could run anywhere, offline. Your feature talks to a real model. The pattern transfers because the only thing the code ever depended on was a callable that takes messages and returns text.

The lesson

  1. Wrap your provider behind the seam. Write a function live(messages) -> str that calls your provider’s API and returns the reply text. Read the API key from an environment variable; never put it in code or in a recording.

  2. Write the contract first. Exact fields, types, ranges; the tools and their argument types; the retry count and the fallback. Lesson 2’s exercise is your draft.

  3. Record once, replay on every change. Wrap the live client so each reply is saved, run your labelled cases through it once, then evaluate from the recordings on every later change — no key, no cost, the same answer every time:

    import json
    from pathlib import Path
    
    
    class RecordingClient:
        """Wrap a live client and keep every reply so an eval can replay it."""
    
        def __init__(self, live):
            self.live = live
            self.replies = []
    
        def __call__(self, messages):
            text = self.live(messages)
            self.replies.append(text)
            return text
    
    
    def save_recordings(recorded: dict[str, list[str]], path: Path) -> None:
        path.write_text(
            json.dumps({"replies": recorded}, ensure_ascii=False, indent=2) + "\n",
            encoding="utf-8",
        )
    

    Re-record deliberately — when you change the prompt, the model, or the provider — and compare the new eval line with the old one.

  4. Gate on the eval. Pick a threshold before you look at the result, and make the eval command exit non-zero below it — the same shape as ticket_triage.py.

  5. Record what it does not prove. Write the three lines: verified / not verified / known limits. “Not verified” always includes live traffic you have not recorded.

If your feature does not fit — the output is free text with no fields to validate, or there are too few cases to label — write down where the pattern stopped working. That judgment is part of the skill.

Exercise

Label at least ten real or realistic inputs for your feature before you record anything. Note which ones you expect to fall back.

Checkpoint

This checkpoint is self-attested. When you can answer the questions below, claim it with python verify.py --attest l05:

  1. What does your live client return, and where does its key come from?
  2. What was your first eval line, and did it pass the threshold you chose in advance?
  3. What is on your “not verified” list that a stakeholder would assume was covered?

Expected evidence

Your output contract, your labelled cases, the first eval line, and the three-line record. Keep recordings with customer data out of public repositories.

Hints

Stuck? Open one at a time.

Hint 1 — What this checkpoint tests

Self-attested: you confirm you applied the pattern to a model call you own. The evidence is your contract, your recorded cases, and your eval line — not a code we can check.

Hint 2 — The client is the seam

Everything in this course depends only on client(messages) -> str. A live provider call fits behind that callable; so does a replay of what it said last time.

Hint 3 — Recordings are data

Replies recorded from real traffic can contain customer data. Review them like any other dataset before they go into git.

Submit

Done? Record it.

Use the 8-character code printed by python verify.py. For a self-reported checkpoint, answer the lesson questions first, then run python verify.py --attest l05.

Youbrowser

Submit the claim code

Your agentauto-submit

Let the agent solve and submit

Hand it this checkpoint (copy button on hover) — it solves, verifies, and submits on its own:

Work on the FlyPython challenge "Build LLM features in Python: structured output, tool calls, and evals" (course id course-llm-features), checkpoint l05.
Machine-readable brief: https://flypython.com/api/challenges/llm-features-in-python
Open the course folder and read TASK.md first — it is the contract.
Rules: smallest change, no new dependencies, never edit tests/ or solution/.
Check starter/ with python verify.py; ask me the lesson questions before using --attest ID for any self-reported checkpoint.
Target: solve only checkpoint l05, and submit it as soon as it passes.

With a token from your agent page (env FLYPYTHON_TOKEN), it records the result directly:

curl -X POST https://flypython.com/api/claims \
  -H "Authorization: Bearer $FLYPYTHON_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"claims":[{"course":"llm-features-in-python","checkpoint":"l05","code":"<8-char code>"}]}'

Or install the full FlyPython agent skill once and skip the paste.

Files

The starter and verifier

Solving runs on your machine — your agent fetches the course files itself via /api/challenges/llm-features-in-python/files; you download nothing by hand. Prefer reading the source? Browse the folder on GitHub ↗