Skip to content

Scorer evaluation fails when the dataset harm category differs from the harm definition category #2570

Description

@varunj-msft

Summary

Scorer.evaluate_async() raises ValueError for any harm dataset whose CSV harm_category label differs from the category declared in its harm-definition YAML. Two of PyRIT's own shipped evaluation datasets hit this, so python -m build_scripts.evaluate_scorers cannot produce metrics for them.

Reproduction

Observed during the v1.1.0 release run of python -m build_scripts.evaluate_scorers:

File "pyrit/score/scorer_evaluation/scorer_evaluator.py", line 418, in evaluate_dataset_async
    score = self._select_evaluation_score(scores=scores, harm_category=harm_category)
File "pyrit/score/scorer_evaluation/scorer_evaluator.py", line 504, in _select_evaluation_score
    raise ValueError(
ValueError: Scorer evaluation requires a score for harm category 'bias',
but the single score returned is categorized as ['fairness_bias'].

and

ValueError: Scorer evaluation requires a score for harm category 'sexual_content',
but the single score returned is categorized as ['sexual'].

Root cause

Two different namespaces are being compared:

Dataset CSV harm_category Harm definition YAML category
scorer_evals/harm/fairness_bias.csv bias harm_definition/fairness_bias.yaml fairness_bias
scorer_evals/harm/sexual.csv sexual_content harm_definition/sexual.yaml sexual

The scorer emits score_category from the YAML, while the evaluator compares it against the dataset label. The codebase already documents that these names legitimately diverge — scorer_evaluator.py:192-193:

# The CSV header is authoritative since the harm_category name may differ from
# the YAML filename (e.g., harm_category="bias" but file is "fairness_bias.yaml").

The remaining 6 of 8 harm datasets (violence, privacy, self_harm, exploits, hate_speech, information_integrity) happen to use identical names on both sides, which is why only these two fail.

Regression window

_select_evaluation_score was introduced by #2491 (0899b2144, "FEAT: Refactoring score model (phase 2)"). The previous implementation performed no category matching at all:

scores = await self.scorer.score_prompts_batch_async(...)
score_values = [score.get_value() for score in scores]

Both fairness_bias_metrics.jsonl and sexual_metrics.jsonl contain rows generated as recently as 0.14.0.dev0, confirming evaluation previously succeeded for these datasets.

Suggested fix

When the scorer returns exactly one score, take it. That is what the function's own docstring already describes:

A lone score is taken as the answer, because most scorers report one verdict and leave score_category empty.

With a single score there is no ambiguity about which score to select, so the category comparison adds no disambiguation value and only produces false failures. The multi-score branch genuinely needs category matching and should keep it.

Alternatively, reconcile the two namespaces explicitly (map dataset label → harm-definition category) so the check can stay strict.

Impact

Evaluation/benchmarking only. Normal scoring (score_async), attacks, and the rest of the runtime are unaffected. Metrics for these two harm categories remain at their 0.14.0.dev0 values.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions