Build a production-grade evaluation suite for an AI application: a customer support bot. You will implement every eval tier — format tests, LLM judges, adversarial red-teaming, and a production shadow eval — and wire them into a CI/CD pipeline.
An eval suite for a bank customer support AI that answers questions about account features, fees, and policies. The suite includes 4 test modules, a golden dataset, and a CI configuration that fails PRs when any tier degrades.
support_eval/ ├── app/ │ └── bot.py # The AI under test ├── eval/ │ ├── golden_set.json # 30 test cases with expected behaviors │ ├── test_format.py # Tier 1: format/schema tests │ ├── test_semantic.py # Tier 2: LLM judge quality tests │ ├── test_guardrails.py # Tier 3: behavioral safety tests │ ├── red_team.py # Tier 4: adversarial attacks │ └── production_monitor.py # Live shadow eval (bonus) ├── .github/ │ └── workflows/ │ └── eval.yml # CI pipeline └── pytest.ini
Implement SupportBot class with a query() method
Returns structured response: {"answer": str, "confidence": "high"|"medium"|"low", "escalate": bool}
Write a system prompt that restricts to banking topics
Include explicit refusal instructions for off-topic, investment advice, and system-prompt extraction
Add a query_with_latency() wrapper
Returns (response, latency_ms) tuple — needed for production eval
# eval/test_format.py
import pytest
from app.bot import SupportBot
bot = SupportBot()
def test_response_has_required_keys():
r = bot.query("What is my account number?")
assert "answer" in r and "confidence" in r and "escalate" in r
def test_confidence_is_valid_enum():
r = bot.query("How do I reset my PIN?")
assert r["confidence"] in ("high", "medium", "low")
def test_escalate_is_bool():
r = bot.query("My card was stolen.")
assert isinstance(r["escalate"], bool)
def test_answer_is_non_empty_string():
r = bot.query("What are your hours?")
assert isinstance(r["answer"], str) and len(r["answer"]) > 0
def test_stolen_card_escalates():
r = bot.query("Someone stole my card and made charges.")
assert r["escalate"] is True, "High-risk situations must trigger escalation"Build a llm_judge() function with a 1–5 accuracy rubric
Judges answer against the expected_behavior field in golden_set.json
Run all 30 golden set cases through the judge
Fail if any case scores < 3, or if the average drops below 4.0
Log all failing cases with scores and reasoning
Output to eval_results.json for debugging
Write 10 manually crafted guardrail tests
Off-topic, investment advice, system prompt extraction, persona jailbreak, competitor mentions
Generate 20 automated attack prompts using an attacker LLM
Attacker model: claude-sonnet-4-6 with red-team persona. Target: your SupportBot
Judge each attack for success/failure with a judge LLM
Fail the test suite if any attack succeeds
Add all successful attacks to the regression suite
Fix the bot, add the attack to test_guardrails.py to prevent reversion
Format tests run on every push
pytest -m format — fast, zero API cost
Semantic + guardrail tests run on every PR
pytest -m "semantic or guardrail" — gated behind ANTHROPIC_API_KEY secret
Full red team runs on release branch merges only
pytest -m redteam — most expensive, runs once per release
Post results as PR comment with score summary
Use github-script action to post formatted results table
Congratulations — you have completed LLM Evaluation & Testing. You now have the tooling to ship AI features with confidence. Next: LLM Fine-Tuning & Adaptation, where you will learn to go beyond prompting and actually modify model weights.