fix(evaluation): resolve rubric verdicts per invocation, not per evaluator - #7302
Open
chelsealong wants to merge 1 commit into
Open
chelsealong wants to merge 1 commit into
chelsealong wants to merge 1 commit into
Conversation
…uator RubricBasedEvaluator kept the effective rubric list as shared instance state. LlmAsJudge.evaluate_invocations formats every invocation's prompt before gathering any of the async judge calls, so by the time a response is converted back into a score, the shared list held whatever rubrics the last invocation in the batch had. A verdict for a rubric that belonged to an earlier invocation, but not the last one, was silently dropped with a "not found in the rubrics" warning. Thread the actual invocation through convert_auto_rater_response_to_score and cache the effective rubrics list per invocation so each response is matched against the rubrics of the invocation it was sampled for. Fixes google#7301
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.
Please ensure you have read the contribution guide before creating a pull request.
Link to Issue or Description of Change
1. Link to an existing issue (if applicable):
Problem:
RubricBasedEvaluatorkept the "effective rubric list" as instance state:format_auto_rater_promptcallscreate_effective_rubrics_list(actual_invocation.rubrics),which sets
self._effective_rubrics_list, andconvert_auto_rater_response_to_scorelater reads
get_effective_rubrics_list()to map parsed verdicts back torubrics.
LlmAsJudge.evaluate_invocationsformats the prompt for every invocationfirst (the loop at the top of the method), then gathers all sample tasks. So
by the time any response is converted,
_effective_rubrics_listis whateverthe last invocation's rubrics were. A verdict for a rubric that is on an
earlier invocation but not on the last one is silently discarded with the
warning
Rubric ... not found in the rubrics provided to the metric.. Withthe same rubric on every invocation the bug is invisible, which is why
criterion-level rubrics never hit it.
Solution:
Thread the invocation that a given auto-rater response was sampled for into
convert_auto_rater_response_to_score(new optional parameter, plumbedthrough
LlmAsJudge._evaluate_single_sample), and cache the effectiverubrics list per invocation (keyed by
id(actual_invocation)) instead of ina single shared slot. Each response is now resolved against the rubrics of
the invocation it was actually sampled for, regardless of formatting/gather
order. The existing no-argument behavior of
create_effective_rubrics_list/get_effective_rubrics_listis preserved as a fallback, so callers thatdon't pass an invocation (existing unit tests,
FinalResponseMatchV2Evaluator)are unaffected.
Testing Plan
Unit Tests:
Added
test_evaluate_invocations_scores_each_invocation_against_its_own_rubricsin
tests/unittests/evaluation/test_rubric_based_evaluator.py, which runsevaluate_invocationsend-to-end over two invocations that each carry adifferent, non-overlapping rubric and asserts each invocation's result is
scored against its own rubric.
Confirmed the test fails without the fix (checked out the pre-fix source
for the touched files, keeping the new test):
Also reproduced the exact symptom described in the issue directly against
the real
RubricBasedFinalResponseQualityV1Evaluator(not just the testdouble), with the pre-fix source:
And with the fix applied, both invocations score correctly:
Full evaluation test suite after the fix:
Full unit test suite after the fix:
pre-commit run(ruff, isort, pyink, addlicense, ADK compliance checks) onall touched files: all hooks pass.
Manual End-to-End (E2E) Tests:
Not applicable — this is a pure logic fix in the local eval judge pipeline,
covered by the automated tests above and by re-running the exact repro steps
from the issue against the real evaluator (see above).
Checklist
Additional context
This PR was prepared with AI assistance (Claude Code), with all changes
reviewed and verified by re-running the reproduction from the issue against
the real evaluator, before and after the fix.
🤖 Generated with Claude Code