Add MulticlassJudge detector for configurable LLM-as-judge classification - #1773
Add MulticlassJudge detector for configurable LLM-as-judge classification#1773ABeltramo wants to merge 7 commits into
Conversation
e89c4fa to
0cfc5f0
Compare
|
From a quick glance it seems that the CI failures are unrelated to this PR. This test has no |
|
The test failure is from an environment requirements change in the |
immu4989
left a comment
There was a problem hiding this comment.
Third in the judge family review pass after #1717 and #1725. Different shape than either: rubric scoring on one side, classifier-token on the other, JSON-mode classification here. A few technical notes.
JSON extraction is brittle. _strip_code_fences finds the first { and last } in the response text. That works for the canonical case ("here is the JSON: { ... }") and for code-fenced output, but it breaks when the judge model wraps the answer with prose that itself contains braces. Real example I've hit: The model's reasoning included compliance markers like { brackets in code blocks }. My classification: {"complied": 80, ...}. Current logic grabs from the brace in the prose through to the closing brace of the JSON, producing invalid input. A regex anchored on the JSON object pattern, or json.loads over a sliding window of candidates, would be sturdier. Adjacent option: most modern OpenAI-compatible APIs (OpenAI, Together, Groq, Fireworks, vLLM) support response_format={"type": "json_object"} as a server-side guarantee. The PR already monkey-patches extra_params["response_format"] for the response_schema case; doing the same for the response_format == "json" default would give a much stronger reliability floor than prompt-only instructions.
__init__ mutates the shared generator instance. When response_schema is set the code writes to self.evaluation_generator.extra_params. If the same configured generator is reused by another detector, or by another instance of MulticlassJudge with a different schema, the side effect leaks. Probably not a frequent scenario in practice (most runs use a single judge config), but worth a note in the docstring or a deepcopy of the generator before the mutation.
confidence_cutoff scale differs silently from ModelAsJudge. The parent uses confidence_cutoff=7 on a 1-10 rating. This subclass uses confidence_cutoff=70 on a 0-100 percentage scale. Both numbers happen to mean "70%" but a user inheriting muscle memory from ModelAsJudge could mis-set it. Worth a single sentence in the class docstring calling out the scale.
Milestone-12 note. Same point I raised on #1725: attempt.notes["multiclass_scores"] is a sensible v1, and after the technique-and-intent work in #1434 lands the canonical detector-output slot is likely to shift. No action needed, just keeping the threads visible.
Things done well. Subclassing ModelAsJudge cleanly, the dual config-param pattern (system_prompt + user_prompt_template) that makes the judge fully customisable, the code-fence stripping (mechanism aside) handling the common JSON-in-markdown case, parameterised test coverage including malformed and missing-key paths, and the explicit opt-out fallback to the existing rating parser. The PR is genuinely close to a useful piece of shared infrastructure.
Looking forward to seeing this and the other two land.
7891bce to
3e75cab
Compare
|
Hi @immu4989 thanks for taking the time to test and review this PR! All very good points, I should've addressed everything:
I'm also really looking forward to |
|
@ABeltramo , Glad the suggestions were useful, and impressed by the turnaround. On Milestone 12: same here. The notes key plumbing is the right v1, and migration will be cheap once the canonical field lands. Looking forward to seeing this merge. |
|
@ABeltramo, apologies it looks like github did not auto-retarget on |
|
@ABeltramo heads up, I got the same note on #1979. In my case a rebase onto |
jmartin-tech
left a comment
There was a problem hiding this comment.
This seems viable, the embedded prompts seem a bit restrictive and cause issues for detector --plugin_info output.
Can you offer a suggested way to validate this detector? Is there some probe that it would work well with when set to override the primary or extended detectors?
| "system_prompt": DEFAULT_MULTICLASS_SYSTEM_PROMPT, | ||
| "user_prompt_template": DEFAULT_MULTICLASS_USER_PROMPT, |
There was a problem hiding this comment.
Consider defaulting these to None and having the __init__ fallback to the constants if the user did not provide an override.
Reasoning, DEFAULT_PARAMS are listed in --plugin_info results as well as added to the plugin cache file, and long text blocks do not format well as this time.
As an alternative, these values could be stored in a data fixture file and the detector could offer configuration of the at file location instead of a hardcoded constant in the module. This would allow a user level override via the XDG_DATA path or accept a specific filename from the configuration.
There was a problem hiding this comment.
Right, I see. Defaulted to None and used __init__ as the fallback
|
Two things that might help with @jmartin-tech's points, though the validation question is yours to answer. On the DEFAULT_PARAMS feedback: Worth flagging a naming collision though. #1832 (open, unreviewed) is already applying that same None default plus On validation, one option if it is useful: your default system prompt already targets dan style dual output, since it enumerates 'DAN', 'developer mode', 'AIM', 'NRAF' and 'Anarchy' and says to evaluate only the jailbreak section. The |
…tion Introduces a new MulticlassJudge detector that extends ModelAsJudge with JSON-aware response parsing and user-defined classification categories (e.g. complied/rejected/alternative/other). Supports configurable system and user prompts, custom score keys/fields, confidence thresholds, and optional JSON schema injection for structured output APIs. Signed-off-by: ABeltramo <beltramo.ale@gmail.com>
Signed-off-by: ABeltramo <beltramo.ale@gmail.com>
Signed-off-by: ABeltramo <beltramo.ale@gmail.com>
Signed-off-by: ABeltramo <beltramo.ale@gmail.com>
Signed-off-by: ABeltramo <beltramo.ale@gmail.com>
Added comment for `confidence_cutoff` Signed-off-by: ABeltramo <beltramo.ale@gmail.com>
3e75cab to
348133e
Compare
Address review feedback (NVIDIA#1773): the long default system/user prompts were embedded directly in DEFAULT_PARAMS, cluttering `--plugin_info` output and reading as restrictive. Follow the existing judge-family pattern (cf. Jailbreak.custom_system_prompt): default the prompt params to None and fall back to `_multiclass_system_prompt` / `_multiclass_user_prompt` class constants in __init__. Rename `system_prompt` to `system_prompt_judge` to reuse the parent ModelAsJudge key name and avoid introducing a third name for the judge system prompt across the family. Users can still override both prompts via config. Add tests covering the None defaults, fallback population, and user override. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks for the feedback @immu4989 and @jmartin-tech I should've addressed the defaults, and I was looking at the validation part, but I think I'm missing something here.. It looks like only the precomputed summary ships in the repo, I couldn't find the labelled benchmark dataset or the evaluation harness that produces it; can you point me at how |
|
The pipeline that generates @ABeltramo please edit the commit messages to ensure sign-off is included to meet the DCO requirements. |
Address review feedback (NVIDIA#1773): the long default system/user prompts were embedded directly in DEFAULT_PARAMS, cluttering `--plugin_info` output and reading as restrictive. Follow the existing judge-family pattern (cf. Jailbreak.custom_system_prompt): default the prompt params to None and fall back to `_multiclass_system_prompt` / `_multiclass_user_prompt` class constants in __init__. Rename `system_prompt` to `system_prompt_judge` to reuse the parent ModelAsJudge key name and avoid introducing a third name for the judge system prompt across the family. Users can still override both prompts via config. Add tests covering the None defaults, fallback population, and user override. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ABeltramo <beltramo.ale@gmail.com>
4dbf18c to
02fa0fa
Compare
|
@jmartin-tech sorry about that, should be fixed now |
Introduces a new
MulticlassJudgedetector that extendsModelAsJudgewith JSON-aware response parsing and user-defined classification categories (e.g. complied/rejected/alternative/other). Supports configurable system and user prompts, custom score keys/fields, confidence thresholds, and optional JSON schema injection for structured output APIs.Cherry-picked from trustyai-explainability/garak:automated-red-teaming