feat(tasks): add Multi-IF multi-turn multilingual instruction-following - #80
Open
ethan-scitix wants to merge 1 commit into
Open
feat(tasks): add Multi-IF multi-turn multilingual instruction-following#80ethan-scitix wants to merge 1 commit into
ethan-scitix wants to merge 1 commit into
Conversation
Multi-IF extends IFEval into three-turn conversations across eight languages (4,501 conversations). Adds the `multi_if` dataset, the `multi_if_0shot_gen` task, and a `multi-if` optional-dependency group. sieval's first multi-turn task: one sample is one whole conversation, and `infer` walks its turns in order, appending the model's own reply before sending the next user turn. It returns `list[ModelOutput]`, which the runner already special-cases, so every turn's tokens reach the profile. Upstream reaches the same conversation by re-running the whole set once per `--steps` value and writing the growing history back to a CSV; one pass makes a conversation a single unit of work and lets one run report all three turns. Upstream's own multilingual fork of the IFEval checkers is vendored in `sieval/community/multi_if/` rather than reusing the google-research sibling. Both carry the same 25 instruction ids, but Multi-IF's are language-aware (langdetect-routed word/sentence counting, CJK and Hindi counters, Thai tokenizers), so they are not interchangeable. The only local adaptation is a lazy pythainlp import. Grading is verified against upstream's own `metrics_gen` on 535 conversations spanning all eight languages and all 56 two-turn rows: 3,098 strict/loose follow-lists and every per-language `overall` agree exactly. `status="experimental"` all the same — Multi-IF publishes paper scores only, with no per-model inference dump to replay, so no published number has been reproduced yet. Two upstream defects are tracked rather than repaired, per the unqualified-name rule; both make upstream's grader unable to reproduce itself: - Two conversations (6 of 13,447 turn-cells) carry kwargs the checker rejects (`letter="#"`; a missing `keyword`), and `build_description` falls back to an unseeded `random.choice`, grading the response against a letter nobody asked for. - `langdetect` is unseeded, and detection picks the counting algorithm behind every length constraint. Other notes: - The 56 conversations without a third turn get no third generation. Upstream sends them a literal "None" prompt and then drops the row when scoring turn 3, so metrics are unchanged and the tokens are not spent. - Constraints accumulate: turn t is graded against turns 1..t's constraints, verified as a prefix-extension on every row. - Instruction-level accuracy is pooled from raw counts, not averaged from per-sample rates, which differ when turns carry different counts. - `kwargs` stay JSON-encoded in the sample; decoding them would make Arrow unify 24 sparse struct fields per constraint. - The dataset license is CC-BY-NC-2.0 (the Hub card's), not the Apache-2.0 of the code repo that ships the evaluator. 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
Adds Multi-IF (paper · code · data) — IFEval extended into three-turn conversations across eight languages, 4,501 conversations.
inferwalks its turns in order, appending the model's own reply before sending the next user turn, and returnslist[ModelOutput]— a shape the runner already special-cases, so every turn's tokens reachprofile.json. Upstream instead re-runs the whole set once per--stepsvalue, writing the growing history back to a CSV; one pass makes a conversation a single unit of work and is what lets one run report all three turns.sieval/community/multi_if/, not reused fromsieval/community/instruction_following_eval/. Both carry the same 25 instruction ids, but Multi-IF's implementations are language-aware (langdetect-routed word/sentence counting, CJK and Hindi counters, Thai tokenizers), so they are not interchangeable — please don't "deduplicate" them later.metrics_gen, not merely faithful by construction — see the table below.status="experimental": Multi-IF publishes paper scores only, with no per-model inference dump to replay, so no published number has been reproduced yet.Related Issues
None.
Test Plan
Automated
ruff check && ruff format --check)ty check) —tyis the primary checker per CLAUDE.md.mypy --strictis repo-wide noisy (1,426 pre-existing errors in 135 files); the one diagnostic genuinely introduced here (alistinvariance error on the prediction payload) is fixed, and the remainder are the house-style ones every task shares (unannotated@overridestage methods, baredict).tests/unit/suite green at 3,181 passed, no regressions.python scripts/check_preflight.py— 22/22 PASS, includingcheck_dep_coverage,check_meta_index_sync, andcheck_deps(no unrequested lock drift).Manual
Grader fidelity — the port vs. upstream's own evaluator. Both were run on identical
(row, response)pairs and compared per-constraint, not just on the aggregate:follow_instruction_listturn_{t}_{lang}_overallturn_{t}_prompts_numberSample: 535 conversations, language-stratified across all eight languages, including all 56 two-turn rows. The two conversations described below are excluded — they cannot match anything, upstream included.
No score-vs-published table is included, and that is why
status="experimental". The paper reports o1-preview 0.877 → 0.707 (turn 1 → turn 3); reproducing that needs a live run against a checkpoint that is no longer served, and Multi-IF publishes no inference cache to replay the way PlatinumBench and MathArena ports do. This PR ships the half that can be verified offline — the grader and the aggregation — exactly.Also verified manually:
sieval dataset download multi_ifsucceeds;sieval task show multi_if_0shot_genthen reportsReady: yes.t'sinstruction_id_listis a prefix-extension of turnt-1's on every row of the pinned revision, 0 violations.raw.githubusercontent.comat1cdb53ed).Two upstream defects, tracked rather than repaired
Both are documented in
reference_impl.notesand at their source sites. Fixing either would be a grader change, which belongs in a_fixedvariant with a measured delta — not under the unqualified name.random.choice. Two conversations (6 of 13,447 turn-cells, 0.04%) carry kwargs the checker rejects —keywords:letter_frequencywithletter="#", andkeywords:frequencywith nokeyword.build_descriptionthen draws a random letter and grades the response against a constraint nobody asked for, redrawn on every call.langdetectis unseeded, and detection selects the word- and sentence-counting algorithm behind every length constraint (~2–3% of calls flip on short or mixed-script text). Measured exposure is narrower than that rate suggests: observed flips stayed within Latin-script languages, which share a counting branch.Other deviations from upstream
"None"prompt and then drops the row when scoring turn 3 — identical metrics, tokens not spent. Turn-3 denominators are 4,445, andreport.jsoncarriesturn_{t}_prompts_numberso this is visible rather than inferred.scoreis the mean of the three turns' all-language overalls. Upstream emits one report per turn and never reduces them; a task needs one headline, and every component is in the report.Checklist
Required (all PRs)
type(scope): description)AI-Generated Code - <model> (<provider>)in module docstring (the vendored upstream files carry Meta's Apache-2.0 header instead, as they are not AI-generated)core/—core/is untouchedIf: New or Modified Benchmark
Score comparison table included (model, expected, actual, diff)— not possible for this benchmark; the grader-fidelity table above is the substitute, andstatus="experimental"records the gap. See the Manual section.sieval dataset download multi_ifsucceeds)__init__.py(lazy registry + regenerated__init__.pyiandmeta/index.json)If: community/ Changes
sieval/community/multi_if/__init__.pyenumerates every adaptation. Only one behavioural change:pythainlpis imported lazily instead of at module scope.evaluation_lib.pytakes only the two per-response graders from upstream'smetrics.py(its surrounding pipeline is a pandas/scipy CSV driver sieval does not use). The unseededlangdetectis deliberately left as-is, with a note explaining why the obvious fix is absent.If: New Dependency
multi-ifextra; group name inserted intopdm.lock[metadata].groupsfirst, thenpdm lock --update-reuse, per.claude/rules/deps.md. Lock diff is +27/−12 withpythainlpthe only new package;check_depsconfirms no unrequested drift.ifevalgroup: the fork uses stdlibloggingandMappingProxyType, soabsl-py/immutabledictare not needed, whileemojiis required rather than optional because the CJK word counter behind every Chinese length constraint counts emoji as words.pythainlpis declared but lazily imported: it is only reached if langdetect reports Thai for a model response (Thai is not one of the dataset's eight languages), and declaring it keeps that path from dying onImportErrormid-run.Note on the dataset license
license="CC-BY-NC-2.0"— the Hub dataset card's license, which is not the Apache-2.0 of thefacebookresearch/Multi-IFcode repo that ships the evaluator. The data is non-commercial; the two licenses differ andDatasetMeta.licenserecords the data's.🤖 Generated with Claude Code