feat(tasks): add AdvancedIF rubric-graded instruction-following benchmark - #79
Open
ethan-scitix wants to merge 1 commit into
Open
feat(tasks): add AdvancedIF rubric-graded instruction-following benchmark#79ethan-scitix wants to merge 1 commit into
ethan-scitix wants to merge 1 commit into
Conversation
…mark AdvancedIF (Meta, arXiv:2511.10507) is 1,645 expert-written prompts paired with human-curated rubrics, spanning complex single-turn (402), system steerability (507) and carried-context multi-turn (736) instruction following. A grader LLM answers every rubric question and declares whether the response satisfied all of them; the headline score is the overall pass rate, with the co-published micro rubric rate and a per-aspect breakdown. The judge prompts are NOT vendored. Upstream ships every file under CC-BY-NC-4.0, which cannot be redistributed inside this Apache-2.0 tree, so the operator stages their own checkout and points SIEVAL_ADVANCED_IF_SRC at it; the loader sha256-pins judge.py to commit f9d3013 and refuses a drifted revision. The benchmark data carries the same terms and is likewise only referenced, so running AdvancedIF accepts them either way. Loading the prompts from the operator's checkout also makes them byte-exact by construction rather than by review. Upstream's judge routing is reproduced with its defect intact: it selects the system-steerability judge on benchmark_name == "if_system_steerability _oss", a value the released dataset never contains (it ships "system_steerability_v2"), so all 507 system-prompt rows are graded by the user-instruction judge and the CLI's --task choices match zero rows. processor.process_file's own docstring uses the released spelling, so the if_*_oss literals are what went stale. The unqualified task name tracks upstream including defects; correcting the routing moves scores on a third of the benchmark and belongs in a _fixed variant carrying a measured delta. A test pins the behaviour so a "cleanup" cannot silently change scores. The two published rates deliberately do not share a denominator: the per-sample rubric rate divides by the rubric count the data carries, while the pooled micro rate counts every answer key the grader emitted. Both are kept, each matching its own upstream definition, with the raw counts a pooled rate cannot reconstruct persisted per rollout. Deviations, both documented in sieval/community/advanced_if.py: the reply parser falls back to extracting fenced JSON, because sieval cannot force response_format=json_object on an arbitrary grader endpoint the way upstream's OpenAI client does; and non-string rubric answers are stringified rather than aborting the row. The whole rubric goes to the grader in one indexed call per rollout, so its ModelOutput is stored as a single mapping and its spend reaches profile.json (iter_grader_outputs skips a list). status="experimental": faithful port, no published number reproduced -- the paper's figures come from Meta's internal pipeline, not the released CLI. Co-Authored-By: Claude Opus 5 (1M context) <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.
Type
Summary
score= overall pass rate, with the co-publishedmicro_pass_rateand a per-aspect breakdown.sieval/, only NClicense=metadata on dataset pointers. The operator stages their own checkout and pointsSIEVAL_ADVANCED_IF_SRCat it; the loader sha256-pinsjudge.pytof9d3013and refuses a drifted revision. The data is CC-BY-NC-4.0 too and likewise only referenced, so running this benchmark accepts the upstream terms either way. Side benefit: the prompts are byte-exact by construction rather than by review.benchmark_name == "if_system_steerability_oss", a value the released dataset never contains (it shipssystem_steerability_v2) — so all 507 system-prompt rows are graded by the plain user-instruction judge, and the CLI's--taskchoices match zero rows.processor.process_file's own docstring uses the released spelling, so theif_*_ossliterals are what went stale. Persieval/tasks/CLAUDE.md, the unqualified name tracks upstream including defects; correcting the routing moves scores on a third of the benchmark and belongs in a_fixedvariant carrying a measured delta. A test pins the behaviour so it cannot be "cleaned up" silently.micro_pass_ratecounts every answer key the grader emitted. Both are kept, each matching its own upstream definition, with the raw counts a pooled rate cannot reconstruct persisted per rollout.ModelOutputis stored as a single mapping and its spend reachesprofile.json(iter_grader_outputsskips a list).status="experimental"— faithful port, no published number reproduced (see Manual below).Test Plan
Automated
ruff check && ruff format --check— clean acrosssieval/andtests/)ty checkclean;mypy --strictemits only the same pre-existingno-untyped-def/type-argclasses as the sibling grader tasksimpleqa_verified_0shot_gen)Also clean:
scripts/check_preflight.py(all checks, no FAIL/WARN), andsync_meta_index.py --check/sync_package_stubs.py --check.Manual
judge.pyimports, and both judge prompts compose with every slot filled (judge_prompt1,048 chars; system-steer 28,587 chars incl. the 27,227-char few-shot block). A realistic grader reply then parses and scores correctly. The 27KB few-shot block is also the concrete reason vendoring was not an option.sieval dataset download advanced_ifsucceeds andsieval task show advanced_if_0shot_genreportsReady: yes. Loaded rows match the modelled schema exactly: 1,645 rows, threestrcolumns,trainmirrored totest, andbenchmark_namecounts 402 / 507 / 736 as documented.status="experimental"; validation is follow-up work, and any_fixedrouting variant is blocked on the same measurement.Checklist
Required (all PRs)
type(scope): description)AI-Generated Code - <model> (<provider>)in module docstringcore/If: New or Modified Benchmark
sieval dataset download advanced_ifsucceeds)__init__.py(lazy auto-discovering registry;__init__.pyistubs +meta/index.jsonregenerated, and name resolution verified viasieval task show)If: community/ Changes
sieval/community/advanced_if.pyenumerates the reproduced routing defect plus two deviations: a fenced-JSON parse fallback (sieval cannot forceresponse_format=json_objecton an arbitrary grader endpoint the way upstream's OpenAI client does — without it a grader that fences its JSON would score zero everywhere, a harness artifact rather than a model property), and stringifying non-string rubric answers instead of aborting the row.license=field, and the task'sreference_impl.notes.Running it
🤖 Generated with Claude Code