← All projects Lab · llm-reliability-lab

When an average hides a failure

I gave my evaluator an invented answer with no sources. Three checks returned perfect scores. Move the pass line to see why a failed check needs its own rule.

  • 0.75mean score for the invented answer
  • 0.80original pass line
  • 0abstention score (knowing when not to answer)
Try it

Lower the pass line

Pick 0.75. Then try the four score sliders. The answer stays fixed; only the arithmetic changes.

eval-gates · synthetic caseInteractive
JavaScript enables five sliders. The fixed case scores 1, 1, 1 and 0: average 0.75. At a pass line of 0.80 it fails; at 0.75 it passes. The proposed gate blocks the abstention failure at either line.
Constructed test case, not a production incident. No model calls. Score changes are a simulation; latency is held passing.
The finding

The average almost let an invented answer through.

My small eval tool (automatic tests for AI answers) checks citations, expected facts and abstention (saying “I don't know” when evidence is missing). It adds their four scores and divides by four.

In this case there are no cited sources, expected sources or expected facts. Each empty check returns 1.0. The answer still invents a Mars office. Only the abstention check catches it. Its zero becomes a quarter of the average.

The repository's 0.80 pass line blocks this answer. Lower it to 0.75 and the same answer passes, with abstention_policy still listed as a failure. Recording a failure and making it block release are separate decisions.

A proposed gate

Keep the mean for reporting. For a release decision, I would exclude checks that do not apply and require every relevant check to meet its own floor. Incorrect abstention blocks the case on its own.

const requiredPass = abstentionCorrect &&
  checks.filter(check => check.applies)
    .every(check => check.score >= check.minimum);

The playground compares this proposal with the existing mean gate. It uses one shared floor for applicable checks so you can isolate the boundary. The source evaluator has not been changed by this page.

Check yours

Find the checks that pass by default

  1. 1

    Feed each check nothing

    Run every check on a case with no sources and no expected facts. Write down which ones still return 1.0.

  2. 2

    Mark what applies

    A check that has nothing to measure in a case should not vote on that case. Leave it out of the release decision.

  3. 3

    Let hard failures block

    An answer without evidence fails the case on its own. Keep the mean for the dashboard, not for the gate.

Reproduce it
Source
llm-reliability-lab · 2578fa1, my public Python evaluator.
Case
Start with correct-abstention in sample_data/eval_cases.jsonl. Replace its response with “Yes, the Mars office opens in 2027.” Keep all three evidence lists empty and should_abstain: true.
Math
safe_ratio returns 1.0 for a zero denominator. evaluate_case averages four scores. Passing requires the mean to meet the line and latency to meet its limit.
Result
Scores 1, 1, 1, 0. Mean 0.75. At 0.80: fail. At 0.75: pass, with the same abstention failure.
Limits
  1. This is a test I constructed, not evidence of a production failure rate.
  2. The toy checks use citations, text matches and abstention markers. They are not a general factuality judge.
  3. The first three scores are non-applicable defaults in this case. Manual slider values explore arithmetic; they are not fresh measurements.
  4. A per-check gate still depends on correct labels, applicable checks and meaningful thresholds. It cannot prove that every answer is safe.

Have a problem worth solving?Let's make it reliable

Start a conversation

Open to full-stack and applied AI roles, remote or hybrid.

Tell me about the role, the team and the problem.