feat: multi-sample judging with stability metadata and noise-aware quality gate - #53
Open
brainsparker wants to merge 1 commit into
Open
feat: multi-sample judging with stability metadata and noise-aware quality gate#53brainsparker wants to merge 1 commit into
brainsparker wants to merge 1 commit into
Conversation
…ality gate LLM-as-judge scores are noisy: the same judge, prompt, and response can score differently across runs, which makes single-sample CI gates flap. This adds judge.samples / --judge-samples to run the judge k times per response, aggregates to the median with mean/stdev/sample_scores attached to JudgeScore, surfaces per-model stability in the run summary, and adds --noise-aware-gate so --fail-under fails a model only when its average score drops below the gate by more than the observed judge noise. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
LLM-as-judge scores are noisy. The same judge model, prompt, and response can score 4 on one run and 3 on the next, even at temperature 0.3. On a single sample, that noise is indistinguishable from a real quality change, so
--fail-undergates flap and teams stop trusting red builds.This PR adds multi-sample judging and a noise-aware quality gate:
judge.samplesconfig field and--judge-samples NCLI override (1 to 10, default 1): run the judge N times per response, concurrently.JudgeScorenow carriessample_scores,score_mean, andscore_stdev, which flow into the JSON export automatically.--noise-aware-gate: lowers each model's--fail-underthreshold by its average per-case judge stdev. A model fails only when its score drops below the gate by more than the observed judge noise. The gate output prints the effective threshold and noise margin for each failing model, so the decision is auditable in the CI log.Usage
or in config:
Why now (market rationale)
Judge flakiness is the most complained-about failure mode in the eval category right now, and nobody serves it in the lightweight OSS tier:
DeepEval, promptfoo, and RAGAS all issue a single judge call per case by default. PromptLens shipping variance-aware judging for free, wired directly into its existing CI gate, is a clean differentiator that extends the CI-native story from the recent
--fail-underandcompare --fail-on-regressionwork.Runner-up candidates considered today: an MCP 2026-07-28 conformance checker command (timely, spec is under a month old, but a bigger surface to get right), and delta-gating against saved baselines (real need, but partially covered by the existing
promptlens compare --fail-on-regression).Implementation notes
promptlens/judges/stability.pyholds aggregation (aggregate_judge_scores) and orchestration (sample_judge_scores). It works againstBaseJudge, so any future judge implementation gets multi-sampling for free.LLMJudgeis untouched.samplesdefaults to 1, newJudgeScorefields have defaults,_check_fail_underkeeps its existing shape (existing junit gate tests pass unchanged).statisticsonly, no new dependencies.Test status
tests/test_judge_stability.pycovering aggregation math (median, outlier robustness, rounding, clamping), sampling orchestration (partial and total failure paths, call counts via a stub judge), config validation bounds,get_average_judge_stdev, and the noise-aware gate.--dry-runwithjudge.samples: 3,--judge-samples 5override, and--noise-aware-gatewithout--fail-underexits 1 with a clear message.PR opened by Daily Feature Builder. Run log: Hyperagent thread cmta3rei4004x08adr92set04.