From outputai
Validate LLM judges against human labels using TPR/TNR metrics and train/dev/test splits. Use after writing a judge prompt to verify it agrees with human judgment.
How this skill is triggered — by the user, by Claude, or both
Slash command
/outputai:output-eval-validate-judgeThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
An LLM judge is only useful if it agrees with human judgment. This skill walks you through calibrating a judge against human-labeled data using True Positive Rate (TPR) and True Negative Rate (TNR) metrics. Do this **before** trusting any `judgeVerdict()`, `judgeScore()`, or `judgeLabel()` evaluator in your eval suite.
An LLM judge is only useful if it agrees with human judgment. This skill walks you through calibrating a judge against human-labeled data using True Positive Rate (TPR) and True Negative Rate (TNR) metrics. Do this before trusting any judgeVerdict(), judgeScore(), or judgeLabel() evaluator in your eval suite.
.prompt file — Written following output-eval-judge-promptground_truth.evals.<evaluator_name>.verdict: pass or failThis process applies only to LLM-based judges. For code-based Verdict.* evaluators, write unit tests instead.
Split your labeled datasets into three groups:
| Split | % of Data | Purpose | Example (100 datasets) |
|---|---|---|---|
| Train | 10-20% | Source of few-shot examples in the judge prompt | 15 datasets |
| Dev | 40-45% | Iterate on judge prompt, measure TPR/TNR | 42 datasets |
| Test | 40-45% | Final held-out measurement, run once | 43 datasets |
Use a naming convention or subdirectories to separate splits:
Option A: Name prefixes
tests/datasets/
├── train_formal_pass_01.yml
├── train_casual_fail_01.yml
├── dev_technical_pass_01.yml
├── dev_ambiguous_fail_01.yml
├── test_simple_pass_01.yml
├── test_contradictory_fail_01.yml
└── ...
Option B: Subdirectories
tests/datasets/
├── train/
│ ├── formal_pass_01.yml
│ └── casual_fail_01.yml
├── dev/
│ ├── technical_pass_01.yml
│ └── ambiguous_fail_01.yml
└── test/
├── simple_pass_01.yml
└── contradictory_fail_01.yml
.prompt file. Never use dev or test examples — that's data leakageExecute the eval workflow against only the dev-split datasets:
# Run with cached output on dev datasets
npx output workflow test <workflowName> --cached \
--dataset dev_technical_pass_01,dev_ambiguous_fail_01,dev_formal_pass_02,...
Or if using subdirectories, list the dev dataset names:
npx output workflow test <workflowName> --cached \
--dataset $(ls tests/datasets/dev/ | sed 's/.yml//' | tr '\n' ',')
Save the output. You need the judge's verdict for each dataset to compare against ground truth.
Use --json to get machine-readable results:
npx output workflow test <workflowName> --cached --dataset <dev_datasets> --json
The output includes per-dataset, per-evaluator verdicts that you can compare against ground_truth.evals.<evaluator_name>.verdict.
For the evaluator you're validating, build a confusion matrix from the dev results.
Using "fail" as the positive class (what you're trying to detect):
| Judge says Fail | Judge says Pass | |
|---|---|---|
| Human says Fail | True Positive (TP) | False Negative (FN) |
| Human says Pass | False Positive (FP) | True Negative (TN) |
TPR (True Positive Rate) = TP / (TP + FN)
TNR (True Negative Rate) = TN / (TN + FP)
Dev set results for check_tone evaluator (42 datasets):
| Judge: Fail | Judge: Pass | |
|---|---|---|
| Human: Fail | 18 (TP) | 3 (FN) |
| Human: Pass | 2 (FP) | 19 (TN) |
Raw accuracy = (TP + TN) / total = (18 + 19) / 42 = 88.1%
This looks fine, but masks problems. If your dataset were 90% pass (class imbalance), a judge that always says "pass" would get 90% accuracy while catching zero failures (TPR = 0%). TPR and TNR measure what actually matters: catching failures and not crying wolf.
For every case where the judge disagrees with the human label, determine the root cause.
The judge said "pass" but the human said "fail." For each:
The judge said "fail" but the human said "pass." For each:
Track each disagreement to guide prompt iteration:
| Dataset | Human | Judge | Root Cause | Fix |
|---|---|---|---|---|
| dev_technical_pass_03 | pass | fail | Judge flagged "it's" as casual but context was a direct quote | Add exception: "Contractions within direct quotes are acceptable" |
| dev_ambiguous_fail_02 | fail | pass | Judge missed subtle tone shift in paragraph 3 | Add borderline few-shot example showing mid-text tone drift |
Apply the fixes from Step 4 to the judge .prompt file. Then re-run on the dev set:
npx output workflow test <workflowName> --cached --dataset <dev_datasets>
Recompute TPR and TNR. Repeat until both metrics meet the target.
| Metric | Target | Minimum Acceptable |
|---|---|---|
| TPR | > 90% | > 80% |
| TNR | > 90% | > 80% |
If you can't reach 80%/80% after 3-4 iterations:
.prompt frontmatterEach iteration:
.prompt file (not random changes)Once dev metrics meet the target, run the judge on the held-out test set exactly once:
npx output workflow test <workflowName> --cached --dataset <test_datasets> --json
Compute TPR and TNR on the test results. Record these as the final metrics.
Document the final validation results alongside the judge prompt:
# Validation: check_tone ([email protected])
# Date: 2026-03-25
# Model: claude-haiku-4-5-20251001
## Dev Set (42 datasets)
- TPR: 90.5% (19/21)
- TNR: 95.2% (20/21)
## Test Set (43 datasets)
- TPR: 88.0% (22/25)
- TNR: 94.4% (17/18)
## Conclusion: APPROVED — both metrics above 80% minimum
Store this in a VALIDATION.md file next to the judge prompt or in the evaluator's documentation.
output-eval-judge-prompt — Design the judge prompt being validatedoutput-eval-error-analysis — Source of human-labeled data for validationoutput-eval-dataset-design — Generate additional labeled datasets if you need more dataoutput-dev-eval-testing — output workflow test CLI, --cached and --dataset flagsoutput-eval-audit — Audit whether existing judges have been validatedclaude plugin install outputai@claude-plugins-officialCalibrates an LLM judge against human labels using data splits, TPR/TNR, and bias correction. Use after writing a judge prompt to verify alignment before trusting its outputs.
Designs effective LLM judge .prompt files for evaluators. Use when creating judgeVerdict/judgeScore/judgeLabel prompts or when existing judges produce unreliable results.
Use this skill when the user asks to "set up LLM as a judge", "write an LLM judge prompt", "automate quality evaluation", "use Claude to evaluate outputs", "build an automated eval", "LLM-based evaluation", or wants to create a scalable automated evaluation system where one LLM grades the outputs of another LLM.