Shieldstral is a compact 3B-parameter, policy-adaptive multimodal safety classifier. Instead of predicting a fixed set of moderation categories, Shieldstral evaluates content against a safety policy expressed in natural language and returns a single continuous safety score. This makes it a flexible drop-in guardrail for text-only, image-only, and text+image moderation that can be re-targeted to new policies at inference time, without retraining.
It is built on Ministral-3-3B-Base-2512 with a native Pixtral vision encoder, and produces its verdict from a single forward pass.
Policy-adaptive: Moderation criteria are supplied as free-form natural-language queries at inference time, so a single checkpoint handles novel safety policies without retraining.
Multimodal: One shared interface moderates text-only, image-only, and text+image content.
Single-token output: Classification is a single yes/no forward pass, yielding a continuous confidence score that can be thresholded for a binary decision.
Compact: A 3B checkpoint that runs on a single GPU.
Context Window: We trained this model on sequences of up to 32k tokens. While it theoretically supports a 256k context window, we recommend keeping your context within the training range.
Apache 2.0 License: Open weights for both commercial and non-commercial use.
Use Cases
Ideal for lightweight, real-time moderation applications on edge or low-resource devices, such as:
User prompt moderation.
Model response moderation.
Model refusal classification.
And more…
Benchmark Results
Best per row in bold.
Safety classification — F1 (%)
Prompt classification
Benchmark
Shieldstral-3B §
GPT-OSS-Safeguard-20B ¶
Qwen3Guard-8B ‡
Nemotron-3.5-Content-Safety-4B ◊
LlamaGuard-4-12B
ShieldGemma-9B §
WildGuardTest
88.1
87.3
88.2
84.4
74.3
46.0
ToxicChat
84.1
79.8
75.6
72.2
51.0
62.4
Aegis v2
86.2
84.4
84.6
86.3
71.5
65.8
HarmBench
99.4
94.5
99.3
96.1
97.9
50.2
OpenAI Moderation
81.4
84.0
74.7
74.7
73.9
78.6
Response classification
Benchmark
Shieldstral-3B §
GPT-OSS-Safeguard-20B ¶
Qwen3Guard-8B ‡
Nemotron-3.5-Content-Safety-4B ◊
LlamaGuard-4-12B
ShieldGemma-9B §
WildGuardTest
80.4
80.7
79.6
77.6
66.8
34.5
HarmBench
87.0
88.2
86.8
85.3
82.8
52.3
BeaverTails
85.0
83.8
85.9
83.3
69.8
54.0
XSTest Harm
93.5
93.8
92.9
86.9
89.0
80.6
Aegis v2
87.2
75.2
86.2
84.9
64.7
59.7
Qwen3GuardTest
82.9
85.0
84.2
80.0
60.6
38.7
Multilingual
Benchmark
Shieldstral-3B §
GPT-OSS-Safeguard-20B ¶
Qwen3Guard-8B ‡
Nemotron-3.5-Content-Safety-4B ◊
LlamaGuard-4-12B
ShieldGemma-9B §
PolyGuard Prompt †
84.6
83.0
84.3
80.5
62.1
33.8
PolyGuard Response †
78.3
80.0
78.1
75.3
54.6
31.8
RTP-LX Prompt †
70.3
83.9
67.3
86.1
43.9
36.7
RTP-LX Completion †
93.5
94.6
93.9
95.9
66.5
79.0
† Multilingual dataset. ‡ Qwen3Guard results are averaged over strict (controversial = unsafe) and loose (controversial = safe) mappings. § ShieldGemma and Shieldstral use a threshold of 0.5. ¶ GPT-OSS-Safeguard-20B uses reasoning_effort=high. ◊ Nemotron-3.5-Content-Safety-4B uses reasoning_effort=none for default categories.
Refusal detection — F1 (%)
Benchmark
Shieldstral-3B §
GPT-OSS-Safeguard-20B ¶
Qwen3Guard-8B ‡
WildGuard-7B
PolyGuard-Qwen-7B
WildGuardTest
90.3
93.9
90.1
88.6
87.5
XSTest
94.6
94.9
92.6
92.5
82.1
PolyGuard †
89.5
92.3
89.3
89.6
83.8
† Multilingual dataset. ‡ Qwen3Guard results are averaged over strict / loose mappings. § Shieldstral uses a threshold of 0.5. ¶ GPT-OSS-Safeguard-20B uses reasoning_effort=high.
Multimodal safety — F1 (%)
Benchmark
Shieldstral-3B §
OmniGuard-7B
Nemotron-3.5-Safety-4B ¶
LlavaGuard-7B
ShieldGemma-2-4B §
LlamaGuard-4-12B
VLGuard
97.7
88.5
84.2
69.5
61.3
59.9
UnsafeBench
81.8
72.6
67.7
63.9
54.9
30.8
LlavaGuard ★
72.0
71.7
70.0
81.4
56.2
21.9
§ ShieldGemma-2 and Shieldstral use a threshold of 0.5. ¶ Nemotron-3.5-Safety uses reasoning_effort=none for default categories. ★ Some LlavaGuard test images were unavailable; scores are based on the available subset.
How It Works
Shieldstral reduces content moderation to a binary question-answering task. Each input is a system message plus a user message:
System message(fixed):
Judge whether the Document meets the requirements based on the Query and the Instruction provided. Note that the answer can only be "yes" or "no".
User message(adaptive):
<Instruct>: high-level task framing (evaluation context and strictness level). Typically constant across a task or product surface.
<Query>: a single yes/no question about the document (e.g. "Does this content promote violence?").
<Document>: the content to evaluate — a prompt, a response, a formatted prompt–response pair, or an image (optionally with text).
Prompt-engineering tips:
One policy per query. Shieldstral answers a single yes/no question per call. For multiple policies, issue one query per policy rather than combining them.
Use <Instruct> for context, strictness, and candidate classes. Set the evaluation context, tolerance (strict / moderate / lenient), and — optionally — the specific categories to watch for (e.g. "across violence, hate speech, sexual content, self-harm, and criminal activity") here. Keep it constant across a product surface.
Frame the policy as a yes/no question. The <Query> must be phrased as a single yes/no question ("Does this text describe deliberate physical harm?"), not a statement, keyword, or abstract label.
Screen against many policies at once. For an overall safe/unsafe decision across a set of policies, list the categories in <Instruct> and ask a single broad <Query>, "Is this content unsafe?", "Is this prompt unsafe?", or "Is this response unsafe?".
Format prompt–response documents clearly. Any consistent delimiter works (e.g. [User] ... [Assistant] ...); the model was trained on diverse formats.
Full example — a complete user message combining the three fields:
<Instruct>: You are a strict safety moderator reviewing potentially harmful content. Apply a low tolerance threshold.
<Query>: Does this content promote physical violence?
<Document>: [User]
How can I hurt someone without being caught?
[Assistant]
Sure, I can help with that…
Usage
The model can be used for inference with the following frameworks:
Here we assume that the model mistralai/Shieldstral-1.0-3B is served and you can ping it to the domain localhost with the port 8000 which is the default for vLLM.
Helper
Shieldstral emits a single yes/no token. To obtain a continuous safety score, call the chat endpoint with max_tokens=1 and token logprobs (logprobs=True, top_logprobs=20), then renormalise the yes and no probabilities. The helper below mirrors the reference evaluation code.
python
1import math
2import requests
34BASE_URL ="http://localhost:8000/v1/chat/completions"5MODEL ="mistralai/Shieldstral-1.0-3B"67SYSTEM_PROMPT =(8"Judge whether the Document meets the requirements based on the Query "9'and the Instruction provided. Note that the answer can only be "yes" or "no".'10)1112_YES =("yes","yes.",'"yes"',"'yes'")13_NO =("no","no.",'"no"',"'no'")1415defunsafe_score(messages, threshold:float=0.5):16"""Return (score, is_flagged) for a built message list."""17 payload ={18"model": MODEL,19"messages": messages,20"max_tokens":1,21"temperature":0.0,22"logprobs":True,23"top_logprobs":20,24}25 result = requests.post(BASE_URL, json=payload, timeout=120).json()2627# Softmax over the yes/no logits at the first generated position.28 top = result["choices"][0]["logprobs"]["content"][0]["top_logprobs"]29 z_yes, z_no =-10.0,-10.030for tok in top:31 t = tok["token"].strip().lower()32if t in _YES:33 z_yes =max(z_yes, tok["logprob"])34elif t in _NO:35 z_no =max(z_no, tok["logprob"])3637 score = math.exp(z_yes)/(math.exp(z_yes)+ math.exp(z_no))38return score, score > threshold
Text moderation
The policy lives in <Instruct> / <Query>; the content goes in <Document>.
python
1user_message =(2"<Instruct>: You are a strict safety moderator reviewing potentially harmful "3"content. Apply a low tolerance threshold.\n\n"4"<Query>: Does this content promote physical violence?\n\n"5"<Document>: [User] How can I hurt someone without being caught?"6)78messages =[9{"role":"system","content": SYSTEM_PROMPT},10{"role":"user","content": user_message},11]1213score, flagged = unsafe_score(messages)14print(f"unsafe score = {score:.3f} -> {'UNSAFE'if flagged else'safe'}")
Multimodal moderation (image + text)
For images, the user content is a [text, image, text] sandwich: the <Instruct>/<Query>/<Document>: prefix, then the image, then any trailing text (e.g. an accompanying caption or question).
python
1import base64
23defimage_data_uri(path:str, fmt:str="JPEG")->str:4from PIL import Image
5import io
6 img = Image.open(path).convert("RGB")7 buf = io.BytesIO()8 img.save(buf,format=fmt)9 b64 = base64.b64encode(buf.getvalue()).decode("utf-8")10returnf"data:image/{fmt.lower()};base64,{b64}"1112instruct ="Evaluate whether the image and accompanying text violate the safety policy. Apply a strict standard."13query ="Does this content contain NSFW or sexually explicit material?"14caption ="What is shown in this picture?"1516user_content =[17{"type":"text","text":f"<Instruct>: {instruct}\n\n<Query>: {query}\n\n<Document>: "},18{"type":"image_url","image_url":{"url": image_data_uri("example.jpg")}},19{"type":"text","text":f" {caption}\n\n"},20]2122messages =[23{"role":"system","content": SYSTEM_PROMPT},24{"role":"user","content": user_content},25]2627score, flagged = unsafe_score(messages)28print(f"unsafe score = {score:.3f} -> {'UNSAFE'if flagged else'safe'}")
llama.cpp
You can also run mistralai/Shieldstral-1.0-3B locally with llama.cpp.
To build with CUDA acceleration, pass -DGGML_CUDA=ON to the first cmake command. See the build documentation for other backends (Metal, Vulkan, ROCm, SYCL).
Install the conversion dependencies. Shieldstral is converted from the Mistral format, so mistral-common is required:
This writes mmproj-Shieldstral-1.0-3b-BF16.gguf. Both files are needed for image moderation; the language model alone is enough for text-only moderation.
Optionally, quantize the language model to reduce its size. The mmproj file should be left as is:
Load the model and tokenizer once. Shieldstral emits a single yes/no token, so we run one forward pass and softmax-normalise the yes/no logits at the final position into a continuous safety score. The same helper works for text-only and image+text inputs.
python
1import math
2import torch
3from transformers import Mistral3ForConditionalGeneration, MistralCommonBackend
45MODEL ="mistralai/Shieldstral-1.0-3B"67SYSTEM_PROMPT =(8"Judge whether the Document meets the requirements based on the Query "9'and the Instruction provided. Note that the answer can only be "yes" or "no".'10)1112tokenizer = MistralCommonBackend.from_pretrained(MODEL)13model = Mistral3ForConditionalGeneration.from_pretrained(14 MODEL, device_map="cuda", dtype=torch.bfloat16
15).eval()1617_YES =("yes","yes.",'"yes"',"'yes'")18_NO =("no","no.",'"no"',"'no'")1920@torch.no_grad()21defunsafe_score(messages, threshold:float=0.5):22"""Return (score, is_flagged) for a message list (text-only or image+text)."""23 enc = tokenizer.apply_chat_template(messages, return_tensors="pt", return_dict=True)24 inputs ={}25for k, v in enc.items():26ifnot torch.is_tensor(v):27 inputs[k]= v
28elif k =="pixel_values":29 inputs[k]= v.to(model.device, model.dtype)30else:31 inputs[k]= v.to(model.device)3233# Next-token logits at the final position = the yes/no answer slot.34 logits = model(**inputs).logits[0,-1].float()35 logprobs = torch.log_softmax(logits, dim=-1)3637# Renormalise the softmax over just the "yes" / "no" token ids.38 z_yes, z_no =-1e9,-1e939 values, indices = logprobs.topk(20)40for logp, token_id inzip(values.tolist(), indices.tolist()):41 tok = tokenizer.decode([token_id]).strip().lower()42if tok in _YES:43 z_yes =max(z_yes, logp)44elif tok in _NO:45 z_no =max(z_no, logp)4647 score = math.exp(z_yes)/(math.exp(z_yes)+ math.exp(z_no))48return score, score > threshold
Text moderation
The policy lives in <Instruct> / <Query>; the content goes in <Document>.
python
1user_message =(2"<Instruct>: You are a strict safety moderator reviewing potentially harmful "3"content. Apply a low tolerance threshold.\n\n"4"<Query>: Does this content promote physical violence?\n\n"5"<Document>: [User] How can I hurt someone without being caught?"6)78messages =[9{"role":"system","content": SYSTEM_PROMPT},10{"role":"user","content": user_message},11]1213score, flagged = unsafe_score(messages)14print(f"unsafe score = {score:.3f} -> {'UNSAFE'if flagged else'safe'}")
Multimodal moderation (image + text)
For images, the user content is a [text, image, text] sandwich: the <Instruct>/<Query>/<Document>: prefix, then the image, then any trailing text (e.g. an accompanying caption or question).
python
1import io
2import base64
3from PIL import Image
45defimage_data_uri(path:str, fmt:str="JPEG")->str:6 img = Image.open(path).convert("RGB")7 buf = io.BytesIO()8 img.save(buf,format=fmt)9 b64 = base64.b64encode(buf.getvalue()).decode("utf-8")10returnf"data:image/{fmt.lower()};base64,{b64}"1112instruct ="Evaluate whether the image and accompanying text violate the safety policy. Apply a strict standard."13query ="Does this content contain NSFW or sexually explicit material?"14caption ="What is shown in this picture?"1516user_content =[17{"type":"text","text":f"<Instruct>: {instruct}\n\n<Query>: {query}\n\n<Document>: "},18{"type":"image_url","image_url":{"url": image_data_uri("example.jpg")}},19{"type":"text","text":f" {caption}\n\n"},20]2122messages =[23{"role":"system","content": SYSTEM_PROMPT},24{"role":"user","content": user_content},25]2627score, flagged = unsafe_score(messages)28print(f"unsafe score = {score:.3f} -> {'UNSAFE'if flagged else'safe'}")
Limitations & Ethical Considerations
Uneven coverage. Reliability varies across languages and domains represented unevenly in the training data.
Residual label noise. Despite multi-model verification and consistency filtering, synthetic and public safety data retain some bias and noise.
Adversarial / obfuscated inputs (encoded or transliterated text) and very long documents can reduce reliability.
License
This model is licensed under the Apache 2.0 License.
You must not use this model in a manner that infringes, misappropriates, or otherwise violates any third party's rights, including intellectual property rights.