Skip to content

FEAT: Updating Scorer Metrics Update Workflow and SelfAskRefusalScorer update#1549

Draft
rlundeen2 wants to merge 19 commits intomicrosoft:mainfrom
rlundeen2:users/rlundeen/2026_02_26_refusal_scorer_update
Draft

FEAT: Updating Scorer Metrics Update Workflow and SelfAskRefusalScorer update#1549
rlundeen2 wants to merge 19 commits intomicrosoft:mainfrom
rlundeen2:users/rlundeen/2026_02_26_refusal_scorer_update

Conversation

@rlundeen2
Copy link
Copy Markdown
Contributor

Updates refusal scorer and shows how to do end to end metrics updates.

Many scorers depend on some core scorer — objective scorers wrap a SelfAskRefusalScorer inside TrueFalseInverterScorer or
TrueFalseCompositeScorer. When the refusal prompt changes (or a new variant performs better), every dependent scorer's
identity hash changes too, invalidating all their cached metrics. This means re-running evaluations for the entire scorer
suite — a process that takes hours — just because the underlying refusal prompt was tweaked. There was no way to evaluate
refusal variants in isolation, pick the best one, and then selectively re-evaluate only the scorers affected by that
change.

This PR introduces tag-based evaluation and auto-detected dependencies so you can iterate on refusal scorers quickly
without re-running everything.

It also updates the refusal scorers and refusal scorer metrics. GPT-5 refused scores in a different way, making our existing refusal scorers less accurate. So this is the consequence of working through that flow.

Refusal Scorer Human Dataset Updates

First, we ran some refusal tests against gpt-5 and evaluated refusals. Many of these were different from previous models. We added many of these to the human-labeled datasets in both refusal and objective scores. We also trimmed down the refusal dataset to a more manageable size, reducing repetitive samples.

We bumped the dataset version making all previous metrics invalid.

Refusal Scorer update

Replaces the single default refusal scorer with 4 named variants, adds auto-dependency detection so wrapper scorers automatically use the best-performing refusal prompt, and provides tag-based batch evaluation via evaluate_scorers.py

  • Replace refusal_default.yaml and refusal_strict.yaml with 4 explicit variants:
  • OBJECTIVE_BLOCK_SAFE / OBJECTIVE_ALLOW_SAFE — require an explicit objective
  • NO_OBJECTIVE_BLOCK_SAFE / NO_OBJECTIVE_ALLOW_SAFE — work with or without an objective
  • Each variant is registered in ScorerInitializer with a refusal tag
  • Expanded human-labeled refusal evaluation dataset (refusal.csv + refusal_extra.csv)
  • Added objective evaluation datasets: chemical/biological, cyber, harassment, illegal activity, misinformation, phishing

Scorer Registry Initializer Update

Dynamic Best-Refusal Selection; now the registry checks for the best refusal scorer, and uses that for all other metrics that need a refusal scorer

  • _register_best_refusal_f1() reads existing metrics from refusal_metrics.jsonl and tags the best variant as
    best_refusal_f1 / default_refusal_scorer
  • Dependent scorers (TrueFalseInverterScorer, composites) are built using the best refusal path
  • Falls back to OBJECTIVE_ALLOW_SAFE when no metrics exist yet
  • ComponentIdentifier._collect_child_eval_hashes() recursively collects eval hashes from child identifiers
  • BaseInstanceRegistry.find_dependents_of_tag() discovers wrapper/composite scorers that embed a tagged scorer, using
    eval_hash matching — no explicit depends_on declaration needed

Evaluation of different components

  • evaluate_scorers.py now accepts --tags CLI filter (e.g., --tags refusal)
  • ScorerInitializer phases: register refusal variants → pick best → build dependents → register remaining → pick best
    objective
  • Documented Recommended workflow: --tags refusal first, then full re-run

(credit: @fdubut for help)

rlundeen2 and others added 19 commits February 24, 2026 17:06
- Remove duplicate seed_type in harms.prompt (both sides added it independently)
- Update stale REFUSAL_GPT4O docstring reference to REFUSAL_GPT4O_OBJECTIVE_ALLOW_SAFE

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tion

- Add _collect_child_eval_hashes() to ComponentIdentifier for recursive
  child eval_hash collection
- Add find_dependents_of_tag() to BaseInstanceRegistry for auto-detecting
  wrapper/composite scorer dependencies via eval_hash matching
- Add 4 refusal scorer variants with REFUSAL tag in ScorerInitializer
- Add _register_best_refusal_f1() to tag the best refusal scorer by F1
  from existing metrics (parallels _register_best_objective_f1)
- Refactor initialize_async into 5 phases: base refusal, best refusal
  selection, dependent scorers, other scorers, best objective selection
- Add --tags CLI filtering to evaluate_scorers.py via argparse
- Add comprehensive unit tests for all new functionality

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Metrics should be regenerated with evaluate_scorers.py after
the new refusal scorer variants are finalized.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Document evaluate_scorers.py usage with --tags filtering and the
recommended two-step workflow: evaluate refusal scorers first,
then re-run all scorers so dependents use the best refusal variant.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Change tags parameter type from list[str] to Sequence[str] to accept
list[ScorerInitializerTags] (list is invariant, Sequence is covariant).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant