Evaluation & Testing

Measure AI output quality with a test set, not just vibes.

AI features are non-deterministic, so you cannot rely on a quick manual check. Build evaluations (evals): a set of inputs with expected results that you run automatically.

Kinds of checks

  • Exact/format checks — is the JSON valid, is the label one of the allowed values.
  • Reference comparison — how close is the output to a known-good answer.
  • LLM-as-judge — use another model to grade quality against criteria.
  • Human review — sample outputs regularly.

Run evals on every prompt or model change so you catch regressions before users do.

Example

Example · json
{
  "eval_case": {
    "input": "Refund a $20 order placed 3 days ago.",
    "expect": {"eligible": true, "reason": "within 14-day window"},
    "got": {"eligible": true, "reason": "within policy"},
    "pass": true
  }
}

When to use it

  • A team builds a 50-example golden test set for their summarisation prompt and runs it after every prompt change to detect quality regressions.
  • A product ships an LLM feature only after it scores above 90% on an automated test set that covers edge cases gathered from early beta users.
  • A company uses an LLM-as-judge to score 1000 generated customer emails for tone and accuracy rather than paying humans to review each one.

More examples

Run prompt against golden test set

Evaluates the current prompt on a small golden set and prints a pass-rate score.

Example · python
from openai import OpenAI

client = OpenAI()

golden = [
    {'input': 'Translate "hello" to Spanish.',  'expected': 'hola'},
    {'input': 'Translate "goodbye" to Spanish.', 'expected': 'adios'},
    {'input': 'Translate "thank you" to Spanish.','expected': 'gracias'},
]

correct = 0
for item in golden:
    r = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role':'user','content':item['input'] + ' One word only.'}]
    )
    answer = r.choices[0].message.content.strip().lower()
    if item['expected'] in answer:
        correct += 1

print(f'Score: {correct}/{len(golden)} ({100*correct//len(golden)}%)')

LLM-as-judge quality scorer

Uses a second LLM call to score the quality of a generated answer, returning a numeric rating and reason.

Example · python
import json
from openai import OpenAI

client = OpenAI()

def judge(question, answer):
    prompt = (
        f'Question: {question}\nAnswer: {answer}\n\n'
        'Rate the answer quality 1-5 and return JSON: {"score": <int>, "reason": "<str>"}'
    )
    r = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role':'user','content':prompt}],
        response_format={'type':'json_object'}
    )
    return json.loads(r.choices[0].message.content)

result = judge('What is DNA?', 'DNA carries genetic information in living organisms.')
print(f"Score: {result['score']}/5 — {result['reason']}")

Compare prompt versions by score

Runs two prompt versions on the same test set and compares output characteristics to inform which version to ship.

Example · python
from openai import OpenAI

client = OpenAI()

tests = [
    'Summarise: Photosynthesis converts sunlight into glucose.',
    'Summarise: The mitochondria produce ATP for the cell.',
]

for version, sys_prompt in [
    ('v1', 'Summarise the text.'),
    ('v2', 'Summarise in exactly one sentence, plain English, for a 12-year-old.')
]:
    outputs = []
    for t in tests:
        r = client.chat.completions.create(
            model='gpt-4o-mini',
            messages=[{'role':'system','content':sys_prompt},
                      {'role':'user','content':t}]
        )
        outputs.append(r.choices[0].message.content)
    avg_len = sum(len(o) for o in outputs) / len(outputs)
    print(f'{version} avg output length: {avg_len:.0f} chars')
    print(f'  Sample: {outputs[0][:80]}')

Discussion

  • Be the first to comment on this lesson.