Source code for eval_framework.benchmarks.ifeval
"""IFEval: Instruction Following Eval (https://arxiv.org/pdf/2311.07911).
The model follows a natural-language prompt carrying verifiable constraints (word counts, formats, casing, …).
The instruction checks run from a per-sample ``IFEvalMetricContext``, so the task has no gold answer and is
0-shot only.
"""
from typing import TYPE_CHECKING, Any
from eval_framework.answer import ExtractFromCompletion
from eval_framework.composed import ComposedBenchmark, LanguageSpec
from eval_framework.contract import Benchmark
from eval_framework.eval_kind import Generative
from eval_framework.fewshot import NoFewShot
from eval_framework.metrics.completion.ifeval import IFEvalMetric, IFEvalMetricContext
from eval_framework.metrics.completion.language_checker import LanguageRawConsistencyChecker
from eval_framework.tasks.base import Language
from eval_framework.tasks.dataset_loading import DatasetPolicy
from eval_framework.tasks.dataset_revisions import pinned_by_framework
if TYPE_CHECKING:
from eval_framework.metrics.base import BaseMetric
IFEVAL_DATASET_PATH = "google/IFEval"
IFEVAL_DE_DATASET_PATH = "jzhang86/de_ifeval"
def _ifeval_context(item: dict[str, Any]) -> IFEvalMetricContext:
new_kwargs = []
for d in item["kwargs"]:
# Some dataset variants type integer kwargs as float; int() below must not truncate anything.
assert all(v.is_integer() for v in d.values() if isinstance(v, float)), f"Non-integer float in {d}"
# None marks an absent kwarg; dropping it gives dense and sparse dataset shapes the same context.
new_kwargs.append({k: int(v) if isinstance(v, float) else v for k, v in d.items() if v is not None})
return IFEvalMetricContext(
key=item["key"],
instruction_id_list=item["instruction_id_list"],
prompt=item["prompt"],
additional_kwargs=new_kwargs,
)
def _ifeval(
id: str,
*,
dataset_path: str,
metrics: list[type["BaseMetric"]],
language: LanguageSpec,
dataset: DatasetPolicy | None,
) -> Benchmark:
kind = Generative(
build_prompt=lambda item: item["prompt"],
cue="", # the model answers directly; no assistant cue
ground_truth=lambda item: None, # no gold answer — scored from the context's instruction checks
metrics=metrics,
context=_ifeval_context,
)
answer = ExtractFromCompletion(lambda completion_text: completion_text) # checks run on the whole generation
dataset_policy = dataset if dataset is not None else pinned_by_framework(dataset_path)
return ComposedBenchmark.compose(
id=id,
kind=kind,
answer=answer,
sample_split="train",
fewshot=NoFewShot(),
dataset_policy=dataset_policy,
language=language,
)
[docs]
def ifeval(dataset: DatasetPolicy | None = None) -> Benchmark:
return _ifeval(
"IFEval", dataset_path=IFEVAL_DATASET_PATH, metrics=[IFEvalMetric], language=Language.ENG, dataset=dataset
)
[docs]
def ifeval_de(dataset: DatasetPolicy | None = None) -> Benchmark:
return _ifeval(
"IFEvalDe",
dataset_path=IFEVAL_DE_DATASET_PATH,
metrics=[IFEvalMetric, LanguageRawConsistencyChecker],
language=Language.DEU,
dataset=dataset,
)
IFEVAL_BENCHMARKS: list[Benchmark] = [ifeval(), ifeval_de()]