04 Release to production
Instructor notes for module 04 — timing, talk track, common failures, and reset steps.
Facilitator companion to the learner lesson 04 Release to production.
Timing
~15 minutes total.
- 3 min — start the serving API (
uvicorn serving.api:app --port 8100). - 2 min — a raw
curlagainst/ask. - 4 min — start the web Chat tab and ask a question through the UI, click 👍/👎.
- 6 min — tour LangFuse: Traces filtered by tag
serving, Sessions, cost/latency, theuser_feedbackscore.
Talk track
- Open by naming the reuse, again: the serving API runs the exact same
agents/core andagents/sqlguard.pyread-only sandbox as the benchmark harness. What Modules 01–02 measured is what's about to run live — there is no separate "eval harness" that quietly diverges from what ships. - Frame the shift in question this module represents: from "which config is best?" (a Module 01 question, answered once) to "is it still working, and for whom?" (an ongoing question this module hands off to).
- The load-bearing sentence for this whole module: it's the same LangFuse project. Not a new observability stack — the Traces and Sessions views you're about to open are the same project connected in Module 00 and used to run the Arena in Module 01. Dev and production are two points in one continuous loop, not two different tools.
- When you
curl/ask, point out the response shape live: SQL, result rows,cost_usd,latency_ms,outcome, and atrace_id— say thattrace_idis exactly what an annotation-queue reviewer would open in Module 03's loop. - In the Chat tab, click a 👍 and a 👎 live and then find both as
user_feedbackscores on their traces in LangFuse — this is the moment the audience sees the improvement loop's input actually being produced, not just described. - Close on the "what to watch for" list from the learner module — negative feedback clusters, cost/latency drift, error outcomes — and tie each one explicitly back to Module 03 (triage into the annotation queue) or Module 01 (re-run the Arena if pricing or the model roster changed).
Common failures
- Placeholder
OPENROUTER_API_KEY—/askcalls fail with a401from OpenRouter, surfaced as a 500-ishoutcomein the response rather than a clean error; this should have been caught in Module 00, but if it wasn't, this is where it becomes visible to end users. - Serving API not running / wrong port — the web Chat tab talks to
VITE_SERVING_BASE(defaults tohttp://localhost:8100); ifuvicorn serving.api:appisn't up, or is up on a different port than the UI expects, the Chat tab shows a network/fetch error, not a helpful message. Confirm the port matches on both sides. - CORS —
serving/api.pyallows all origins by default, so CORS itself is unlikely to be the blocker; if the Chat tab still errors, look first at whether the serving process is actually running before chasing CORS. - Stale/invalid
config_id—/askneeds aconfig_idthat matches<model>__<prompt>from Module 01's winner (e.g.claude-sonnet-5__P1_zeroshot); a typo'd or outdatedconfig_id(from a different demo run) fails immediately. - ClickHouse not seeded —
/askqueries thev_*views through the read-onlyarena_rouser; if Module 00 didn't finish, questions return empty results or errors instead of real answers. - No LangFuse trace showing up — confirm
.env'sLANGFUSE_*vars are sourced in the same shell that starteduvicorn; a missing key doesn't crash the server, it just silently drops tracing.
Reset steps
- If ClickHouse or the local dashboard needs a clean base first:
scripts/arena.sh up. - Restart the serving API:
source .env && uvicorn serving.api:app --port 8100(kill any prior instance on that port first if it's wedged). - Restart the web Chat tab:
cd web && VITE_SERVING_BASE=http://localhost:8100 npm run dev. - Re-verify with a fresh
curl:curl -s localhost:8100/ask -H 'content-type: application/json' -d '{"question":"How many customers are there?","config_id":"claude-sonnet-5__P1_zeroshot"}'— swap in whateverconfig_idModule 01 actually crowned for this room. - If the demo needs fresh Leaderboard/trace data to point at during the LangFuse tour,
re-run a cheap subset first:
python -m eval.harness --run-id demo2 --models qwen3.7-flash,gpt-5.6-luna --prompts P1_zeroshot,P3_dialect.