RAG eval & guardrails (verified, zero-API)
Prove a RAG/LLM feature is good enough to ship — and isn't leaking identifiers —
with checks that run and exit non-zero on failure, not assertions. The eval
scores a precomputed predictions file, so the gate needs no API access.
Core principle
Quality is measured, not claimed. The loop is: eval against a frozen golden
set → read the failures → fix the prompt / retrieval / data → re-eval, until
thresholds are met and nothing regressed versus the baseline. A separate
PII/PHI guard fails the build if structured identifiers leak.
Be honest about scope (this is the rule that keeps the skill correct): the
metrics here are lexical proxies — token overlap, containment, F1. They
catch gross failures (hallucination, fabricated citations, retrieval misses) but
do not measure truth. A correct paraphrase can score low; a wrong answer
that reuses context words can score high. True faithfulness/correctness needs
human review or an LLM-as-judge. The PII guard catches structured identifiers
(emails, cards, SSNs…), not names or contextual PHI. Report
"thresholds met on lexical proxies; no regression; no structured-identifier
leakage" — never "the AI system is correct" or "compliant."
→ references/01-eval-driven-rag.md, references/02-metrics.md
When to use vs. not
- Use for: evaluating or regression-testing a RAG/LLM feature; measuring
groundedness/hallucination, citation validity, retrieval hit@k, answer
correctness, refusal rate, latency; adding an eval gate to CI; scanning
prompts/answers/logs for PII/PHI leakage in regulated domains.
- Not for: training/fine-tuning models; a clinical or regulatory validation
of an AI system (this assists, it does not certify); detecting personal names
or free-text PHI (needs NER + human review).
Inputs to gather first
- Golden set — questions with optional
expected_answer / expected_sources
as golden.jsonl. The contract everything keys off. → references/03-building-the-golden-set.md
- Predictions — a precomputed
predictions.jsonl ({id, answer, contexts?, citations?, latency_ms?}). Generate once via your endpoint, then score
offline. → references/05-running-it-and-ci.md
- Thresholds — the bars in
rageval.config.json; set them just under an
acceptable baseline, don't invent numbers.
- What to scan for leakage — which prompts/answers/logs the PII guard runs
over. →
references/04-guardrails-and-pii.md
Workflow
Load each reference when you reach its step.
Adopt eval-driven development & accept the honest scope. Lexical proxies
are necessary, not sufficient. → references/01-eval-driven-rag.md
Build the golden set — cover core facts, multi-hop, unanswerable, and
adversarial/injection cases; freeze it like test code. → references/03-building-the-golden-set.md
cp scripts/golden.example.jsonl golden.jsonl # then edit to your domain
Generate predictions — the only step that touches your model. Wire your
endpoint into the provider-agnostic stub, or supply any predictions.jsonl.
→ references/05-running-it-and-ci.md
cp scripts/rageval.config.example.json rageval.config.json # edit thresholds
python3 scripts/client.example.py --golden golden.jsonl --out predictions.jsonl
Run the eval gate offline (no API); read report.md. → references/02-metrics.md
python3 scripts/rag_eval.py --golden golden.jsonl --predictions predictions.jsonl \
--config rageval.config.json --out-dir eval-report
Fix the root cause of the lowest-groundedness / failing items — retrieval,
prompt, or data — and re-eval. Repeat until thresholds are met. → references/05-running-it-and-ci.md
Gate regressions against a trusted baseline report so upgrades/tweaks
can't quietly degrade quality. → references/05-running-it-and-ci.md
python3 scripts/rag_eval.py --golden golden.jsonl --predictions predictions.jsonl \
--config rageval.config.json --baseline baseline/report.json --out-dir eval-report
Run the PII/PHI guard over answers and the prediction/log artifacts; it
fails the build on any leak. → references/04-guardrails-and-pii.md
python3 scripts/pii_guard.py --input predictions.jsonl --fields answer,contexts
What's in this skill
scripts/rag_eval.py — the gate backbone: scores a precomputed predictions file (groundedness, F1/EM, hit@k, citation presence/validity, refusal rate, latency p50/p95), compares to thresholds and an optional --baseline, writes report.json+report.md, exits non-zero on any failure. STDLIB only, no network.
scripts/pii_guard.py — PII/PHI leakage gate: regex + Luhn over JSONL/text for emails, phones, SSNs, MRN/DOB labels, IBANs, cards; redacts findings; exits non-zero on any leak. STDLIB only.
scripts/client.example.py — provider-AGNOSTIC stub with a marked TODO showing where to call your LLM/RAG endpoint, plus a helper that dumps predictions.jsonl. Runs offline (emits refusals) until wired.
scripts/golden.example.jsonl / predictions.example.jsonl — a 6-item self-test set with a correct refusal and one deliberately hallucinated answer + fabricated citation.
scripts/rageval.config.example.json — thresholds + regression deltas.
scripts/requirements.txt — stdlib-only; nothing to install for the runnable path.
references/01–05 — eval-driven development & honest scope, metrics (how each is computed + its limits + the optional LLM-judge path), building the golden set, guardrails/PII/injection, and running it in CI.
Definition of done
Guardrails — avoid these mistakes
- Don't claim "correct" or "compliant" from a green eval. State "thresholds
met on lexical proxies; no regression; no structured-identifier leakage."
Overclaiming is the cardinal error here.
- Don't lower a threshold (or edit the golden set) to go green. Fix the
retrieval/prompt/data root cause; baselines and golden items are the contract.
- Groundedness is overlap, not truth. A high score means lexically
supported by the contexts, not factually correct — confirm with human review
or an LLM judge for high-stakes outputs.
- Refusals cut both ways. Gate refusal rate with an upper bound; an
over-cautious model is a regression other metrics miss.
- The PII guard misses names and contextual PHI. It's an early tripwire, not
a HIPAA/GDPR attestation; pair with NER de-identification and human review.
- Don't log raw prompts/answers in regulated domains, and run the PII guard
over the artifacts you persist — the most common leak is the log line.
- Keep the scoring path API-free and deterministic so CI stays cheap and
reproducible; only generation should touch your model.
1---2name: rag-eval-guardrails3description: Build a verified eval harness for a RAG/LLM feature plus PII/PHI-leakage guardrails, gated by checks that actually run. Scores a precomputed predictions file (so it runs with ZERO API access) on groundedness, citation validity, retrieval hit@k, answer F1/exact-match, refusal rate, and latency; compares to config thresholds and a baseline to catch regressions; and fails the build on PII/PHI leakage. Use when the user wants to evaluate or regression-test an AI/RAG feature, measure hallucination/groundedness, add an eval gate to CI, or scan prompts/answers/logs for leaked identifiers. Triggers: "RAG evaluation", "LLM eval", "eval harness", "hallucination", "groundedness", "PII/PHI leakage", "guardrails", "regression testing for AI features".4license: MIT5---67# RAG eval & guardrails (verified, zero-API)89Prove a RAG/LLM feature is good enough to ship — and isn't leaking identifiers —10with checks that **run and exit non-zero on failure**, not assertions. The eval11scores a precomputed predictions file, so the gate needs **no API access**.1213## Core principle1415**Quality is measured, not claimed.** The loop is: eval against a frozen golden16set → read the failures → fix the prompt / retrieval / data → re-eval, until17thresholds are met **and** nothing regressed versus the baseline. A separate18PII/PHI guard fails the build if structured identifiers leak.1920**Be honest about scope (this is the rule that keeps the skill correct):** the21metrics here are **lexical proxies** — token overlap, containment, F1. They22catch gross failures (hallucination, fabricated citations, retrieval misses) but23do **not** measure truth. A correct paraphrase can score low; a wrong answer24that reuses context words can score high. True faithfulness/correctness needs25human review or an LLM-as-judge. The PII guard catches **structured** identifiers26(emails, cards, SSNs…), not names or contextual PHI. Report27**"thresholds met on lexical proxies; no regression; no structured-identifier28leakage"** — never "the AI system is correct" or "compliant."29→ `references/01-eval-driven-rag.md`, `references/02-metrics.md`3031## When to use vs. not3233- Use for: evaluating or regression-testing a RAG/LLM feature; measuring34 groundedness/hallucination, citation validity, retrieval hit@k, answer35 correctness, refusal rate, latency; adding an eval gate to CI; scanning36 prompts/answers/logs for PII/PHI leakage in regulated domains.37- Not for: training/fine-tuning models; a clinical or regulatory *validation*38 of an AI system (this assists, it does not certify); detecting personal names39 or free-text PHI (needs NER + human review).4041## Inputs to gather first42431. **Golden set** — questions with optional `expected_answer` / `expected_sources`44 as `golden.jsonl`. The contract everything keys off. → `references/03-building-the-golden-set.md`452. **Predictions** — a precomputed `predictions.jsonl` (`{id, answer, contexts?,46 citations?, latency_ms?}`). Generate once via your endpoint, then score47 offline. → `references/05-running-it-and-ci.md`483. **Thresholds** — the bars in `rageval.config.json`; set them just under an49 acceptable baseline, don't invent numbers.504. **What to scan for leakage** — which prompts/answers/logs the PII guard runs51 over. → `references/04-guardrails-and-pii.md`5253## Workflow5455Load each reference when you reach its step.56571. **Adopt eval-driven development & accept the honest scope.** Lexical proxies58 are necessary, not sufficient. → `references/01-eval-driven-rag.md`59602. **Build the golden set** — cover core facts, multi-hop, **unanswerable**, and61 adversarial/injection cases; freeze it like test code. → `references/03-building-the-golden-set.md`62 ```bash63 cp scripts/golden.example.jsonl golden.jsonl # then edit to your domain64 ```65663. **Generate predictions** — the only step that touches your model. Wire your67 endpoint into the provider-agnostic stub, or supply any `predictions.jsonl`.68 → `references/05-running-it-and-ci.md`69 ```bash70 cp scripts/rageval.config.example.json rageval.config.json # edit thresholds71 python3 scripts/client.example.py --golden golden.jsonl --out predictions.jsonl72 ```73744. **Run the eval gate offline** (no API); read `report.md`. → `references/02-metrics.md`75 ```bash76 python3 scripts/rag_eval.py --golden golden.jsonl --predictions predictions.jsonl \77 --config rageval.config.json --out-dir eval-report78 ```79805. **Fix the root cause** of the lowest-groundedness / failing items — retrieval,81 prompt, or data — and re-eval. Repeat until thresholds are met. → `references/05-running-it-and-ci.md`82836. **Gate regressions** against a trusted baseline report so upgrades/tweaks84 can't quietly degrade quality. → `references/05-running-it-and-ci.md`85 ```bash86 python3 scripts/rag_eval.py --golden golden.jsonl --predictions predictions.jsonl \87 --config rageval.config.json --baseline baseline/report.json --out-dir eval-report88 ```89907. **Run the PII/PHI guard** over answers and the prediction/log artifacts; it91 fails the build on any leak. → `references/04-guardrails-and-pii.md`92 ```bash93 python3 scripts/pii_guard.py --input predictions.jsonl --fields answer,contexts94 ```9596## What's in this skill9798- `scripts/rag_eval.py` — the gate backbone: scores a precomputed predictions file (groundedness, F1/EM, hit@k, citation presence/validity, refusal rate, latency p50/p95), compares to thresholds and an optional `--baseline`, writes `report.json`+`report.md`, exits non-zero on any failure. STDLIB only, no network.99- `scripts/pii_guard.py` — PII/PHI leakage gate: regex + Luhn over JSONL/text for emails, phones, SSNs, MRN/DOB labels, IBANs, cards; redacts findings; exits non-zero on any leak. STDLIB only.100- `scripts/client.example.py` — provider-AGNOSTIC stub with a marked TODO showing where to call your LLM/RAG endpoint, plus a helper that dumps `predictions.jsonl`. Runs offline (emits refusals) until wired.101- `scripts/golden.example.jsonl` / `predictions.example.jsonl` — a 6-item self-test set with a correct refusal and one deliberately hallucinated answer + fabricated citation.102- `scripts/rageval.config.example.json` — thresholds + regression deltas.103- `scripts/requirements.txt` — stdlib-only; nothing to install for the runnable path.104- `references/01–05` — eval-driven development & honest scope, metrics (how each is computed + its limits + the optional LLM-judge path), building the golden set, guardrails/PII/injection, and running it in CI.105106## Definition of done107108- [ ] `rag_eval.py` runs on the golden + predictions and **exits 0** with all109 configured thresholds met.110- [ ] A `--baseline` regression run **passes** (no metric drop beyond delta).111- [ ] Golden set covers core, multi-hop, **unanswerable/refusal**, and112 adversarial/injection cases; it's frozen and version-controlled.113- [ ] Lowest-groundedness items in `report.md` reviewed; failures traced to114 retrieval / prompt / data, not papered over by lowering a threshold.115- [ ] `pii_guard.py` runs on answers **and** the persisted prediction/log116 artifact and **exits 0** (no structured-identifier leakage).117- [ ] CI runs both gates on the production endpoint's predictions; reports118 archived. Results reported as proxies, not as correctness/compliance.119120## Guardrails — avoid these mistakes121122- **Don't claim "correct" or "compliant" from a green eval.** State "thresholds123 met on lexical proxies; no regression; no structured-identifier leakage."124 Overclaiming is the cardinal error here.125- **Don't lower a threshold (or edit the golden set) to go green.** Fix the126 retrieval/prompt/data root cause; baselines and golden items are the contract.127- **Groundedness is overlap, not truth.** A high score means *lexically128 supported by the contexts*, not *factually correct* — confirm with human review129 or an LLM judge for high-stakes outputs.130- **Refusals cut both ways.** Gate refusal rate with an upper bound; an131 over-cautious model is a regression other metrics miss.132- **The PII guard misses names and contextual PHI.** It's an early tripwire, not133 a HIPAA/GDPR attestation; pair with NER de-identification and human review.134- **Don't log raw prompts/answers in regulated domains**, and run the PII guard135 over the artifacts you persist — the most common leak is the log line.136- **Keep the scoring path API-free and deterministic** so CI stays cheap and137 reproducible; only generation should touch your model.