FEAT Add dedicated LlamaGuard scorer#1867
Conversation
…rd support Per the design discussion in microsoft#1830, extend SelfAskTrueFalseScorer with an optional response_parser callable so the same scorer can wrap fine-tuned safety classifiers (LlamaGuard, ShieldGemma, WildGuard, HarmBench-paper) whose output is not JSON. Default behavior is unchanged. Ships a parse_llamaguard_response helper plus YAML assets (TrueFalseQuestion and system prompt) so users can drop in any LlamaGuard-serving endpoint via PromptChatTarget. No local transformers or torch dependency. Also fixes a latent typing issue in Scorer._score_value_with_llm: score_value_description now defaults to '' when the response omits the description field, instead of being None against a str-typed field.
romanlutz
left a comment
There was a problem hiding this comment.
I don't have a llama-guard deployment and can't test this. Can you confirm that you did test it?
The PR has not been exercised against a live LlamaGuard endpoint. The tests cover the plumbing in two places:
What is not covered: the actual LlamaGuard-3-8B chat template rendering and the round-trip through a real endpoint. If a live smoke test against Together/Groq/Fireworks would help you merge with confidence, I am happy to run one and paste the transcript here. I held off on writing that as a unit-suite test because it would require a configured API key and would not be reproducible in CI. |
- Wire YAMLs into discoverable paths: add TrueFalseQuestionPaths.LLAMAGUARD and LLAMAGUARD_SYSTEM_PROMPT_PATH module-level constant. - Drop misleading 'parameters' declaration in llamaguard_system_prompt.yaml; template is static. - Switch :class: reST cross-references to plain double-backticks in scorer.py and self_ask_true_false_scorer.py (PyRIT docs build is MyST). - Reorder __all__ in pyrit/score/__init__.py: parse_llamaguard_response between ObjectiveScorerMetrics and PlagiarismMetric, LLAMAGUARD_SYSTEM_PROMPT_PATH between LikertScalePaths and MarkdownInjectionScorer.
# Conflicts: # pyrit/score/__init__.py
# Conflicts: # pyrit/score/__init__.py # pyrit/score/scorer.py # pyrit/score/true_false/self_ask_true_false_scorer.py
# Conflicts: # pyrit/score/scorer.py # pyrit/score/true_false/self_ask_true_false_scorer.py
|
Friendly bump on this. Conflicts resolved twice now and merge-state is clean apart from the four conversations I've marked addressed. Happy to apply any further changes if you'd like, or close if direction has shifted. |
|
Closing this. The Glad Thanks for the review time on this one. |
…r' into feat/llamaguard-scorer # Conflicts: # pyrit/score/true_false/self_ask_true_false_scorer.py
# Conflicts: # pyrit/score/__init__.py # pyrit/score/scorer.py # pyrit/score/true_false/self_ask_true_false_scorer.py
Ship the LlamaGuard parser and static prompt as production components for SelfAskTrueFalseScorer through CallableResponseHandler. Replace the architecture pilot with coverage of the exported assets and metadata contract. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9be2dff6-a4fb-4690-9f8d-767dea2f98bd
Not at all, I am glad it was useful, and happy to revive it. Seeing the series land, the composition approach is clearly the better home for this than the Since #2125 through #2157 removed that hook, reviving this means reworking the PR onto the new API rather than merging as is. Concretely: drop the old One consolidation note: a few hours before you reopened this, I filed #2172 proposing exactly that, the LlamaGuard parser and prompt on I will start the rework unless you would rather shape the approach first. |
|
@immu4989 i was curious to see if it would go as cleanly as I thought. See the current PR state. Is this in line with your thinking? |
|
Yes, this is exactly it. I pulled the branch and ran it: the two new test files pass (16), the full One small optional thing from reading the parser: the On consolidation: this supersedes #2172, which I filed proposing this same work a few hours before you reopened here, so this PR can close it. I will add a pointer there. I would also be glad to follow up with ShieldGemma and WildGuard on the same handler once this lands. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9be2dff6-a4fb-4690-9f8d-767dea2f98bd
|
I suspect it's better to have a proper scorer vs what's in the PR right now. I'll just push now so that you can see what that looks like but I can remove that commit, too. |
|
I think the dedicated scorer is the better call, and it does not conflict with the composition direction. It still composes What the dedicated class buys over raw composition is the LlamaGuard-specific structure a generic scorer plus parser cannot express cleanly: Ran it here: the new One follow on this shape makes easy: ShieldGemma and WildGuard could each be the same pattern, a small policy plus parser plus dedicated scorer, once this lands. Happy to take those. |
Yes that's exactly what I was thinking! |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9be2dff6-a4fb-4690-9f8d-767dea2f98bd
…r' into feat/llamaguard-scorer
|
I made a few more minor changes. @immu4989 do you happen to have a deployment to test this? |
Fixes #1830.
Summary
Adds a dedicated
LlamaGuardScorerbuilt on the scorer-composition API introduced by #2125, #2146, and #2157. The bundled default targetsmeta-llama/Llama-Guard-3-8Band its S1-S14 policy. The scorer sends Llama Guard's native plain-text classification request and parses its nativesafe/unsafe\nS1,S6response without adding a genericSelfAskTrueFalseScorerhook.LlamaGuardMessageRole.USERand.AGENTrequest framing, defaulting to Agent for model-response classification.Scorewithout inserting it into the Llama Guard conversation.pyrit/datasets/score/llamaguard/.LlamaGuardPolicyandLlamaGuardCategoryvalue types for validated custom taxonomies and optional category descriptions.Usage
User-input classification is available with
message_role=LlamaGuardMessageRole.USER. Custom policies can be loaded withLlamaGuardPolicy.from_yaml(...)and passed through thepolicyargument. The 1B model uses S1-S13 rather than the bundled 8B S1-S14 policy and therefore requires a matching custom policy.Validation
ty: passed.The endpoint round trip is covered with a mocked
PromptTarget; this has not been exercised against a live Llama Guard deployment.