Repository navigation
fix(eval): honor a stated "answer is X" in multiple choice - #3668
Merged
Merged
Conversation
BaseBenchmark._extract_mc_answer upper-cases the response before it looks for the "answer is X" cue, but the cue in the regex is lower-case and no IGNORECASE flag was passed, so step 1 of the documented strategy never matched anything. Every response fell through to step 2, the last valid letter anywhere in the text, which means any letter the model mentioned after stating its answer overwrote it. Passing re.IGNORECASE to that findall makes step 1 work as documented. Steps 2 and 3 are untouched, so a response with no stated-answer cue still resolves to its last valid letter. The fix sits at the one shared call site, so all twelve benchmarks that route through this helper get it.
jundot
approved these changes
Sep 16, 2026
jundot
left a comment
Owner
There was a problem hiding this comment.
The shared multiple-choice extractor now honors explicit answer is X and answer: X cues regardless of casing. This prevents letters in trailing explanations from overwriting the model's stated answer, including the MMLU-Pro case where I could be mistaken for a choice. I traced the change through all 12 callers and confirmed that the no-cue fallback remains unchanged. LGTM; ready to merge.
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.
Summary
A multiple choice answer is scored against the wrong letter whenever the model states its answer and then keeps talking.
BaseBenchmark._extract_mc_answerdocuments a three step strategy whose step 1 is to look for an explicit "answer is X" cue, but that step can never fire, so extraction always falls through to "last valid letter anywhere in the response". Any letter mentioned after the answer overwrites it.On MMLU-Pro the labels run A to J, so the ordinary English word "I" is harvested as the prediction.
MMLUProBenchmark.extract_answer("The answer is C because I computed the integral.", item)returns'I'. Of the 12,032 questions inomlx/eval/data/mmlu_pro_test.jsonl, 10,782 carry anIlabel.Root cause
omlx/eval/base.py:124-131. The haystack is upper-cased so the letter class matches, but the cue in the pattern is lower-case and no flag is passed:ANSWER IS Dnever matchesanswer\s*(?:is|:). The docstring's third promise is literally "Case-insensitive", which is the one property the call lacks. Every existing assertion that pins step 1 (tests/test_eval.pylines 30, 34, 44, 48 and 49) passes only by coincidence, because in each string the stated letter is also the last valid letter present.Fix
Twelve benchmarks route through this one helper (mmlu, mmlu_pro, arc, hellaswag, truthfulqa, bbq, mathqa, safetybench, winogrande, cmmlu, jmmlu, kmmlu), so the single call site covers all of them. Steps 2 and 3 are untouched: a response with no stated-answer cue still resolves to its last valid letter, so "Looking at A and B, B is correct" stays
B, "The answer is not A, it is B" staysB, and an empty or letterless response still returns"". The one shape that moves the other way is a stated answer followed by a revision that does not repeat the cue: "The answer is A. Actually, I'll go with B." now returnsAwhere it returnedB. That is the documented step-1-wins order, and a revision that says "the answer is" again still gets its last stated letter.Verification
I added two tests to
TestMMLUintests/test_eval.py. On main at ddc4718 they are red:Green with the fix:
I also ran the old and new extractor side by side over sixteen response shapes. Nine are byte identical:
"", "I don't know", "B", "A. Abstract algebra", "Looking at A and B, B is correct", "The answer is not A, it is B", "B is wrong because... The answer is A", "I initially thought C but answer is D" and "answer: 1". Seven change, each onto the stated letter: "The answer is B. Note that A is a distractor." A to B, "Answer: C. Option D looks similar." D to C, "ANSWER IS D. A is incorrect." A to D, "the answer is a, not b" B to A, "The answer is C because I computed the integral." I to C with A to J labels, "The answer is F. I considered E as well." E to F, and winogrande's["1","2"]on "The answer is 2. 1 is wrong." 1 to 2.Adjacent suites:
tests/test_accuracy_benchmark.py,tests/test_accuracy_upload.py,tests/test_bench_external_routes.py,tests/test_benchmark_sse_replay.py,tests/test_eval_worker_pool.pyandtests/test_benchmark.pygive 244 passed in 4.77s. I did not run the full CI filtered suite locally; my environment is missing several of the heavy pins.Lint, scoped to the two touched files with ruff 0.16.7 and black 26.5.1: ruff reports 13 errors on
omlx/eval/base.pyand 3 ontests/test_eval.py, and black would reformat both. Those counts are identical before and after my change, so nothing new was introduced and nothing was reformatted.No live model run, so this is not an end to end accuracy measurement. The tests exercise the real production path from the subclass
extract_answerdown intoBaseBenchmark._extract_mc_answer.