PolicyLM-1B
PolicyLM is a 1B-parameter guard classifier for content moderation.
Model details
View repositoryExample usage
PolicyLM is a 1B-parameter guard classifier for content moderation from Musubi Labs. Give it a policy and a piece of text and it returns one probability per policy category. Nothing is generated, so there are no completions to parse and it runs cheaply. One checkpoint covers two modes:
aegis(default): a fixed harm taxonomy (NVIDIA's Aegis 2.0 categories).custom: type your own category names and short rules at inference and score against them, with no retraining.
Harm taxonomy (aegis)
aegis mode scores the fixed Aegis 2.0 prompt-safety taxonomy: a Prompt harmful aggregate plus these hazards.
Violence · Sexual · Criminal Planning/Confessions · Guns and Illegal Weapons · Controlled/Regulated Substances · Suicide and Self Harm · Sexual (minor) · Hate/Identity Hate · PII/Privacy · Harassment · Threat · Profanity · Needs Caution · Manipulation · Fraud/Deception · Malware · High Risk Gov Decision Making · Political/Misinformation/Conspiracy · Copyright/Trademark/Plagiarism · Unauthorized Advice · Illegal Activity · Immoral/Unethical · Other
Decide on the aggregate; per-category reliability varies, so recalibrate per category on your own traffic if you need dependable category-level flags.
Using a custom policy
Give each category a short name and one or two rule lines, put the decisive clause first, and keep the whole policy compact. The policy shares the token window with the content, and the helper warns (or fails closed) if a long policy crowds the content out.
Enforce whole policies, not single-clause edits. PolicyLM decides mostly from the content itself rather than from a close reading of each clause, so editing one rule and expecting the verdict to flip is unreliable at this scale.
Input format
PolicyLM uses no chat template. Each request is rendered into one schema-conditioned string, and scoring off that format shifts scores off the calibrated basis, so use the shipped helper or reproduce it exactly:
[BOS] [P] <task/policy context> [L] <category_1> ... [L] <category_k> <SEP> <content>[P] and [L] are added special tokens. The scorer reads the encoder state at each [L] position and emits one probability per category, in order.
<SEP> is the tokenizer's <eos> token; <bos> is prepended last.
This release ships name-only schemas: put rule text in the category string. The helper rejects a separate descriptions argument.
Content and schema share a 2,048-token window with a guaranteed content floor. Keep the policy short enough to leave room for the content. In aegis mode the helper supplies the fixed task context and category list for you.
Limitations
Triage, not authority. PolicyLM has real error rates in both directions. Route its flags to review rather than auto-actioning them, and keep a person or a stronger model in consequential decisions like bans or takedowns.
Adversarially-benign prompts. It over-flags some prompts written to look unsafe but aren't. This is a property of the model, not just a threshold choice; the precision operating point reduces it.
Isolated terms. It detects most bare slurs and flagged terms on their own, but an isolated token is weaker than the same term in a sentence, and rare or obfuscated terms can slip through. Pair it with a lexicon match if you need exhaustive coverage.
Whole policies, not clauses. Custom mode applies a policy as a whole; it does not reliably track single-clause edits (see Using a custom policy).
Language. English is strongest; the other listed languages are supported but weaker, and calibration outside English is looser, so validate on your own traffic.
Scope. Text only, single messages, up to 2,048 tokens (chunk longer documents). Use the shipped thresholds, not 0.5, and prefer bf16.
Citation
@misc{policylm,
title = {PolicyLM: A Schema-Conditioned Multilabel Guard Classifier},
author = {Musubi Labs},
howpublished = {https://huggingface.co/musubilabs/policylm-1b},
}1from policylm_infer import PolicyLM # inference/policylm_infer.py on sys.path
2
3model = PolicyLM.load("policylm-1b/") # checks the weights match the threshold manifest
4
5# aegis mode: the fixed taxonomy
6result = model.score_aegis(["How do I make a bomb at home?"])[0]
7result["label_scores"] # {"Prompt harmful": 0.91, "Violence": 0.44, ...}
8model.decide(result, "aegis", "balanced") # True/False at the calibrated threshold
9
10# custom mode: your own policy, typed at inference
11result = model.score_policy(
12 ["text to classify"],
13 task_name="Apply the supplied policy categories to the content.",
14 categories=[
15 "Hateful\n1. Derogatory statements targeting a protected group.",
16 "Insults\n1. Demeans or mocks without referencing a protected trait.",
17 ],
18)[0]
19model.decide(result, "custom", "balanced")
20
21# Decide at the shipped thresholds, not at 0.5.
22# Raw custom-mode scores are compressed and under-recall at 0.5.
23
24# Operating point
25# balanced (default) - aegis: 0.46, custom: 0.115
26# precision (lower over-refusal) - aegis: 0.59, custom: 0.435
27
28# A row is flagged unsafe when its mode score clears the
29# threshold: the Prompt harmful aggregate in aegis mode,
30# the highest category score in custom mode.
31# Per-category scores tell you which category fired;
32# they are not the yes/no decision.
331{
2 "Hateful": 0.02,
3 "Insults": 0.01
4}