Evaluating AI systemsMiddleLesson 2236 min read

Regression tests for prompts and models

A small prompt edit or a model upgrade can quietly break things that used to work. Run your eval suite automatically on every change, with clear thresholds.

Lesson in motion

In 60 seconds

Regression tests for prompts and models

A small prompt edit or a model upgrade can quietly break things that used to work. Run your eval suite automatically on every change, with clear thresholds.

1/4
In simple words
When a railway changes one signal, it checks the whole line, not only that signal. A small change in one place can cause trouble somewhere else. When you change one line of an AI prompt, you must check everything again too.
A regression is something that used to work and now does not. AI systems regress easily: you fix a tone problem in the prompt and the bot starts ignoring the output format; you switch to a newer model and some answers in Bengali get worse. The defence is the same as in normal software: run your tests automatically on every change.

What goes in the eval suite

Type of checkExampleScoring
DeterministicOutput is valid JSON with the required fields; no phone numbers in the replyPass or fail, exact rules
Reference-basedAnswer contains the correct deadline from the referenceMatch against must_include / must_not lists
Judge-basedAnswer is clear and complete by the rubricCalibrated LLM judge (Lesson 5)
SafetyRed-team prompts are refused; normal requests are notRates on two sets (Lesson 9)
Cost and latencyAverage tokens and time per caseMust stay within budget

Thresholds that make sense

  • Hard gates: must-pass items fail the build at once, for example a data leak or broken output format.
  • Floors: each important score must stay above a minimum, per slice (for example, per language).
  • No big drops: compare with the last accepted run; a drop larger than normal run-to-run noise needs a human look.
Note
Model outputs can vary between runs, even with the same input. Measure your noise first: run the suite a few times with no changes and see how much scores move. Set thresholds outside that range, or you will chase false alarms.
Python: a tiny eval runner that fails the build on a regressionpython
import json
import sys

def call_model(prompt: str) -> str:
    ...  # plug in your provider

def check(case, output):
    text = (output or "").lower()
    ok_in = all(p.lower() in text for p in case.get("must_include", []))
    ok_out = not any(p.lower() in text for p in case.get("must_not", []))
    return ok_in and ok_out

def run(cases_path, baseline_path, max_drop=0.03):
    with open(cases_path, encoding="utf-8") as f:
        cases = [json.loads(line) for line in f if line.strip()]
    results = {c["id"]: check(c, call_model(c["input"])) for c in cases}
    score = sum(results.values()) / len(results)
    must_fail = [c["id"] for c in cases if c.get("must_pass") and not results[c["id"]]]
    with open(baseline_path, encoding="utf-8") as f:
        baseline = json.load(f)["score"]
    print(f"score {score:.1%} (baseline {baseline:.1%}), must-pass failures: {must_fail}")
    if must_fail or score < baseline - max_drop:
        sys.exit(1)  # non-zero exit fails the CI job

if __name__ == "__main__":
    run("evals/cases.jsonl", "evals/baseline.json")
Real suites also report results per slice, save every output for later reading, and track cost. But the core idea is this small: run cases, score them, compare with a baseline, fail loudly.

Model upgrades

  1. 1

    Pin the version

    Use a fixed model version where your provider offers one, so the model does not change under you. Check your provider's docs for how versions and retirement dates work.
  2. 2

    Run the full suite on the new model

    Same cases, same judge, same thresholds.
  3. 3

    Compare slice by slice

    Look for drops in any language, task type or safety set, not only the average.
  4. 4

    Read the changed answers

    Scores miss things. Read a sample of cases where the outputs changed.
  5. 5

    Switch with a way back

    Roll out gradually, watch live metrics, and keep the old version ready.
Watch out
Prompts are code. Keep them in version control, review changes like code, and never edit a production prompt directly in a dashboard without running the suite.
Try this. Take one prompt you use often. Change one word. Run it on five inputs before and after. Did anything you did not expect change?

Watch and read more

Lab

A working eval runner with a baseline and a threshold, run before and after a prompt change.

~45 min

The problem

  1. Save the starter script. It includes a fake model so it runs without any API key.
  2. Run it and note the score. Save it as your baseline.
  3. "Change the prompt" by editing the fake model's answers so that one must-pass case breaks. Run again and confirm the script exits with an error.
  4. Restore that case, but make two ordinary cases fail. Does the script fail with max_drop=0.03? What about max_drop=0.25?
  5. Write three sentences on how you would choose max_drop for a real system.

Practice lab

Edit the code and run it. Python runs in your browser — nothing is sent to our server.

Output

No output. Add print(...) to see values.

You are done when

Hard questions

Try to answer before you reveal. If you can answer these, you understood the lesson.

Q1With 5 cases, each case is 20 points. What does that tell you about thresholds on small suites?Reveal

On a tiny suite, any single failure is a huge score change, so a percentage threshold is really a "number of failures allowed" rule. That is fine for must-pass checks, but for quality scores you need many more cases before small percentage thresholds mean anything. Grow the suite, and use hard gates for the few cases that must never fail.

Q2A provider retires the model version you pinned. What is your plan?Reveal

Treat it like any upgrade, but with a deadline. Read the provider's notice, run your full suite on the candidate replacement early, compare slice by slice, fix prompts where needed and re-run, then roll out gradually with the old version still available until retirement. Keep the eval results as a record of why you chose the replacement.

Please sign in to continue.

Questions people ask

Running the full suite on every change is slow and costs money. What can I do?

Split it. Run a small, fast set of deterministic and must-pass cases on every change, and the full suite (with the LLM judge) before release or nightly. Cache results for cases whose inputs, prompt and model did not change.

What should I do when a case fails but the new answer is actually fine?

Read it carefully. If the new answer is genuinely correct, the test was too strict: update the reference or the check, and record why. Do not quietly delete failing cases to make the build green.

How is this different from security testing in the pipeline?

It is the same practice with a wider scope. Security tests check that attacks keep failing; regression evals check that quality, format, cost and safety all hold. They usually run in the same pipeline.

Do I need a special tool for this?

No. A script, a JSONL file of cases and your normal CI system are enough to start. Open-source eval frameworks can add dashboards and helpers later. Choose based on your needs, and check each tool's current documentation.

Lesson test

5 questions. Get 3 right (60%) to pass and complete this lesson.

Sign in to take the test and save your progress