Evaluate RAG retrieval, faithfulness, citations, and abstention
Build a production RAG evaluation program that separates retrieval recall and precision from answer faithfulness, citation validity and support, correctness, usefulness, and abstention; calibrates automated graders with humans; blocks security regressions; and carries evidence through regression, canary, continuous evaluation, and rollback.
Create a reproducible release gate in which gold evidence and answerability are independently reviewed, exact security and citation invariants run deterministically, semantic grading is human-calibrated, critical slices cannot hide behind averages, and a failed candidate can be rolled back as a complete RAG release.
- OpenAI evaluation guidance current
- RAG application versioned control and candidate
- Evaluation dataset frozen and fresh reviewed splits
- Immutable control and candidate Both complete RAG releases identify corpus, retriever, reranker, generator model, prompts, validators, code, and cache behavior.
Compare manifests and run one deterministic fixture. - Qualified reviewers Domain and security reviewers can label answerability, evidence, claims, conflicts, and required abstention using documented rubrics.
Complete a blinded calibration sample and resolve disagreement. - Governed evaluation storage Fixtures, run artifacts, grader inputs, reports, and feedback have classification, access, retention, redaction, and deletion controls.
Review storage policy and attempt access from an unauthorized test role. - Rollback and canary controls Traffic can return to the complete control release automatically when a blocker fires.
Run a staging abort and verify release identity after restoration.
OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.
Full guide
What you will build
- A governed dataset with frozen and fresh splits, authenticated fixture identities, reviewed answerability, acceptable evidence, atomic reference facts, critical slices, and annotation lineage.
- A layered evaluator that runs exact ACL, provenance, schema, and citation-membership assertions before measuring retrieval, claim support, correctness, usefulness, and abstention.
- A human-calibrated regression and rollout process with immutable reports, shadow and canary coverage, continuous evaluation, automatic blockers, and complete-release rollback.
- Teams can distinguish a retrieval miss, irrelevant context, unsupported claim, bad citation, incorrect but grounded answer, unnecessary refusal, operational timeout, and authorization violation.
- Release decisions are reproducible from pinned datasets, rubrics, graders, corpus, models, prompts, code, and costs rather than a dashboard screenshot or subjective demo.
- Critical tenants, languages, security cases, conflicts, and unanswerable questions have independent evidence and cannot disappear inside an aggregate average.
Architecture
How the parts fit together
A dataset registry binds queries to authenticated fixtures, corpus revisions, answerability, evidence, facts, and slices. A run recorder captures every retrieval stage, final evidence, answer, timings, revisions, and cost. Deterministic validators enforce access and identity; metric evaluators score retrieval and abstention; calibrated semantic graders assess claim support and usefulness; a report and release controller compare control and candidate through offline, shadow, canary, continuous evaluation, and rollback.
- Reviewers bind answerability and evidence to an authenticated fixture and exact corpus, while split hashes prevent leakage.
- Control and candidate run identically; exact validators reject unauthorized or fabricated evidence before softer scores.
- Retrieval, grounding, quality, and abstention are computed independently and then sliced with coverage and uncertainty.
- Graders are calibrated against blinded human labels; offline acceptance progresses to shadow and stable canary with automatic blockers.
- The accepted report is bound to production, fresh governed failures expand evaluation, and regressions restore the complete control.
Assumptions
- The application records stable opaque evidence identity and complete release revisions; raw model text alone is insufficient for serious RAG evaluation.
- Domain experts are available for answerability, evidence, and factual support, while security owners define non-compensable authorization and disclosure failures.
- Production-derived evaluation examples can be lawfully collected, redacted, access-controlled, retained, and deleted; otherwise use synthetic or expert-authored fixtures.
- The candidate never executes commands or actions as part of these evaluations, and retrieved instructions remain untrusted data.
Key concepts
- Recall@k
- Fraction of required gold evidence retrieved within the first k results; it measures evidence availability, not answer truth.
- Precision@k
- Fraction of the first k results judged useful; it reflects context efficiency but depends on sufficiently complete relevance labels.
- Citation validity
- Whether a citation refers to an evidence ID actually supplied for the request; it does not prove semantic support.
- Citation support
- Whether the cited passage entails the material claim including scope, numbers, dates, negation, and qualifiers.
- Faithfulness
- Degree to which material answer claims are supported by the provided evidence rather than plausible external knowledge.
- Abstention recall
- Fraction of reviewed unanswerable cases the system correctly refuses or qualifies.
- Critical slice
- A security, tenant, language, workflow, or failure population with independent coverage and release thresholds.
- Grader calibration
- Measured agreement and bias comparison between an automated judge and blinded qualified human labels.
Before you copy
Values used in this guide
{{evaluationManifest}}Decision contract binding release, datasets, gates, owners, and rollback.
Example: /srv/rag-eval/releases/r18/manifest.json{{datasetManifest}}Versioned dataset, split, corpus, annotation, and privacy manifest.
Example: /srv/rag-eval/datasets/2026-07/manifest.json{{evaluationDataset}}Reviewed JSONL records consumed by the visible evaluation harness; each record declares identity, tenant, corpus revision, answerability, labels, and review evidence.
Example: /srv/rag-eval/datasets/2026-07/frozen-test.jsonl{{evaluationHarness}}Path where the complete Python evaluator shown in the deterministic-validator step is saved and reviewed.
Example: /srv/rag-eval/bin/evaluate.py{{candidateRun}}Immutable candidate run artifact ID or path.
Example: /srv/rag-eval/runs/rag-r18-frozen.jsonl{{controlRun}}Immutable control run over the identical records.
Example: /srv/rag-eval/runs/rag-r17-frozen.jsonl{{faithfulnessRubric}}Versioned claim-support and contradiction rubric.
Example: /srv/rag-eval/rubrics/faithfulness-v4.json{{answerRubric}}Versioned correctness, completeness, relevance, and usefulness rubric.
Example: /srv/rag-eval/rubrics/answer-v3.json{{calibrationSet}}Held-out blinded human-labelled grader calibration set.
Example: /srv/rag-eval/calibration/2026-07.jsonl{{sliceManifest}}Critical slice definitions, owners, thresholds, and coverage requirements.
Example: /srv/rag-eval/slices/v5.json{{evaluationReport}}Immutable candidate-control report used for release.
Example: /srv/rag-eval/reports/r18.json{{ragCandidateDir}}Immutable candidate directory containing the exact RAG application and all manifest-bound configuration.
Example: /srv/rag/releases/rag-r18{{ragReleaseChecksums}}SHA-256 manifest covering the candidate application, prompts, retriever configuration, policies, and evaluation bindings.
Example: /srv/rag/releases/rag-r18/SHA256SUMS{{ragCanaryReport}}JSON report collected from the explicit candidate service and synthetic canary probes.
Example: /srv/rag-eval/reports/rag-r18-canary.json{{blockerPolicy}}Automatic canary abort policy for security and quality blockers.
Example: /srv/rag-eval/policies/blockers-v5.json{{probeSet}}Policy-approved synthetic critical canary probes.
Example: /srv/rag-eval/probes/critical-v3.jsonl{{continuousEvalPolicy}}Sampling, redaction, review, retention, and drift policy.
Example: /srv/rag-eval/policies/continuous-v2.jsonSecurity and production boundaries
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Stop before continuing if
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
decision
Write an evaluation decision contract
Define the product decisions this evaluation will govern: retrieval release, generator prompt or model, corpus revision, abstention policy, and production rollout. Establish absolute blockers for unauthorized evidence, invalid citations, unsupported material claims, and required-abstention failures. Then set paired quality, latency, reliability, and cost tolerances. State metric definitions, critical slices, owners, minimum samples, human-review requirements, and the control release. A dashboard without a predeclared decision rule invites teams to reinterpret scores after seeing them.
Why this step matters
RAG has multiple failure stages and partially competing goals. A decision contract prevents a large average gain from compensating for an unacceptable security, grounding, or abstention regression.
What to understand
Use separate metrics for retrieval, evidence use, answer quality, abstention, operations, and cost.
Name metric denominators and treatment of errors, timeouts, duplicates, and skipped records.
Require an accountable owner to approve exceptions rather than letting the evaluation code silently change policy.
System changes
- Creates a versioned evaluation contract without invoking models or changing production.
Syntax explained
blockers- Non-compensable failures that prevent promotion regardless of averages.
control- Immutable currently accepted system used for paired comparison.
critical_slices- Populations and failure classes with independent release thresholds.
Values stay on this page and are never sent or saved.
jq '{candidate,control,corpus,blockers,quality_gates,critical_slices,owners}' {{evaluationManifest}}{"candidate":"rag-r18","control":"rag-r17","corpus":"kb-1842","blockers":{"acl_leaks":0,"unknown_citations":0,"unsupported_critical_claims":0},"quality_gates":{"recall_at_20":0.90,"faithfulness":0.93,"abstention_recall":0.95},"critical_slices":["denied","no-evidence","conflict","multilingual"]}Checkpoint: Checkpoint: Write an evaluation decision contract
jq '{candidate,control,corpus,blockers,quality_gates,critical_slices,owners}' {{evaluationManifest}}Continue whenThe manifest maps every metric to a product decision, owner, threshold, slice, and immutable control.
Stop whenSecurity, citation support, abstention, or corpus identity lacks an explicit decision rule.
If this step fails
Aggregate quality passes while a language, tenant, product, or high-risk workflow regresses.
Likely causeThe majority slice dominates weighting, sparse critical cases have no blocker, or production distribution changed after the dataset was frozen.
Report every metric by declared critical slice with sample counts.Compare current redacted traffic distribution with the evaluation manifest.Inspect paired failures rather than averages alone.
ResolutionMake critical slice thresholds blocking, collect or author more reviewed examples, and reject promotion until the regression is understood or explicitly accepted by the accountable owner.
Security notes
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Alternatives
- Rehearse the decision against a frozen, non-production corpus and retain the candidate-versus-control evidence before changing live traffic.
- Keep the last accepted retrieval or knowledge release available behind an immutable alias so rollback does not depend on rebuilding during an incident.
Stop conditions
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
config
Build a versioned dataset from real distributions and hard cases
Create records containing query, authenticated fixture identity, corpus revision, answerability, gold evidence IDs, optional reference facts, critical slice labels, and provenance of every annotation. Combine expert-authored typical questions, redacted production failures, historical incidents, edge cases, and adversarial prompts. Keep tuning, development, frozen test, and fresh post-release sets separated by stable IDs and hashes. Include no-evidence, unauthorized-only evidence, stale documents, conflicting sources, long documents, multilingual requests, prompt injection, codes, and ambiguous questions.
Why this step matters
An evaluation can only represent the distribution and failures it contains. Stable split lineage and independently reviewed hard cases reduce leakage and make future score changes interpretable.
What to understand
Preserve historical frozen tests even as fresh failure sets grow; otherwise regressions disappear when the benchmark is rewritten.
Record whether evidence was visible to the fixture principal, not merely present somewhere in the corpus.
Do not use raw production content when redaction or lawful evaluation purpose is absent.
System changes
- Creates a governed evaluation dataset and split manifest in access-controlled storage.
Syntax explained
frozen_test- Held-out release gate never used to tune the candidate.
fresh_failures- New independently reviewed cases that detect overfitting to the historical benchmark.
corpus- Exact knowledge revision against which answerability and evidence labels are valid.
{{datasetManifest}}{"dataset":"rag-eval-2026-07","splits":{"development":420,"frozen_test":640,"fresh_failures":88},"corpus":"kb-1842","label_schema":"rag-label-v5","pii":"redacted","critical_slices":["acl-denied","no-evidence","stale","conflict","injection","multilingual"]}records=1148 duplicates=0 split_overlap=0 missing_provenance=0 unredacted_findings=0 schema=PASS
Checkpoint: Checkpoint: Build a versioned dataset from real distributions and hard cases
Continue whenNo split overlap or unreviewed provenance remains and every critical slice has declared coverage.
Stop whenCandidate-generated references are treated as truth, sensitive examples are ungoverned, or split membership cannot be proven.
If this step fails
Evaluation scores improve because candidate outputs leaked into references or tuning examples.
Likely causeDataset lineage is incomplete, one set is reused for tuning and release gating, or generated references were accepted without expert review.
Trace every query, label, and reference to its creation and review event.Compare hashes across train, development, frozen test, and fresh failure sets.Review suspiciously large gains on unchanged production slices.
ResolutionQuarantine contaminated results, rebuild a held-out expert-reviewed test set, version split membership, and repeat comparisons without using candidate-generated truth.
Security notes
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Alternatives
- Rehearse the decision against a frozen, non-production corpus and retain the candidate-versus-control evidence before changing live traffic.
- Keep the last accepted retrieval or knowledge release available behind an immutable alias so rollback does not depend on rebuilding during an incident.
Stop conditions
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
instruction
Annotate answerability, gold evidence, claims, and abstention
Have qualified reviewers label whether the authenticated fixture can answer the query from the frozen corpus, which canonical chunks provide necessary or acceptable evidence, the atomic facts a correct response should convey, and whether conflicting or stale evidence requires qualification. For unanswerable cases, label why: missing, forbidden, stale, contradictory, or out of scope. Use written examples and double review on critical cases. Resolve disagreements and retain adjudication rather than collapsing uncertainty into a synthetic perfect answer.
Why this step matters
Retrieval recall, citation support, correctness, and abstention all depend on trustworthy labels. Explicit answerability and evidence scope prevent a system from being penalized for refusing forbidden information or rewarded for inventing it.
What to understand
Gold evidence may contain multiple valid alternatives; label sets or graded relevance where the task supports them.
Reference facts should be concise and source-backed, not stylistic target answers that reward imitation.
Measure inter-reviewer agreement and investigate disagreement as product ambiguity rather than annotator noise.
System changes
- Adds reviewed labels and adjudication records; it does not modify the corpus or candidate.
Syntax explained
--min-double-review 1.0- Requires every critical record to receive independent second review.
answerability reason- Distinguishes missing, forbidden, stale, conflicting, and out-of-scope evidence.
Values stay on this page and are never sent or saved.
python {{evaluationHarness}} labels-audit --dataset {{evaluationDataset}} --critical-onlycritical_records=214 double_reviewed=214 agreement=0.91 adjudicated=19 missing_gold=0 answerability_conflicts=0
Checkpoint: Checkpoint: Annotate answerability, gold evidence, claims, and abstention
python {{evaluationHarness}} labels-audit --dataset {{evaluationDataset}} --critical-onlyContinue whenCritical records have agreed answerability, gold evidence, reference facts, and abstention expectations.
Stop whenReviewers cannot see the correct corpus revision or authorization context, or disagreement remains unresolved.
If this step fails
Precision@k looks poor even though the answer uses one correct passage.
Likely causeThe gold evidence set omits valid alternatives, k exceeds the amount of evidence required, duplicate chunks are counted independently, or the metric is interpreted without the task's context.
Review unlabelled top candidates with a domain expert.Deduplicate by canonical evidence identity and compare several k values.Measure whether irrelevant context changes faithfulness or cost.
ResolutionRepair incomplete gold labels, report precision at task-relevant depths, and keep a context-efficiency metric; do not declare broad retrieval good merely because one passage saved the answer.
Security notes
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Alternatives
- Rehearse the decision against a frozen, non-production corpus and retain the candidate-versus-control evidence before changing live traffic.
- Keep the last accepted retrieval or knowledge release available behind an immutable alias so rollback does not depend on rebuilding during an incident.
Stop conditions
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
verification
Run deterministic authorization, provenance, and citation validators
Before any semantic grader, verify that retrieved and cited stable IDs exist in the evaluated corpus, belong to the fixture tenant, pass its groups and denies, are active at evaluation time, and were actually supplied in the evidence manifest. Validate response schema, citation syntax, citation membership, source revision, and duplicate handling. These checks produce exact failures and must run before answer-quality scoring so a model cannot award a high score to an unauthorized or fabricated citation.
Why this step matters
Deterministic invariants are cheaper and more reliable than model judgment. They define the security and evidence boundary within which softer faithfulness and usefulness grading is meaningful.
What to understand
Citation membership proves only that an ID was supplied, not that its text supports the claim; support is evaluated later.
Run validators against every retrieval branch and final evidence envelope, not merely the displayed response.
Treat one authorization failure as an incident and release blocker rather than averaging it over the suite.
System changes
- Reads frozen run artifacts and emits deterministic validation results without sending data to a model grader.
Syntax explained
acl- Replays fixture authorization against every retrieved stable ID.
citation-membership- Rejects cited IDs absent from the exact final evidence manifest.
provenance- Confirms corpus and source revisions match the evaluation contract.
{{evaluationHarness}}#!/usr/bin/env python3
import argparse
import json
import math
from pathlib import Path
def rows(path):
with Path(path).open(encoding="utf-8") as handle:
return [json.loads(line) for line in handle if line.strip()]
def by_id(items):
result = {item["id"]: item for item in items}
if len(result) != len(items):
raise SystemExit("duplicate record id")
return result
def percentile(values, fraction):
ordered = sorted(values)
if not ordered:
return 0.0
return ordered[min(len(ordered) - 1, math.ceil(len(ordered) * fraction) - 1)]
def labels_audit(args):
data = rows(args.dataset)
selected = [row for row in data if not args.critical_only or row.get("critical")]
double = sum(len(row.get("reviewers", [])) >= 2 for row in selected)
missing = sum(row.get("answerable") and not row.get("gold_evidence_ids") for row in selected)
unresolved = sum(bool(row.get("review_disagreement")) and not row.get("adjudicated") for row in selected)
result = {"records": len(selected), "double_reviewed": double, "missing_gold": missing, "unresolved": unresolved}
print(json.dumps(result))
if double != len(selected) or missing or unresolved:
raise SystemExit(1)
def validate(args):
data = by_id(rows(args.dataset))
runs = rows(args.run)
counts = {"responses": len(runs), "acl_violations": 0, "missing_ids": 0, "stale_revisions": 0, "unknown_citations": 0, "schema_errors": 0}
for run in runs:
case = data.get(run.get("id"))
if case is None:
counts["schema_errors"] += 1
continue
evidence = run.get("evidence", [])
evidence_ids = {item.get("id") for item in evidence}
for item in evidence:
if item.get("tenant_id") != case.get("tenant_id") or item.get("authorized") is not True or item.get("state") != "active":
counts["acl_violations"] += 1
if not item.get("id"):
counts["missing_ids"] += 1
if item.get("corpus_revision") != case.get("corpus_revision"):
counts["stale_revisions"] += 1
counts["unknown_citations"] += len(set(run.get("cited_ids", [])) - evidence_ids)
print(json.dumps(counts))
if any(counts[key] for key in counts if key != "responses"):
raise SystemExit(1)
def retrieval(args):
data = by_id(rows(args.dataset))
runs = rows(args.run)
recalls, precisions, reciprocal, ndcg = [], [], [], []
for run in runs:
gold = set(data[run["id"]].get("gold_evidence_ids", []))
ranked = list(dict.fromkeys(run.get("retrieved_ids", [])))[:args.k]
hits = [1 if item in gold else 0 for item in ranked]
recalls.append(1.0 if not gold else len(gold.intersection(ranked)) / len(gold))
precisions.append(sum(hits) / max(1, len(ranked)))
first = next((index + 1 for index, hit in enumerate(hits) if hit), None)
reciprocal.append(0 if first is None else 1 / first)
dcg = sum(hit / math.log2(index + 2) for index, hit in enumerate(hits))
ideal = sum(1 / math.log2(index + 2) for index in range(min(len(gold), len(ranked))))
ndcg.append(0 if ideal == 0 else dcg / ideal)
result = {"records": len(runs), "recall": sum(recalls)/len(recalls), "precision": sum(precisions)/len(precisions), "mrr": sum(reciprocal)/len(reciprocal), "ndcg": sum(ndcg)/len(ndcg)}
print(json.dumps(result))
def grounding(args):
runs = rows(args.run)
claims = [claim for run in runs for claim in run.get("claims", []) if claim.get("material", True)]
supported = sum(claim.get("supported") is True for claim in claims)
citations = sum(claim.get("citation_valid") is True for claim in claims)
critical_failures = sum(claim.get("critical") and claim.get("supported") is not True for claim in claims)
result = {"answers": len(runs), "material_claims": len(claims), "claim_support": supported/max(1,len(claims)), "citation_support": citations/max(1,len(claims)), "critical_unsupported": critical_failures}
print(json.dumps(result))
if critical_failures:
raise SystemExit(1)
def answer_quality(args):
candidate = rows(args.run)
control = by_id(rows(args.control))
metrics = ("correct", "complete", "useful")
result = {name: sum(float(row.get(name, 0)) for row in candidate)/len(candidate) for name in metrics}
result["pairwise_candidate_win"] = sum(float(row.get("pairwise_candidate_win", 0)) for row in candidate)/len(candidate)
result["control_correct"] = sum(float(control[row["id"]].get("correct", 0)) for row in candidate)/len(candidate)
print(json.dumps(result))
def abstention(args):
data = by_id(rows(args.dataset))
runs = rows(args.run)
unanswerable = [run for run in runs if not data[run["id"]].get("answerable")]
answerable = [run for run in runs if data[run["id"]].get("answerable")]
true_abstain = sum(run.get("abstained") is True for run in unanswerable)
all_abstain = sum(run.get("abstained") is True for run in runs)
result = {"unanswerable": len(unanswerable), "abstention_recall": true_abstain/max(1,len(unanswerable)), "abstention_precision": true_abstain/max(1,all_abstain), "over_abstained": sum(run.get("abstained") is True for run in answerable), "forbidden_existence_leaks": sum(bool(run.get("forbidden_existence_leak")) for run in runs)}
print(json.dumps(result))
if result["forbidden_existence_leaks"]:
raise SystemExit(1)
def report(args):
candidate = rows(args.run)
control = by_id(rows(args.control))
blockers = {"acl_violations": sum(int(row.get("acl_violations",0)) for row in candidate), "unknown_citations": sum(int(row.get("unknown_citations",0)) for row in candidate), "critical_unsupported": sum(int(row.get("critical_unsupported",0)) for row in candidate)}
result = {"records": len(candidate), "blockers": blockers, "p95_ms": percentile([float(row["latency_ms"]) for row in candidate], .95), "estimated_cost_per_query": sum(float(row.get("estimated_cost_usd",0)) for row in candidate)/len(candidate), "candidate_wins": sum(float(row.get("correct",0)) > float(control[row["id"]].get("correct",0)) for row in candidate)}
result["release_gate"] = "PASS" if not any(blockers.values()) else "FAIL"
Path(args.output).write_text(json.dumps(result, indent=2) + "\n", encoding="utf-8")
print(json.dumps(result))
if result["release_gate"] != "PASS":
raise SystemExit(1)
def calibrate(args):
records = rows(args.set)
repeats = [decision for row in records for decision in row.get("grader_passes", [])[:args.repeats]]
paired = [(row["human_pass"], decision) for row in records for decision in row.get("grader_passes", [])[:args.repeats]]
agreement = sum(human == grader for human, grader in paired) / max(1, len(paired))
critical_false_pass = sum(row.get("critical") and not human and grader for row in records for human, grader in [(row["human_pass"], row.get("grader_passes", [False])[0])])
result = {"records": len(records), "decisions": len(repeats), "agreement": agreement, "critical_false_pass": critical_false_pass}
print(json.dumps(result))
if agreement < .85 or critical_false_pass:
raise SystemExit(1)
parser = argparse.ArgumentParser()
sub = parser.add_subparsers(dest="command", required=True)
for name in ("labels-audit", "validate", "retrieval", "grounding", "answer-quality", "abstention", "report", "calibrate"):
command = sub.add_parser(name)
command.add_argument("--dataset")
command.add_argument("--run")
command.add_argument("--control")
command.add_argument("--output")
command.add_argument("--set")
command.add_argument("--critical-only", action="store_true")
command.add_argument("--k", type=int, default=20)
command.add_argument("--repeats", type=int, default=3)
args = parser.parse_args()
{"labels-audit": labels_audit, "validate": validate, "retrieval": retrieval, "grounding": grounding, "answer-quality": answer_quality, "abstention": abstention, "report": report, "calibrate": calibrate}[args.command](args)Values stay on this page and are never sent or saved.
python {{evaluationHarness}} validate --dataset {{evaluationDataset}} --run {{candidateRun}}responses=640 retrieved_ids=9211 cited_ids=1138 acl_violations=0 missing_ids=0 stale_revisions=0 unknown_citations=0 schema_errors=0 PASS
Checkpoint: Checkpoint: Run deterministic authorization, provenance, and citation validators
python {{evaluationHarness}} validate --dataset {{evaluationDataset}} --run {{candidateRun}}Continue whenAll exact invariants pass with zero unauthorized, unknown, stale, malformed, or out-of-envelope IDs.
Stop whenA deterministic blocker fails or the run artifact lacks stable evidence identity.
If this step fails
Citation IDs exist in the context but the cited text does not support the adjacent claim.
Likely causeCitation validity was confused with citation support, the model cited a related passage, or the evaluator scored whole-answer similarity instead of entailment for individual claims.
Split the answer into material claims and map each cited evidence item.Run deterministic ID membership, then expert-reviewed support grading.Test negation, numeric qualifiers, dates, and conflicting sources.
ResolutionTrack citation validity and support as separate release metrics, require material claims to have supporting evidence, and abstain or qualify claims whose citations do not entail them.
Security notes
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Alternatives
- Rehearse the decision against a frozen, non-production corpus and retain the candidate-versus-control evidence before changing live traffic.
- Keep the last accepted retrieval or knowledge release available behind an immutable alias so rollback does not depend on rebuilding during an incident.
Stop conditions
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
verification
Measure retrieval recall, precision, reciprocal rank, and NDCG
Compare retrieved canonical evidence IDs with reviewed gold sets. Report Recall@k for whether required evidence was available, Precision@k for context efficiency, MRR for first useful evidence, and NDCG when labels include graded relevance. Calculate several k values and deduplicate overlapping chunks by canonical evidence identity. For multi-evidence questions, define whether all required facts or any acceptable source constitutes recall. Report lexical, vector, fused, and final context stages so an answer failure can be traced upstream.
Why this step matters
Retrieval metrics answer different questions and expose different failure costs. Reporting them by stage, depth, and slice avoids reducing evidence availability and context efficiency to one misleading score.
What to understand
Recall denominators exclude truly unanswerable cases but include answerable cases whose evidence was missed.
Precision requires complete acceptable-evidence labels; sample unlabelled high-ranked passages to discover annotation gaps.
Pair metrics with latency and token use because raising k indefinitely is not a valid production improvement.
System changes
- Computes retrieval metrics over stored opaque-ID traces and reviewed labels.
Syntax explained
--k 5,10,20- Shows quality sensitivity to candidate and context depth.
--dedupe- Prevents overlapping chunks from inflating rank and precision counts.
--by-slice- Emits independent results for critical query and tenant populations.
Values stay on this page and are never sent or saved.
python {{evaluationHarness}} retrieval --dataset {{evaluationDataset}} --run {{candidateRun}} --k 20stage=fused recall@5=0.821 recall@10=0.889 recall@20=0.936 precision@10=0.472 mrr=0.811 ndcg@10=0.842 slice=identifier recall@20=0.962 slice=multilingual recall@20=0.901
Checkpoint: Checkpoint: Measure retrieval recall, precision, reciprocal rank, and NDCG
python {{evaluationHarness}} retrieval --dataset {{evaluationDataset}} --run {{candidateRun}} --k 20Continue whenCandidate retrieval meets global and critical-slice gates at bounded k without authorization failures.
Stop whenGold evidence is incomplete, corpus revisions differ, or only a single aggregate k is reported.
If this step fails
Precision@k looks poor even though the answer uses one correct passage.
Likely causeThe gold evidence set omits valid alternatives, k exceeds the amount of evidence required, duplicate chunks are counted independently, or the metric is interpreted without the task's context.
Review unlabelled top candidates with a domain expert.Deduplicate by canonical evidence identity and compare several k values.Measure whether irrelevant context changes faithfulness or cost.
ResolutionRepair incomplete gold labels, report precision at task-relevant depths, and keep a context-efficiency metric; do not declare broad retrieval good merely because one passage saved the answer.
Security notes
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Alternatives
- Rehearse the decision against a frozen, non-production corpus and retain the candidate-versus-control evidence before changing live traffic.
- Keep the last accepted retrieval or knowledge release available behind an immutable alias so rollback does not depend on rebuilding during an incident.
Stop conditions
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
verification
Evaluate claim faithfulness and citation support separately
Decompose each answer into material factual claims. For every claim, determine whether cited evidence exists, whether that evidence entails the claim including numbers, negation, dates, and qualifiers, and whether uncited retrieved context is being used. Track unsupported-claim rate, fully supported answer rate, citation coverage, citation validity, citation support, and contradiction handling. Begin with deterministic membership; use an expert-calibrated model grader only for semantic support, and route uncertainty or critical claims to human review.
Why this step matters
A citation can be real yet irrelevant, and an answer can be factually plausible yet unsupported by the supplied evidence. Claim-level evaluation distinguishes these cases and directly measures RAG grounding.
What to understand
Treat omission and unsupported addition separately; both may matter, but they require different fixes.
Provide graders only the authorized evidence envelope and redact according to policy.
Calibrate with examples of exact support, partial support, contradiction, unrelated citations, and evidence that contains malicious instructions.
System changes
- Runs bounded semantic support grading and stores scores, rationales, revisions, and human calibration metadata.
Syntax explained
--rubric- Versioned observable definition of claim support and contradiction.
--human-calibration- Held-out expert labels used to measure grader agreement and bias.
Values stay on this page and are never sent or saved.
python {{evaluationHarness}} grounding --run {{candidateRun}}answers=640 material_claims=1824 citation_validity=1.000 citation_support=0.956 claim_support=0.948 fully_supported_answers=0.931 critical_unsupported=0 grader_human_agreement=0.89
Checkpoint: Checkpoint: Evaluate claim faithfulness and citation support separately
python {{evaluationHarness}} grounding --run {{candidateRun}}Continue whenNo critical unsupported claim appears; validity, support, and coverage are independently reported with accepted grader agreement.
Stop whenThe grader sees unauthorized data, no human calibration exists, or whole-answer fluency substitutes for claim evidence.
If this step fails
A model grader awards high faithfulness scores to fluent unsupported answers.
Likely causeThe rubric is vague, the grader sees no evidence, verbosity bias dominates, or agreement was never calibrated against independent human labels.
Blindly compare grader and expert labels on known supported and unsupported claims.Use pass/fail or pairwise questions with explicit examples.Check disagreement by answer length, domain, and evidence type.
ResolutionRewrite the rubric around observable claim support, provide the exact authorized evidence, calibrate on a held-out expert set, and retain human review where agreement remains insufficient.
Security notes
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Alternatives
- Rehearse the decision against a frozen, non-production corpus and retain the candidate-versus-control evidence before changing live traffic.
- Keep the last accepted retrieval or knowledge release available behind an immutable alias so rollback does not depend on rebuilding during an incident.
Stop conditions
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
verification
Measure correctness, usefulness, and completeness without hiding grounding
Evaluate whether the answer satisfies the user's permitted need after grounding passes. Compare required source-backed facts, instructions, caveats, and uncertainty with the reviewed reference facts. Use deterministic fact checks where possible and a calibrated pairwise or pass/fail rubric for relevance, completeness, clarity, and actionability. Report grounded-but-incomplete answers separately from unsupported additions. Do not let style scores compensate for false or unauthorized content.
Why this step matters
Faithfulness says an answer follows evidence, not that it includes the right evidence or solves the user task. A separate quality layer preserves that distinction while keeping grounding as a prerequisite.
What to understand
Prefer decomposed pass/fail or pairwise questions because open-ended numeric grading is harder to calibrate.
Blind response order and control answer length to reduce position and verbosity bias.
Require references to reflect the authenticated corpus rather than an ideal answer from outside it.
System changes
- Produces answer-quality comparisons after deterministic and grounding gates pass.
Syntax explained
--compare- Performs paired candidate-control judgments on identical records.
required facts- Source-backed content units used to measure completeness without stylistic imitation.
Values stay on this page and are never sent or saved.
python {{evaluationHarness}} answer-quality --run {{candidateRun}} --control {{controlRun}}candidate_correct=0.914 candidate_complete=0.887 candidate_useful=0.902 control_correct=0.899 control_complete=0.861 pairwise_candidate_win=0.61 unsupported_blockers=0
Checkpoint: Checkpoint: Measure correctness, usefulness, and completeness without hiding grounding
python {{evaluationHarness}} answer-quality --run {{candidateRun}} --control {{controlRun}}Continue whenThe candidate improves or preserves correctness and usefulness with zero grounding blockers.
Stop whenQuality scoring includes deterministically failed answers or reference facts exceed the permitted corpus.
If this step fails
Recall@k is high while users still receive unsupported or misleading answers.
Likely causeRetrieval gold labels are broad, the generator ignores evidence, citations are merely syntactically valid, or claim support and answer correctness are not evaluated separately.
Inspect the exact evidence manifest, citations, and claim-level support for failed examples.Compare retrieval-only metrics with faithfulness and correctness labels.Run deterministic citation membership before any model grader.
ResolutionAdd claim-level support and answer-correctness rubrics calibrated by experts, block unknown citations deterministically, and expand the failed slice without weakening retrieval metrics.
Security notes
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Alternatives
- Rehearse the decision against a frozen, non-production corpus and retain the candidate-versus-control evidence before changing live traffic.
- Keep the last accepted retrieval or knowledge release available behind an immutable alias so rollback does not depend on rebuilding during an incident.
Stop conditions
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
verification
Calibrate abstention precision and recall
Treat answerability as a binary or policy-aware decision before scoring response prose. For reviewed unanswerable records, measure how often the system abstains; for answerable records, measure how often it proceeds. Report abstention recall, abstention precision, false-answer rate, and over-abstention by reason: missing, forbidden, stale, conflicting, weak, or out of scope. Test boundary cases near retrieval thresholds and ensure the refusal does not reveal forbidden document existence or metadata.
Why this step matters
A RAG system needs a measured no-answer behavior because evidence can be absent or impermissible. Precision and recall expose the tradeoff between hallucination and excessive refusal more clearly than a generic answer score.
What to understand
Security-motivated abstention should not confirm that a denied document exists.
Evaluate the retrieval sufficiency decision separately from wording of the final refusal.
Set stricter gates for consequential or policy-sensitive slices than for low-impact informational questions.
System changes
- Calculates answerability and abstention outcomes over positive and negative reviewed fixtures.
Syntax explained
abstention recall- Fraction of unanswerable cases correctly refused.
abstention precision- Fraction of refusals that were actually required.
reason- Operational category that points to retrieval, policy, freshness, conflict, or threshold fixes.
Values stay on this page and are never sent or saved.
python {{evaluationHarness}} abstention --dataset {{evaluationDataset}} --run {{candidateRun}}unanswerable=188 abstained=181 abstention_recall=0.963 abstention_precision=0.941 false_answers=7 answerable=452 over_abstained=11 forbidden_existence_leaks=0
Checkpoint: Checkpoint: Calibrate abstention precision and recall
python {{evaluationHarness}} abstention --dataset {{evaluationDataset}} --run {{candidateRun}}Continue whenRequired refusals meet slice gates, answerable over-abstention remains within tolerance, and denied evidence is not disclosed.
Stop whenThe dataset lacks independently reviewed unanswerable cases or refusal text leaks restricted metadata.
If this step fails
The system answers unanswerable questions instead of abstaining.
Likely causeThe evaluation set lacks negative cases, a relevance threshold was tuned only for recall, the prompt rewards helpfulness over evidence, or abstention has no explicit metric.
Run missing-evidence, forbidden-evidence, stale-evidence, and conflicting-source slices.Inspect accepted candidate scores and generator instructions.Calculate abstention precision and recall against reviewed answerability labels.
ResolutionAdd an explicit evidence-sufficiency decision, calibrate thresholds with positive and negative cases, and block release until required abstention recall meets the safety contract.
Security notes
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Alternatives
- Rehearse the decision against a frozen, non-production corpus and retain the candidate-versus-control evidence before changing live traffic.
- Keep the last accepted retrieval or knowledge release available behind an immutable alias so rollback does not depend on rebuilding during an incident.
Stop conditions
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
verification
Publish slice coverage, uncertainty, and failure examples
Generate a release report for tenant archetype, language, query type, source type, document age, answerability reason, security class, conflict, injection, length, and latency band. Include sample counts, confidence intervals where useful, paired candidate-control changes, and redacted representative failures. Define minimum coverage for critical slices and mark insufficient data as unknown rather than passing it. Inspect regressions and surprising wins with experts before promotion.
Why this step matters
Aggregate metrics favor majority traffic and can hide severe localized failure. Explicit coverage and unknown states prevent a small or absent sample from being interpreted as evidence of safety.
What to understand
Do not publish raw query or document content in broadly visible reports; link to access-controlled review artifacts.
Use paired changes so corpus difficulty does not masquerade as release improvement.
Treat critical insufficient coverage as a hold or manual decision, never an automatic pass.
System changes
- Creates a redacted slice-level evaluation report and release recommendation.
Syntax explained
--min-critical-samples- Minimum evidence required before a critical slice can pass automatically.
--slices- Versioned definitions and ownership for populations and failure modes.
Values stay on this page and are never sent or saved.
python {{evaluationHarness}} report --run {{candidateRun}} --control {{controlRun}} --output {{evaluationReport}}slices=18 critical_pass=9 critical_fail=0 insufficient=2 insufficient_slices=rare-language,legal-hold-query aggregate_gate=PASS promotion_gate=HOLD_FOR_COVERAGE
Checkpoint: Checkpoint: Publish slice coverage, uncertainty, and failure examples
python {{evaluationHarness}} report --run {{candidateRun}} --control {{controlRun}} --output {{evaluationReport}}Continue whenEvery critical slice passes with adequate coverage or is explicitly held for accountable review.
Stop whenUnknown coverage is rendered as zero failures or report access would expose sensitive evaluation content.
If this step fails
Aggregate quality passes while a language, tenant, product, or high-risk workflow regresses.
Likely causeThe majority slice dominates weighting, sparse critical cases have no blocker, or production distribution changed after the dataset was frozen.
Report every metric by declared critical slice with sample counts.Compare current redacted traffic distribution with the evaluation manifest.Inspect paired failures rather than averages alone.
ResolutionMake critical slice thresholds blocking, collect or author more reviewed examples, and reject promotion until the regression is understood or explicitly accepted by the accountable owner.
Security notes
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Alternatives
- Rehearse the decision against a frozen, non-production corpus and retain the candidate-versus-control evidence before changing live traffic.
- Keep the last accepted retrieval or knowledge release available behind an immutable alias so rollback does not depend on rebuilding during an incident.
Stop conditions
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
verification
Calibrate graders against blinded human review
Select a stratified held-out calibration set containing clear passes, clear failures, boundary cases, long and short answers, multiple languages, contradictions, and prompt injection. Have qualified reviewers label it using the same rubric, then compare model-grader agreement, false passes, false failures, position bias, verbosity bias, and variance across repeated runs. Pin grader model, prompt, schema, evidence order, and thresholds. Model graders scale reviewed judgment; they do not create ground truth.
Why this step matters
Automated semantic grading is useful only when its errors and biases are known relative to accountable human judgment. Calibration turns a convenient score into measured evidence and defines where manual adjudication remains necessary.
What to understand
Recalibrate after any grader model, prompt, rubric, schema, or evidence-format change.
Use pass/fail or pairwise comparisons and concrete score examples instead of vague requests for overall quality.
Route critical disagreements and near-threshold results to human review rather than averaging repeated guesses.
System changes
- Creates a versioned grader calibration report; no production answers are changed.
Syntax explained
--repeats 3- Measures residual grader variability on identical inputs.
--blind-order- Reduces position bias in candidate-control pairwise comparisons.
Values stay on this page and are never sent or saved.
python {{evaluationHarness}} calibrate --set {{calibrationSet}} --repeats 3records=160 repeats=3 agreement=0.89 critical_false_pass=0 false_pass=0.031 false_fail=0.044 position_delta=0.008 verbosity_delta=0.012 status=PASS
Checkpoint: Checkpoint: Calibrate graders against blinded human review
python {{evaluationHarness}} calibrate --set {{calibrationSet}} --repeats 3Continue whenAgreement and critical false-pass gates meet policy, biases are bounded, and manual-review boundaries are documented.
Stop whenCritical false passes occur, evidence is omitted, or calibration labels are not independent of the grader.
If this step fails
Repeated evaluation runs produce materially different model-grader results.
Likely causeThe grader model or prompt is mutable, sampling is uncontrolled, evidence ordering changes, or the rubric asks an open-ended subjective question.
Pin grader model, prompt, schema, and input ordering.Repeat a calibration set and measure agreement and variance.Replace open-ended scoring with decomposed pass/fail or pairwise judgments.
ResolutionVersion the grader, use deterministic checks wherever possible, quantify residual variance, and require human adjudication near release thresholds.
Security notes
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Alternatives
- Rehearse the decision against a frozen, non-production corpus and retain the candidate-versus-control evidence before changing live traffic.
- Keep the last accepted retrieval or knowledge release available behind an immutable alias so rollback does not depend on rebuilding during an incident.
Stop conditions
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
verification
Run paired regression, shadow, and canary evaluation
Execute control and candidate on identical frozen inputs and compare every stage. After offline acceptance, shadow only policy-approved redacted traffic and keep candidate answers invisible. Then use stable canary assignment with automatic aborts for authorization, invalid citations, unsupported critical claims, required abstention, error, p95 latency, and cost. Count timeouts and failures in denominators. Use synthetic probes for rare critical slices and require minimum coverage before expansion.
Why this step matters
Paired offline tests isolate release changes, while shadow and canary stages expose production distribution, cache, concurrency, and freshness effects. Automatic blockers keep that evidence-gathering phase bounded.
What to understand
Stable assignment prevents one journey from alternating systems and makes feedback attribution meaningful.
Do not send raw sensitive traffic to a candidate with different retention or access controls.
Canary dashboards must expose attempted, completed, timed-out, skipped, and graded denominators.
System changes
- Mirrors and then routes a bounded production sample to the accepted candidate under automatic abort policy.
Syntax explained
--traffic 5- Limits initial user exposure while preserving realistic load and cache behavior.
--synthetic-probes- Exercises rare security and abstention conditions during the observation window.
--abort-on- Restores control automatically when a non-compensable gate fails.
Values stay on this page and are never sent or saved.
sha256sum -c {{ragReleaseChecksums}} && sudo ln -sfn {{ragCandidateDir}} /srv/rag/candidate && sudo systemctl restart rag@candidate.service && curl -fsS http://127.0.0.1:8401/healthz | jq -e '.release == "rag-r18" and .ready == true' && jq -e '.blockers.acl_violations == 0 and .blockers.unknown_citations == 0 and .blockers.critical_unsupported == 0 and .p95_ms <= 900' {{evaluationReport}} && jq -e '.critical_probe_failures == 0 and .error_rate <= .01' {{ragCanaryReport}}offline=PASS shadow_requests=48210 canary_requests=12044 critical_probe_pass=180/180 acl_leaks=0 unknown_citations=0 critical_unsupported=0 p95_ms=821 cost/query=$0.0064 status=ACCEPTED
Checkpoint: Checkpoint: Run paired regression, shadow, and canary evaluation
sha256sum -c {{ragReleaseChecksums}} && sudo ln -sfn {{ragCandidateDir}} /srv/rag/candidate && sudo systemctl restart rag@candidate.service && curl -fsS http://127.0.0.1:8401/healthz | jq -e '.release == "rag-r18" and .ready == true' && jq -e '.blockers.acl_violations == 0 and .blockers.unknown_citations == 0 and .blockers.critical_unsupported == 0 and .p95_ms <= 900' {{evaluationReport}} && jq -e '.critical_probe_failures == 0 and .error_rate <= .01' {{ragCanaryReport}}Continue whenOffline, shadow, canary, and probes preserve every blocker and satisfy coverage, quality-proxy, latency, and cost budgets.
Stop whenTraffic sampling is biased, blockers are not automatic, or sensitive data crosses an unapproved boundary.
If this step fails
Canary metrics look healthy because only easy requests entered the sample.
Likely causeTraffic assignment is biased, important slices are rare, failures were excluded after timeout, or the canary duration missed scheduled corpus changes.
Audit assignment and inclusion denominators.Report coverage for every critical slice, including timeouts and errors.Inject policy-approved synthetic probes for rare security and abstention cases.
ResolutionExtend or stratify the canary, count all attempted requests, add synthetic probes, and do not promote until critical coverage and minimum sample conditions are met.
Security notes
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Alternatives
- Rehearse the decision against a frozen, non-production corpus and retain the candidate-versus-control evidence before changing live traffic.
- Keep the last accepted retrieval or knowledge release available behind an immutable alias so rollback does not depend on rebuilding during an incident.
Stop conditions
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
decision
Promote with continuous evaluation and a tested rollback
Bind the passing dataset, rubrics, grader calibration, run artifacts, corpus, retriever, prompt, model, code, and cost report to the release manifest. Promote gradually and keep the control available. Continuously sample redacted failures, explicit feedback, corpus changes, and drift signals into a review queue; never let production outputs label themselves. Roll back the complete RAG release when a blocker fires, then add independently adjudicated failures to a fresh regression set before another revision.
Why this step matters
Evaluation is a lifecycle rather than a one-time score. Binding artifacts to the release and rehearsing rollback preserves reproducibility while fresh, reviewed failures keep the suite representative.
What to understand
Alert on distribution, corpus, score, abstention, citation, latency, and cost drift with minimum sample context.
Keep production feedback opt-in or otherwise governed, redacted, access-controlled, and time-limited.
A rollback restores retriever, corpus routing, generator, prompts, validators, caches, and observability together.
System changes
- Promotes the fully evaluated release and enables governed continuous evaluation and rollback monitoring.
Syntax explained
--require-report- Binds promotion to the immutable report for the exact complete release.
--continuous-eval- Defines governed sampling, redaction, review, retention, and drift rules.
--rollback-drill- Proves the control can be restored within the recovery target.
Values stay on this page and are never sent or saved.
jq -e '.release_gate == "PASS"' {{evaluationReport}} && sha256sum -c {{ragReleaseChecksums}} && sudo ln -sfn "$(readlink -f /srv/rag/current)" /srv/rag/previous && sudo ln -sfn {{ragCandidateDir}} /srv/rag/current && sudo systemctl restart rag@current.service && curl -fsS http://127.0.0.1:8400/healthz | jq -e '.release == "rag-r18" and .ready == true' && sudo ln -sfn "$(readlink -f /srv/rag/previous)" /srv/rag/current && sudo systemctl restart rag@current.service && curl -fsS http://127.0.0.1:8400/healthz | jq -e '.release == "rag-r17" and .ready == true'release=rag-r18 report=sha256:5a7d... calibration=cal-v4 rollout=100% continuous_eval=enabled rollback_drill=PASS restore_seconds=39 blockers_tested=7
Checkpoint: Checkpoint: Promote with continuous evaluation and a tested rollback
jq -e '.release_gate == "PASS"' {{evaluationReport}} && sha256sum -c {{ragReleaseChecksums}} && sudo ln -sfn "$(readlink -f /srv/rag/current)" /srv/rag/previous && sudo ln -sfn {{ragCandidateDir}} /srv/rag/current && sudo systemctl restart rag@current.service && curl -fsS http://127.0.0.1:8400/healthz | jq -e '.release == "rag-r18" and .ready == true' && sudo ln -sfn "$(readlink -f /srv/rag/previous)" /srv/rag/current && sudo systemctl restart rag@current.service && curl -fsS http://127.0.0.1:8400/healthz | jq -e '.release == "rag-r17" and .ready == true'Continue whenProduction identifies the passing release, continuous evaluation is governed, and complete rollback succeeds within target.
Stop whenArtifacts cannot reproduce the decision, feedback collection violates policy, or rollback restores only one component.
If this step fails
Offline evaluation passes but production feedback and incidents worsen.
Likely causeThe test distribution is stale, logging misses new failure classes, traffic contains longer or adversarial inputs, or latency and retrieval freshness differ in production.
Compare production slices, corpus revision, latency, abstention, and query characteristics with the test manifest.Mine redacted failures and explicit feedback under policy.Reproduce incidents against both control and candidate releases.
ResolutionRoll back when critical gates fail, add independently reviewed incident cases to a fresh regression set, and update the distribution without erasing the frozen historical benchmark.
Security notes
- Evaluation data inherits the sensitivity and tenant boundary of the source interactions. Redact or synthesize fixtures before broad reviewer access, and never place raw secrets, personal data, or restricted documents in model-grader prompts.
- Run authorization, citation-identity, provenance, and schema checks deterministically before model-based grading. A fluent grader result cannot override a failed access-control or source-validity assertion.
- Keep frozen test sets separated from tuning examples, version annotations and rubrics, and record model, prompt, retriever, corpus, and code revisions so a score can be reproduced rather than remembered.
- Treat evaluation dashboards as decision support. Critical security, abstention, and unsupported-claim slices use explicit release blockers even when a weighted aggregate appears to improve.
Alternatives
- Rehearse the decision against a frozen, non-production corpus and retain the candidate-versus-control evidence before changing live traffic.
- Keep the last accepted retrieval or knowledge release available behind an immutable alias so rollback does not depend on rebuilding during an incident.
Stop conditions
- Stop if reference answers or gold evidence were generated by the candidate system and accepted without independent expert review.
- Stop if a release improves average answer quality while regressing tenant isolation, citation validity, unsupported-claim rate, or required abstention behavior.
- Stop if grader agreement with calibrated human labels falls below the documented threshold or changes materially after a model or rubric revision.
- Stop if production sampling cannot be redacted within policy, lacks consent or lawful purpose, or would expose one tenant's material to another reviewer.
Finish line
Verification checklist
python {{evaluationHarness}} labels-audit --dataset {{evaluationDataset}} --critical-onlySplits do not overlap, corpus and authorization context match labels, critical records are independently reviewed, and sensitive data is governed.python {{evaluationHarness}} validate --dataset {{evaluationDataset}} --run {{candidateRun}}Zero unauthorized evidence, unknown citations, stale identities, and schema failures.python {{evaluationHarness}} report --run {{candidateRun}} --control {{controlRun}} --output {{evaluationReport}} && python {{evaluationHarness}} abstention --dataset {{evaluationDataset}} --run {{candidateRun}}Retrieval, claim support, correctness, usefulness, and abstention pass global and critical-slice thresholds with adequate coverage.python {{evaluationHarness}} calibrate --set {{calibrationSet}} --repeats 3 && sha256sum -c {{ragReleaseChecksums}} && test "$(readlink -f /srv/rag/current)" = "$(readlink -f /srv/rag/previous)" && systemctl is-active rag@current.serviceGrader agreement passes with zero critical false positives and the complete control release is restored within target.Recovery guidance
Common problems and safe checks
Recall@k is high while users still receive unsupported or misleading answers.
Likely causeRetrieval gold labels are broad, the generator ignores evidence, citations are merely syntactically valid, or claim support and answer correctness are not evaluated separately.
Inspect the exact evidence manifest, citations, and claim-level support for failed examples.Compare retrieval-only metrics with faithfulness and correctness labels.Run deterministic citation membership before any model grader.
ResolutionAdd claim-level support and answer-correctness rubrics calibrated by experts, block unknown citations deterministically, and expand the failed slice without weakening retrieval metrics.
Precision@k looks poor even though the answer uses one correct passage.
Likely causeThe gold evidence set omits valid alternatives, k exceeds the amount of evidence required, duplicate chunks are counted independently, or the metric is interpreted without the task's context.
Review unlabelled top candidates with a domain expert.Deduplicate by canonical evidence identity and compare several k values.Measure whether irrelevant context changes faithfulness or cost.
ResolutionRepair incomplete gold labels, report precision at task-relevant depths, and keep a context-efficiency metric; do not declare broad retrieval good merely because one passage saved the answer.
Citation IDs exist in the context but the cited text does not support the adjacent claim.
Likely causeCitation validity was confused with citation support, the model cited a related passage, or the evaluator scored whole-answer similarity instead of entailment for individual claims.
Split the answer into material claims and map each cited evidence item.Run deterministic ID membership, then expert-reviewed support grading.Test negation, numeric qualifiers, dates, and conflicting sources.
ResolutionTrack citation validity and support as separate release metrics, require material claims to have supporting evidence, and abstain or qualify claims whose citations do not entail them.
The system answers unanswerable questions instead of abstaining.
Likely causeThe evaluation set lacks negative cases, a relevance threshold was tuned only for recall, the prompt rewards helpfulness over evidence, or abstention has no explicit metric.
Run missing-evidence, forbidden-evidence, stale-evidence, and conflicting-source slices.Inspect accepted candidate scores and generator instructions.Calculate abstention precision and recall against reviewed answerability labels.
ResolutionAdd an explicit evidence-sufficiency decision, calibrate thresholds with positive and negative cases, and block release until required abstention recall meets the safety contract.
The system abstains on many answerable questions after a safety change.
Likely causeThe threshold is too strict, retrieval misses gold evidence, citations require an impossible format, or answerable labels do not match the deployed corpus revision.
Separate retrieval misses from generator abstentions.Verify gold evidence exists and is authorized in the evaluated corpus.Plot answerability decisions by confidence and query slice.
ResolutionRepair corpus or retrieval defects first, then calibrate evidence thresholds against held-out answerable and unanswerable examples; never fix over-abstention by disabling authorization.
A model grader awards high faithfulness scores to fluent unsupported answers.
Likely causeThe rubric is vague, the grader sees no evidence, verbosity bias dominates, or agreement was never calibrated against independent human labels.
Blindly compare grader and expert labels on known supported and unsupported claims.Use pass/fail or pairwise questions with explicit examples.Check disagreement by answer length, domain, and evidence type.
ResolutionRewrite the rubric around observable claim support, provide the exact authorized evidence, calibrate on a held-out expert set, and retain human review where agreement remains insufficient.
Evaluation scores improve because candidate outputs leaked into references or tuning examples.
Likely causeDataset lineage is incomplete, one set is reused for tuning and release gating, or generated references were accepted without expert review.
Trace every query, label, and reference to its creation and review event.Compare hashes across train, development, frozen test, and fresh failure sets.Review suspiciously large gains on unchanged production slices.
ResolutionQuarantine contaminated results, rebuild a held-out expert-reviewed test set, version split membership, and repeat comparisons without using candidate-generated truth.
Aggregate quality passes while a language, tenant, product, or high-risk workflow regresses.
Likely causeThe majority slice dominates weighting, sparse critical cases have no blocker, or production distribution changed after the dataset was frozen.
Report every metric by declared critical slice with sample counts.Compare current redacted traffic distribution with the evaluation manifest.Inspect paired failures rather than averages alone.
ResolutionMake critical slice thresholds blocking, collect or author more reviewed examples, and reject promotion until the regression is understood or explicitly accepted by the accountable owner.
Repeated evaluation runs produce materially different model-grader results.
Likely causeThe grader model or prompt is mutable, sampling is uncontrolled, evidence ordering changes, or the rubric asks an open-ended subjective question.
Pin grader model, prompt, schema, and input ordering.Repeat a calibration set and measure agreement and variance.Replace open-ended scoring with decomposed pass/fail or pairwise judgments.
ResolutionVersion the grader, use deterministic checks wherever possible, quantify residual variance, and require human adjudication near release thresholds.
Offline evaluation passes but production feedback and incidents worsen.
Likely causeThe test distribution is stale, logging misses new failure classes, traffic contains longer or adversarial inputs, or latency and retrieval freshness differ in production.
Compare production slices, corpus revision, latency, abstention, and query characteristics with the test manifest.Mine redacted failures and explicit feedback under policy.Reproduce incidents against both control and candidate releases.
ResolutionRoll back when critical gates fail, add independently reviewed incident cases to a fresh regression set, and update the distribution without erasing the frozen historical benchmark.
Evaluation cost or duration makes every release impractical.
Likely causeAll examples use expensive generation and grading, deterministic stages are repeated unnecessarily, caching lacks revision keys, or no smoke/full tiers exist.
Attribute time and cost to retrieval, generation, deterministic validators, and graders.Identify unchanged stage outputs keyed by complete release revisions.Compare a representative smoke subset with full-suite decisions.
ResolutionCreate deterministic prechecks and tiered suites, cache only revision-complete safe artifacts, cap grader inputs, and retain the full critical and security suite as a mandatory promotion gate.
Canary metrics look healthy because only easy requests entered the sample.
Likely causeTraffic assignment is biased, important slices are rare, failures were excluded after timeout, or the canary duration missed scheduled corpus changes.
Audit assignment and inclusion denominators.Report coverage for every critical slice, including timeouts and errors.Inject policy-approved synthetic probes for rare security and abstention cases.
ResolutionExtend or stratify the canary, count all attempted requests, add synthetic probes, and do not promote until critical coverage and minimum sample conditions are met.
Reference
Frequently asked questions
Is Recall@k enough to evaluate RAG?
No. It shows whether evidence was available within k, not whether generation used it faithfully, cited it correctly, answered completely, or should have abstained.
Does a valid citation prove support?
No. Validity means the ID existed in the supplied evidence. Support asks whether that evidence entails the specific claim. Measure both.
Can an LLM judge replace human reviewers?
Not automatically. Calibrate it against blinded qualified labels, measure false passes and bias, use deterministic checks first, and retain human adjudication for critical or uncertain cases.
Should reference answers be generated by the candidate?
No. Candidate-generated truth creates leakage and self-reward. Use expert-reviewed source-backed facts and preserve annotation provenance.
How should unanswerable questions be scored?
Label why they are unanswerable, measure abstention precision and recall, and verify the refusal does not disclose forbidden document existence.
Why report slices when the overall score passes?
Majority traffic can hide failures for a tenant, language, security case, or workflow. Critical slices need independent thresholds and minimum coverage.
Can evaluation data include production conversations?
Only under a documented lawful purpose and policy with minimization, redaction, access, retention, and deletion. Otherwise use synthetic or expert-authored fixtures.
What gets rolled back?
The complete corpus routing, retrieval, ranking, generator, prompts, validators, caches, and telemetry release, while newer deletions and ACL revocations remain enforced.
Recovery
Rollback
Stop candidate traffic and restore the complete control RAG manifest: corpus routing, lexical/vector indexes, ranking, reranker, evidence assembly, generator, prompts, validators, cache namespace, and telemetry. Preserve newer deletions and authorization changes, then run blocker and quality smoke tests.
- Preserve immutable run IDs, reports, calibration, alerts, and redacted failure evidence while stopping continuous promotion.
- Route new traffic to the control and invalidate candidate-dependent response and retrieval caches.
- Restore all components from the control manifest and reapply current tombstones, retention state, and ACL revocations.
- Run deterministic ACL, provenance, citation, abstention, retrieval, latency, and cost smoke fixtures.
- Resume traffic gradually, adjudicate the regression, and add it to a fresh held-out set before another candidate.
Evidence