Back to course overview
Module 1Why LLMOps 20 min

Lab: Baseline a system

Stand up the course project, pick the AI feature you'll operate, and take an honest first measurement — the baseline every later module improves on.

You can't operate what you haven't measured. This lab establishes your baseline: the AI feature under management, a first golden set, and its honest current numbers. Everything in the course is measured against this.

A runnable, offline-tested starter kit ships with this course

course-assets/llmops/ is the whole ops layer, runnable end to end with no API key. It wraps a small Harbor Lane email-triage feature (triage.py, exposing run_feature(input) -> {category, urgency, reply}) behind the exact artifacts you'll build: the harness (evalharness.pyrun_evals), the tracer (trace.pyTracer + call_cost), the CI gate (run_evals.pyreport.jsoncheck_gate.py), and the workflow (.github/workflows/evals.yml). The harness math, the tracer's span tree and cost arithmetic, and the gate's exit codes are tested offline (python3 tests/test_offline.py, 53 assertions) against a deterministic stub feature — no key needed. The LLM-judge (faithfulness_check) and the real Anthropic-backed feature are shipped correct-by-construction but need your own ANTHROPIC_API_KEY; they are not run by the offline suite. Use it as the reference implementation for every lab — the file and function names below match it exactly. You still bring your own real feature to operate (the kit's stub is the same run_feature stub Step 1 recommends if you have no prior project).

Step 1 — Choose your system

Honest framing: no mock is shipped with this course. You bring a working AI feature from a prior course and wrap it behind one entry point — everything the course builds assumes that entry point exists.

  • Best: a project you built in a prior course — the triage assistant (Prompt Engineering), HarborDocs (RAG), or the resolution agent (Agentic AI). You know its guts, which makes the ops work concrete.
  • Whichever you bring, get it running end to end from one function call — run_feature(input) -> output — before going further. That single entry point is what everything wraps.
  • No prior project handy? Stub run_feature with a canned dict so the ops layer is still exercisable (shape below), then swap in a real feature later — the harness, tracer, and gates don't care which is behind the entry point.
feature.pypython
def run_feature(input: str) -> dict:
    # Wrap your real prior-course feature here (triage / HarborDocs / agent).
    # No feature yet? Stub it so the ops layer is exercisable, swap in later:
    return {"category": "billing", "urgency": "low", "reply": "..."}
If you hit a model-not-found error

The labs use the house model id claude-sonnet-5. If your SDK reports that id as not found, replace it with a current Anthropic model id from the docs (docs.anthropic.com) — the model list moves faster than course text.

Step 2 — Assemble a starter golden set

  1. 1Collect 15 realistic inputs for your feature. Reuse cases from the prior course if you have them; otherwise write them across the archetypes you know (routine, boundary, adversarial, unanswerable).
  2. 2Write the expected output (or the pass/fail criteria) for each. This is the same golden-set discipline — the arguments about hard cases are the point.
  3. 3Save as golden/v1.jsonl: one JSON object per line, {id, input, expected, notes}. JSONL because you'll append to it all course as production surfaces new failures.

Step 3 — The honest baseline measurement

baseline.pypython
import json, time
from feature import run_feature   # your one entry point

def baseline(golden_path: str):
    rows = [json.loads(l) for l in open(golden_path)]
    results = []
    for r in rows:
        t0 = time.time()
        out = run_feature(r["input"])          # run it for real
        results.append({"id": r["id"], "input": r["input"],
                        "expected": r["expected"], "output": out,
                        "latency_s": round(time.time() - t0, 2)})
    json.dump(results, open("baseline_results.json", "w"), indent=2)
    print(f"ran {len(results)} cases — now GRADE them by hand")
  1. 1Run it. Then grade each output by hand: pass / fail, and a one-word failure reason for the fails. Resist automating the grading yet — Module 2 does that; today you feel the ground truth yourself.
  2. 2Compute three numbers: pass rate, median latency, and (from the API response usage) rough tokens-per-call. Write them at the top of BASELINE.md.
  3. 3Run the whole set a SECOND time. Compare: how many outputs changed? That number — the non-determinism you just measured directly — is why this course exists.
Problem set 1

In the workbook: four 'green dashboard, broken feature' incident reports (uptime 100%, users furious). For each, name which of the four reliability-gap sources caused it and which station of the LLMOps loop would have caught it first.