fix(evals): keep sampled-out items out of the experiment pass rate - #1397
fix(evals): keep sampled-out items out of the experiment pass rate#1397CTWalk wants to merge 1 commit into
Conversation
An item whose scorers were all sampled out has no evaluation evidence, but
evaluateItemStatus() returns "passed" for it, so it counted in both the
numerator and the denominator of summary.passRate. Lowering scorer sampling
therefore pushed the pass rate toward 1, and a { type: "passRate" } criterion
could pass on a run where nothing was scored.
Exclude those items from the pass rate on both sides, matching the scorer
aggregate, which already leaves skipped results out of its own denominator. A
run with nothing evaluated now reports null. successCount, failureCount,
errorCount, skippedCount and item status are unchanged.
Developed with AI assistance.
🦋 Changeset detectedLatest commit: 35a5fdd The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThe experiment aggregator now calculates pass rates from evaluated items. Items with all scorers sampled out do not affect pass rates. Runs with no evaluated items return ChangesPass-rate correction
Estimated code review effort: 3 (Moderate) | ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
All reported issues were addressed across 4 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
PR Checklist
Please check if your PR fulfills the following requirements:
Bugs / Features
What is the current behavior?
An experiment item whose scorers were all sampled out counts as a pass in
summary.passRate.evaluateItemStatus()sees a score list with nothresholdPassed === falseand returns
passed, so the item lands insuccessCount(
packages/evals/src/experiment/run-experiment.ts:456).passRateis thensuccessCount / completedCount(aggregator.ts:144), and the item is in boththe numerator and the denominator — even though nothing about it was evaluated.
The same criterion resolves two different ways today:
A scorer's own
passRateispassCount / (passCount + failureCount)(
aggregator.ts:179) — skipped results are already left out of thedenominator. The item-level pass rate does not do the same, so
{ type: "passRate", min: 1 }and{ type: "passRate", min: 1, scorerId: "x" }can disagree on one run.Repro
Because sampling is a cost control, the realistic shape is partial: with 100
items at 10 % sampling, ~90 unevaluated items are counted as passes, so the
pass rate sits near 1 regardless of how the evaluated 10 did. The practical
effect is that a
passRatecriterion gets easier to satisfy the less youevaluate — including in the setup the evaluation docs suggest for a regression
test (
passCriteria: { type: "passRate", min: 1.0 }).What is the new behavior?
Items whose every scorer was skipped are excluded from the pass rate, on both
sides of the fraction. A run with nothing evaluated reports
passRate: null,the same "no data" value already used for
meanScoreand for a scorer-scopedpass rate with no attempts. With that, the two spellings of the criterion agree.
passRatebefore1null0.500.670.51successCount,failureCount,errorCount, andskippedCountkeep theircurrent meanings, and item status is untouched.
Added two regression tests beside the existing experiment specs: a mixed run
(one item below threshold, one errored, one skipped) that reported
0.33before and reports
0now, and a fully sampled-out run that pinspassRate: nullplus agreement between the scoped and unscoped criteria.Notes for reviewers
The change is confined to
aggregator.ts, which the package does not export,so no public type changes and no changeset beyond a
@voltagent/evalspatch.One consequence worth flagging: with sampled-out items present,
summary.passRateis no longersuccessCount / completedCount. Anythingdownstream that recomputes a pass rate from those counts — including consumers
of the summary
voltops/run.tsuploads — would differ from the reportedpassRateby exactly the sampled-out items.mapSummarycurrently sendssuccessCount,failureCount,meanScoreandpassRate; happy to addskippedCountthere too if that is useful on your side.One neighbouring question this PR deliberately does not decide: a
sampled-out item still has item status
passed, while the offline-evaluationdocs list
skippedas an item status and defineskippedCountas "items withstatus
skipped". Reconciling those would mean adding"skipped"toEvalResultStatus/VoltOpsEvalResultStatus, which is forwarded to VoltOps(
packages/evals/src/voltops/run.ts:407) — whether the API accepts that valueis something only you can tell from here. Glad to follow up either way; this
fix holds under both outcomes.
Developed with AI assistance. I ran the repro above and the
@voltagent/evalssuite myself against
main, and I'm answerable for everything in the diff.Summary by cubic
Fixes inflated experiment pass rates by excluding items whose scorers were all sampled out. Pass criteria now reflect only evaluated items and match scorer-scoped pass rates.
Bug Fixes
summary.passRate(both numerator and denominator).passRate: nullwhen nothing was evaluated.successCount,failureCount,errorCount, andskippedCountunchanged.website/evaluation-docs.Migration
summary.passRatemay no longer equalsuccessCount / completedCountwhen sampling is used. Update any downstream recomputations accordingly.Written for commit 35a5fdd. Summary will update on new commits.
Summary by CodeRabbit
Bug Fixes
nullpass rate instead of an inflated result.Documentation