Mistral, 추론 시점에 정책을 바꾸는 3B 규모의 멀티모달 안전성 분류 모델 Shieldstral 공개

Shieldstral 소개

Mistral AI가 공개한 Shieldstral 은 30억(3B) 개의 매개변수를 가진 정책 적응형(Policy-Adaptive) 멀티모달 안전성 분류 모델 입니다. 텍스트 안전성 벤치마크에서 최대 7배 큰 모델과 대등한 성적을 내고, 멀티모달 콘텐츠 조정(Moderation) 분야에서는 새로운 최고 성능을 기록했습니다. 가중치는 Apache License 2.0으로 Hugging Face에 공개되어 있어 상업적 용도로도 자유롭게 쓸 수 있습니다.

LLM을 제품에 얹는 순간 개발자는 필연적으로 같은 종류의 질문을 마주하게 됩니다. "이 콘텐츠가 특정 집단에 대한 폭력을 조장하는가?", "이 이미지를 미성년자에게 보여줘도 되는가?", "어시스턴트가 방금 요청을 거절한 것인가?" 같은 질문들입니다. 문제는 이 질문들의 정답이 제품마다, 사용자층마다, 심지어 같은 서비스 안에서도 상황마다 달라진다는 데 있습니다. 보안 연구 도구에서는 아무 문제 없는 대화가 정신 건강 상담 플랫폼에서는 심각한 해를 끼칠 수 있습니다.

그런데 기존의 가드레일(Guardrail) 모델 대부분은 유해 범주의 분류 체계(Taxonomy)를 가중치 안에 고정해 넣어 두는 구조입니다. LlamaGuard, ShieldGemma, WildGuard, Qwen3Guard 모두 미리 정해진 범주 목록에 대해서만 판정을 내립니다. 새로운 배포 환경에 맞추려면 재학습이 필요하고, 애초에 안전성의 정의 자체가 응용 분야마다 다르기 때문에 "하나의 올바른 범주 집합" 이라는 것이 존재하지 않습니다. 공개된 안전성 데이터셋들이 서로 다른 분류 체계와 라벨 규약을 쓰는 것도 같은 이유에서입니다.

Shieldstral은 이 문제를 정면으로 다시 정의합니다. 범주를 가중치에 굽는 대신, 정책을 추론 시점에 평문(plain language) 질문으로 건네받고 보정된(calibrated) 안전성 점수를 돌려주는 방식입니다. 재학습이 필요 없고, 텍스트와 이미지가 하나의 인터페이스를 공유하며, 판정은 단 하나의 토큰에서 나옵니다. Mistral AI는 NVIDIA 등과 함께 Open Secure AI Alliance의 창립 멤버로 참여하면서 이 모델을 공개했고, 상세한 데이터 구축 레시피는 기술 보고서에 정리되어 있습니다.

고정된 분류표를 버리고, 모더레이션을 하나의 질문으로 바꾸다

Shieldstral의 핵심 발상은 콘텐츠 조정을 이진 질의응답(Binary Question-Answering) 과제 로 환원하는 것입니다. 모든 입력은 고정된 시스템 메시지 하나와, 세 개의 태그로 구성된 사용자 메시지로 이루어집니다.

  • <Instruct>: 평가 맥락과 엄격도(strictness)를 설명하는 상위 과제 프레이밍입니다. 어떤 제품 화면이나 작업 단위 안에서는 대체로 고정된 값으로 둡니다. 필요하면 여기에 감시할 범주 목록을 함께 적을 수 있습니다.
  • <Query>: 문서에 대해 던지는 단 하나의 예/아니오 질문입니다. 예를 들어 "이 콘텐츠가 신체적 폭력을 조장하는가?" 같은 형태입니다.
  • <Document>: 판정 대상이 되는 콘텐츠입니다. 사용자 프롬프트, 모델 응답, 프롬프트와 응답의 쌍, 또는 이미지(선택적으로 텍스트를 동반)가 모두 들어갈 수 있습니다.

시스템 메시지는 다음과 같이 고정되어 있습니다.

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".

학습 시에는 출력 위치에서 전체 어휘에 대한 교차 엔트로피 손실(Cross-Entropy Loss)로 학습하지만, 추론 시에는 yesno 두 토큰의 로짓만 읽어냅니다. 두 로짓을 각각 z_{\text{yes}}, z_{\text{no}} 라 할 때 안전성 점수 s 는 소프트맥스로 정규화한 값입니다.

s = \frac{\exp(z_{\text{yes}})}{\exp(z_{\text{yes}}) + \exp(z_{\text{no}})}

이 값을 임계값 \tau = 0.5 로 자르면 이진 판정이 되고, 자르지 않고 그대로 쓰면 신뢰도 순으로 순위를 매기거나 서비스별로 임계값을 다르게 잡을 수 있습니다. 이산적인 라벨 하나만 뱉는 모델과 달리 운영자가 정밀도와 재현율의 균형점을 직접 고를 수 있다는 뜻입니다.

이 단순한 형식화가 실제로 해내는 일은 생각보다 많습니다. 프롬프트 분류, 응답 모더레이션, 거부(refusal) 탐지, 독성(toxicity) 탐지처럼 서로 다르게 다뤄지던 과제들이 전부 하나의 예/아니오 문제로 통합됩니다. 그리고 정책이 전적으로 프롬프트 안에 살기 때문에, 체크포인트 하나가 배포 시점에 마주치는 새로운 정책에 그대로 적응합니다. 학습 데이터 쪽에서도 같은 이득이 있습니다. 이진 안전/유해 플래그만 있는 데이터셋과 다중 라벨 세분 분류 체계를 가진 데이터셋이 동일한 형식 아래로 들어오게 됩니다.

한눈에 보는 Shieldstral의 특징

정책 적응형(Policy-Adaptive): 모더레이션 기준을 추론 시점에 자유 형식의 자연어 질의로 넘깁니다. 체크포인트 하나가 재학습 없이 새로운 안전성 정책을 처리합니다.

멀티모달(Multimodal): 텍스트 전용, 이미지 전용, 텍스트와 이미지 혼합 콘텐츠를 하나의 공유 인터페이스로 판정합니다. Pixtral 계열의 네이티브 비전 인코더를 그대로 물려받았습니다.

단일 토큰 출력: 분류가 예/아니오 순방향 전파 한 번으로 끝납니다. 긴 추론 흔적(reasoning trace)을 생성하는 경쟁 모델들과 달리 지연 시간이 예측 가능합니다.

소형 모델: 3B 체크포인트로, BF16 기준 16GB VRAM 한 장에 올라갑니다. 엣지나 저사양 환경에서의 실시간 모더레이션을 염두에 둔 크기입니다.

다국어 지원: 영어, 프랑스어, 스페인어, 독일어, 이탈리아어, 포르투갈어, 네덜란드어, 중국어, 일본어, 한국어, 아랍어, 러시아어를 지원합니다.

컨텍스트 윈도우: 최대 32K 토큰 길이의 시퀀스로 학습했습니다. 이론적으로는 256K 컨텍스트를 지원하지만, Mistral은 학습 범위인 32K 안에서 사용할 것을 권장합니다.

벤치마크: 3B 모델이 20B 모델과 같은 자리에 서다

기술 보고서는 16개 벤치마크(21개 분할)와 10개의 베이스라인 모델을 놓고 네 가지 축으로 평가했습니다. 모든 평가 샘플은 학습 데이터에서 제외(held out)되었습니다. 베이스라인에는 GPT-OSS-Safeguard-20B, Qwen3Guard-8B, Nemotron-3.5-Content-Safety-4B, LlamaGuard-4-12B, ShieldGemma-9B, WildGuard-7B, OmniGuard-7B 등이 포함되었습니다.

텍스트 안전성 분류: 종합 F1 84.9%

프롬프트 분류와 응답 분류, 그리고 PolyGuard, RTP-LX 같은 다국어 데이터셋을 합산한 결과에서 Shieldstral은 종합 F1 84.9%로 전체 1위를 기록했습니다. 비교 대상 중 가장 작은 모델(3B 대 4~20B)이면서, 6배 이상 큰 GPT-OSS-Safeguard-20B와 동률입니다.

프롬프트 분류에서는 ToxicChat 84.1%, HarmBench 99.4%로 1위를 차지했고, WildGuardTest 88.1%, Aegis v2 86.2%로 선두권에 붙었습니다. 응답 분류에서는 Aegis v2 87.2%로 1위, BeaverTails 85.0%와 XSTest Harm 93.5%로 근소한 2위입니다.

프롬프트 분류 Shieldstral-3B GPT-OSS-Safeguard-20B Qwen3Guard-8B LlamaGuard-4-12B ShieldGemma-9B
WildGuardTest 88.1 87.3 88.2 74.3 46.0
ToxicChat 84.1 79.8 75.6 51.0 62.4
Aegis v2 86.2 84.4 84.6 71.5 65.8
HarmBench 99.4 94.5 99.3 97.9 50.2
OpenAI Moderation 81.4 84.0 74.7 73.9 78.6

다국어 쪽은 명암이 갈립니다. PolyGuard 프롬프트에서는 84.6%로 1위지만, RTP-LX 프롬프트에서는 70.3%로 Nemotron-3.5-Content-Safety-4B(86.1%)나 GPT-OSS-Safeguard-20B(83.9%)에 뚜렷하게 밀립니다. 28개 언어를 다루는 RTP-LX처럼 언어 폭이 넓은 독성 평가에서는 3B라는 크기의 제약이 드러난다고 읽는 편이 정확합니다.

거부 탐지: 어시스턴트가 실제로 거절했는가

거부 탐지는 유해성 판정과는 결이 다른 과제입니다. 모델이 요청을 실제로 거절했는지를 판별하는 것으로, 과잉 거부(over-refusal)를 모니터링하거나 안전 스택의 동작을 로깅할 때 쓰입니다.

Shieldstral은 종합 91.5%로 GPT-OSS-Safeguard-20B(93.7%)에 이어 2위이며, Qwen3Guard-8B(90.7%)와 WildGuard-7B(90.2%)를 앞섭니다. WildGuardTest 90.3%, XSTest 94.6%, PolyGuard 89.5%로 세 벤치마크 모두 90% 안팎에서 고르게 나온다는 점이 실용적으로 중요합니다.

정책 적응성: 학습에 없던 분류 체계에 얼마나 대응하는가

이 축이 Shieldstral이 스스로를 차별화하는 지점입니다. 기존 벤치마크는 일반적인 모더레이션 성능은 측정할 수 있지만, 적응성 은 측정하지 못합니다. 그래서 연구팀은 학습 분류 체계와 독립적으로 설계된 평가 분류 체계 를 별도로 만들었습니다.

결과는 Shieldstral 91.3%, GPT-OSS-Safeguard-20B 94.1%, Nemotron-3.5-Safety-4B 91.8%입니다. 1위는 아니지만, 여기서 눈여겨볼 것은 도달 방식입니다. GPT-OSS-Safeguard-20B와 Nemotron-3.5-Safety는 답을 내기 전에 긴 추론 흔적을 생성하는 방식이고, Shieldstral은 단일 토큰으로 끝냅니다. 보고서는 이 차이를 "실제 배포에서 추론 효율을 크게 떨어뜨린다" 고 지적합니다. 20B 매개변수에 추론 생성까지 얹은 모델과 3B 단일 순방향 전파 사이의 2.8%p 격차를, 운영 비용까지 포함해 어떻게 볼 것인지는 서비스마다 판단이 갈릴 대목입니다.

멀티모달 안전성: 새로운 최고 성능

Shieldstral이 명확히 1위를 차지한 영역입니다. 종합 F1 83.8%로, 차순위인 OmniGuard-7B(77.6%)를 6.2%p 앞서면서 매개변수는 절반 이하입니다.

VLGuard에서 97.7%(차순위 88.5%), UnsafeBench에서 81.8%(차순위 72.6%)로 큰 격차를 벌렸습니다. 다만 LlavaGuard 벤치마크에서는 72.0%로, 해당 벤치마크와 같은 이름을 가진 LlavaGuard-7B(81.4%)에 밀립니다. 보고서는 대화 중심의 안전성 프레이밍에 의존하는 LlamaGuard-4-12B(종합 37.5%)와 Nemotron-3.5-Safety(종합 73.9%)가 이미지 단독 벤치마크에서 상대적으로 덜 효과적이라고 분석합니다.

작은 모델이 큰 모델을 따라잡은 비결: 데이터 파이프라인

기술 보고서가 반복해서 강조하는 결론은 단순합니다. "데이터만 제대로 되어 있다면 작은 모델이 훨씬 큰 모델을 이길 수 있다" 는 것입니다. 그 데이터를 제대로 만드는 과정은 약 5,410만(54.1M) 개 샘플을 네 단계로 쌓아 올리는 작업이었습니다. 공개 텍스트 4,520만 개, 합성 대조 텍스트 440만 개, 멀티모달 450만 개로 구성됩니다.

서로 다른 데이터셋을 하나의 형식으로 통합하기

공개된 안전성 데이터셋들은 분류 체계, 라벨, 주석 규약이 제각각입니다. 이진 안전/유해 플래그만 있는 것부터 세분화된 다중 라벨 체계까지 편차가 큽니다. 연구팀은 데이터셋마다 전용 처리기(processor) 를 손으로 설계해 전부 동일한 instruction-query-document 형식으로 변환했습니다.

핵심은 문구를 고정하지 않았다는 점입니다. 지시문과 질의, 프롬프트와 응답을 구분하는 구분자의 표현을 여러 벌 준비해 두고 학습 시점에 무작위로 뽑아 씁니다. 문서 형식만 해도 Prompt: ... Response: ... 같은 기본 라벨, [User] ... [Assistant] ... 형태의 대괄호, XML 스타일, 마크다운, Human: ... AI: ... 같은 역할 기반 등 일곱 가지 계열을 두었습니다. 덕분에 모델은 하나의 표현 방식에 과적합되는 대신 문구 변화 전반에 걸쳐 일반화합니다.

여기에 더해 데이터 출처별로 엄격도를 보정 했습니다. 적대적 탈옥(jailbreak) 데이터에는 엄격한 지시 템플릿을, 응답 품질 데이터에는 관대한 템플릿을 붙이는 식입니다. 이렇게 하면 그냥 두면 서로 충돌했을 데이터셋들이 각자의 결정 경계를 유지한 채 한 모델 안에 공존할 수 있습니다.

엄격도 적용 도메인 근거
엄격(Strict) 적대적 탈옥, 시각 안전성 미묘한 위해도 적극적으로 탐지해야 함
보통(Moderate) 일반 안전성, 혐오 표현, 독성 민감도와 오탐 회피의 균형
관대(Lenient) 응답 품질, 대화 모더레이션 명백히 유해한 내용만 탐지

마지막으로 공개 데이터셋에 흔한 오라벨 문제를 다뤘습니다. 오픈소스 LLM으로 데이터셋 라벨을 교차 검증해, 이진 수준과 범주 수준 양쪽에서 원 라벨과 LLM 판정이 불일치하는 샘플을 제거했습니다.

암기가 아니라 변별을 가르치기

이 파이프라인에서 가장 흥미로운 아이디어입니다. 고정된 정책 라벨 집합으로만 학습하면 모델은 그 정책들을 분류하는 법만 배우지, 주어진 정책의 정확한 경계를 추론하는 법을 배우지 못합니다. 새로운 정책으로의 일반화가 막히는 지점입니다.

그래서 연구팀은 의도적으로 서로 헷갈리는 유사 정책 쌍 을 구성하고, LLM에게 안전한 텍스트를 대조 쌍(contrastive pair)으로 다시 쓰게 했습니다. 각 재작성본은 목표 범주는 위반하되 그 형제(sibling) 범주는 위반하지 않도록 설계됩니다. 한 번의 LLM 호출로 (1) 목표 범주를 드러내는 유해 재작성본, (2) 목표 범주에 대한 질의, (3) 형제 범주에 대한 부정 질의가 함께 나옵니다. 같은 콘텐츠에 서로 다른 질의를 붙여 양성 쌍과 음성 쌍을 동시에 얻는 구조입니다.

이렇게 학습하면 모델은 "어떤 특정 정책을 이 콘텐츠가 위반하는가" 를 변별하는 기술을 익히게 되고, 이 기술은 추론 시점에 처음 보는 사용자 정의 정책으로 전이됩니다. 학습용 분류 체계는 11개 상위 클래스와 73개 말단 범주로 구성된 계층 구조입니다. 계층적이라는 점을 활용해, 말단 범주를 위반하는 콘텐츠는 상위 조상 범주도 모두 위반한다는 사실로부터 추가 LLM 호출 없이 양성 샘플을 재귀적으로 늘렸습니다.

적응성 평가용 분류 체계는 여기서 완전히 분리해 설계했습니다. 12개 상위 클래스, 26개 하위 범주, 52개 말단 범주의 3단 트리이며, 데이터 생성에 쓴 LLM도 학습 때와 다른 것을 썼습니다. 두 체계는 이름도, 세분도도, 묶는 방식도 다릅니다. 예를 들어 학습 체계의 "Indiscriminate Weapons" 는 평가 체계에서 "WMDs" 가 되고, 혐오 관련 15개 말단 범주는 4개로 압축되며, 학습 체계가 하나의 상위 클래스로 묶은 범죄는 평가 체계에서 재산 범죄, 사이버 범죄, 마약 범죄 셋으로 쪼개집니다. 12개 평가 상위 클래스 중 10개가 학습 체계에 느슨한 대응물을 갖지만, 말단 범주 중 일대일로 대응되는 것은 하나도 없습니다. 평가 점수가 학습 라벨 암기의 결과가 아니라는 것을 구조적으로 보장하기 위한 설계입니다.

이미지 안전성 데이터의 희소성 문제

텍스트와 달리 유해 이미지는 LLM으로 합성할 수 없습니다. 공개 이미지 모더레이션 데이터셋은 수도 적고 규모도 작으며 다루는 범주도 좁습니다. 연구팀은 네 가지 방법으로 이 격차를 메웠습니다.

  • 일반 목적 이미지 데이터셋 활용: 이미지 분류와 객체 탐지 데이터셋을 끌어와, 자연스럽게 안전한 이미지들의 큰 풀을 고품질 음성 샘플로 씁니다.
  • 질의 변이(Query mutation): 이미지를 대규모로 변형하기 어려우니 질의 쪽 다양성을 늘렸습니다. NSFW, 폭력, 혐오, 불법 콘텐츠를 아우르는 14개 하위 범주의 시각 모더레이션 분류 체계에서 약 2,000개의 질의 표현을 LLM으로 생성했습니다. 이 중 약 30%는 "이 이미지는 폭력으로부터 안전한가?" 처럼 뒤집힌 형태여서, 같은 범주의 긍정 프레이밍과 부정 프레이밍을 모두 다루도록 가르칩니다.
  • 비전-언어 리랭커 필터링: 데이터셋 구축 후 비전-언어 리랭커 모델이 모든 이미지-질의 쌍에 점수를 매겨 오라벨과 LLM 환각을 걸러냅니다. 희귀한 위반 샘플은 보존하고 흔한 음성 샘플에는 더 엄격한 기준을 적용하는 비대칭 임계값을 씁니다.
  • 어려운 음성 샘플 생성: 형제 범주에서 뽑은 아슬아슬한 질의를 이미지에 붙여 도메인 내 변별력을 날카롭게 만듭니다.

이 과정을 거쳐 약 450만 개의 멀티모달 학습 샘플이 만들어졌습니다. 텍스트 부분(4,520만 개)의 10분의 1 규모지만, 텍스트로 배운 안전성 개념을 시각 콘텐츠에 접지(grounding)시키기에는 충분했다는 것이 멀티모달 벤치마크 결과로 확인됩니다.

학습 레시피: LoRA 미세조정과 세 갈래 SLERP 병합

Shieldstral의 기반 모델은 Ministral-3-3B-Base-2512이고, 여기에 Pixtral 비전 인코더가 네이티브로 붙어 있습니다. 미세조정(fine-tuning)은 언어 모델 매개변수에 LoRA를 적용해 단일 출력 토큰에 대한 교차 엔트로피 손실로 진행했습니다. 전체 SFT와 비교했을 때 유의미한 차이가 없어서, 학습 효율이 좋은 LoRA를 선택했다고 밝히고 있습니다.

학습 단계별 기여도를 보면 이 데이터 레시피가 왜 중요한지가 드러납니다. 세분 분류 체계 검증 세트에서 측정한 결과입니다.

학습 단계 정확도 정밀도 재현율 F1 F1 변화
기본 Ministral-3B (안전성 학습 없음) 37.8 0.0 0.0 0.0 -
+ 공개 데이터 62.7 90.8 46.0 61.1 +61.1
+ 생성 분류 체계 데이터 77.6 75.9 95.0 84.4 +23.3

안전성 학습을 거치지 않은 기본 모델은 재현율 0%, 즉 위반을 한 번도 예측하지 않고 전부 안전으로 넘깁니다. 공개 데이터만으로 미세조정해도 61.1%가 나오는데, 이 평가 분류 체계의 질의와 라벨을 모델이 한 번도 본 적이 없다는 점을 감안하면 데이터 큐레이션 레시피 자체가 미지의 정책으로의 일반화를 만들어낸다는 뜻입니다. 여기에 LLM 생성 분류 체계 데이터를 더하면 23.3%p가 추가로 붙습니다.

마지막 단계는 모델 병합 입니다. 공개 데이터로만 학습한 체크포인트(P)는 표준 벤치마크에 잘 보정되어 있고, 공개 데이터와 생성 데이터를 합쳐 학습한 체크포인트(PG)는 세분 범주 변별력이 뛰어나지만 분포 이동(distribution drift)을 겪을 수 있습니다. 두 장점을 추가 학습 없이 합치기 위해 SLERP(구면 선형 보간) 병합을 씁니다.

  • PG (가중치 0.6): 정책 적응형 일반화를 담당
  • P (가중치 0.3): 벤치마크 보정을 고정
  • Ministral-3B-Instruct (가중치 0.1): 일반적인 지시 따르기 능력을 기여
병합 구성 Aegis v2 F1 세분 분류 체계 F1
P 88.5 61.1
PG 87.1 84.4
0.9 PG + 0.1 I 87.4 84.6
0.6 PG + 0.3 P + 0.1 I 88.0 88.7

생성 분류 체계 데이터를 넣으면 Aegis v2 성능이 조금 떨어지지만 분류 체계 F1은 61.1%에서 84.4%로 급등합니다. 세 갈래 병합은 Aegis v2 하락분을 대부분 회복하면서 분류 체계 F1을 88.7%까지 밀어 올립니다. 두 데이터 체제가 상호 보완적인 특징을 학습한다는 증거이고, 이 구성이 최종 모델로 채택되었습니다.

한 가지 더 눈에 띄는 점은 지시 따르기 능력의 전이입니다. Ministral-3B-Instruct를 0.1 가중치로 섞는 것만으로 재현율과 F1이 전반적으로 개선되는데(P 단독 61.1% 대비 0.9 P + 0.1 I는 65.3%), 일반적인 지시 따르기 능력이 안전성 분류 과제로 그대로 넘어온다는 의미입니다. 학습 인프라와 데이터/모델 샤딩, 메트릭과 로깅은 Mistral의 커스텀 모델 학습 플랫폼인 Forge가 담당했습니다.

직접 실행해보기: vLLM으로 서빙하고 안전성 점수 얻기

Shieldstral은 vLLM(권장), llama.cpp, transformers 세 가지 방식으로 실행할 수 있고, Axolotl로 미세조정도 가능합니다. BF16 기준 16GB VRAM에 들어가므로 로컬 배포가 현실적입니다.

pip install vllm --upgrade   # vllm >= 0.26.0, mistral_common >= 1.11.5

vllm serve mistralai/Shieldstral-1.0-3B --max-model-len 32768

핵심은 max_tokens=1과 토큰 로그 확률(logprobs=True, top_logprobs=20)을 함께 요청한 뒤, yesno 확률을 재정규화해 연속 점수를 얻는 부분입니다.

import math
import requests

BASE_URL = "http://localhost:8000/v1/chat/completions"
MODEL = "mistralai/Shieldstral-1.0-3B"

SYSTEM_PROMPT = (
    "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".'
)

_YES = ("yes", "yes.", '"yes"', "'yes'")
_NO = ("no", "no.", '"no"', "'no'")

def unsafe_score(messages, threshold: float = 0.5):
    """Return (score, is_flagged) for a built message list."""
    payload = {
        "model": MODEL,
        "messages": messages,
        "max_tokens": 1,
        "temperature": 0.0,
        "logprobs": True,
        "top_logprobs": 20,
    }
    result = requests.post(BASE_URL, json=payload, timeout=120).json()

    # Softmax over the yes/no logits at the first generated position.
    top = result["choices"][0]["logprobs"]["content"][0]["top_logprobs"]
    z_yes, z_no = -10.0, -10.0
    for tok in top:
        t = tok["token"].strip().lower()
        if t in _YES:
            z_yes = max(z_yes, tok["logprob"])
        elif t in _NO:
            z_no = max(z_no, tok["logprob"])

    score = math.exp(z_yes) / (math.exp(z_yes) + math.exp(z_no))
    return score, score > threshold

텍스트 모더레이션

정책은 <Instruct><Query>에 담고, 판정 대상은 <Document>에 넣습니다.

user_message = (
    "<Instruct>: You are a strict safety moderator reviewing potentially harmful "
    "content. Apply a low tolerance threshold.\n\n"
    "<Query>: Does this content promote physical violence?\n\n"
    "<Document>: [User] How can I hurt someone without being caught?"
)

messages = [
    {"role": "system", "content": SYSTEM_PROMPT},
    {"role": "user", "content": user_message},
]

score, flagged = unsafe_score(messages)
print(f"unsafe score = {score:.3f} -> {'UNSAFE' if flagged else 'safe'}")

이미지와 텍스트를 함께 판정하기

이미지가 들어갈 때는 사용자 콘텐츠를 [텍스트, 이미지, 텍스트] 샌드위치로 구성합니다. <Instruct>, <Query>, <Document>: 접두부를 먼저 두고, 그다음 이미지, 마지막에 캡션 같은 후행 텍스트를 붙이는 순서입니다.

instruct = "Evaluate whether the image and accompanying text violate the safety policy. Apply a strict standard."
query = "Does this content contain NSFW or sexually explicit material?"
caption = "What is shown in this picture?"

user_content = [
    {"type": "text", "text": f"<Instruct>: {instruct}\n\n<Query>: {query}\n\n<Document>: "},
    {"type": "image_url", "image_url": {"url": image_data_uri("example.jpg")}},
    {"type": "text", "text": f" {caption}\n\n"},
]

messages = [
    {"role": "system", "content": SYSTEM_PROMPT},
    {"role": "user", "content": user_content},
]

score, flagged = unsafe_score(messages)
print(f"unsafe score = {score:.3f} -> {'UNSAFE' if flagged else 'safe'}")

llama.cpp로 로컬에서 돌리기

llama.cpp를 쓸 경우 Mistral 형식 가중치를 GGUF로 변환합니다. 언어 모델과 비전 인코더(mmproj)를 별도 파일로 만들어야 하며, 텍스트 전용 모더레이션만 필요하면 언어 모델 파일만 있어도 됩니다.

hf download mistralai/Shieldstral-1.0-3B \
    --exclude "model.safetensors" \
    --local-dir Shieldstral-1.0-3B

python convert_hf_to_gguf.py Shieldstral-1.0-3B \
    --mistral-format --outtype bf16 \
    --outfile Shieldstral-1.0-3B-BF16.gguf

python convert_hf_to_gguf.py Shieldstral-1.0-3B \
    --mistral-format --mmproj --outtype bf16 --outfile .

언어 모델은 Q8_0, Q5_K_M, Q4_K_M 등으로 양자화해 크기와 성능을 조절할 수 있지만, mmproj 파일은 그대로 두어야 합니다.

프롬프트 작성 요령: 정책 하나에 질문 하나

Shieldstral은 정책이 프롬프트에 사는 모델이므로, 프롬프트 설계가 곧 모더레이션 정책 설계입니다. 모델 카드가 제시하는 원칙은 다음과 같습니다.

  • 호출 하나에 정책 하나: Shieldstral은 호출당 예/아니오 질문 하나에만 답합니다. 여러 정책을 검사해야 한다면 정책마다 별도 질의를 보내야 하며, 하나의 질의에 여러 정책을 묶지 않습니다.
  • 맥락과 엄격도, 후보 범주는 <Instruct>: 평가 맥락, 허용 수준(엄격/보통/관대), 그리고 선택적으로 감시할 범주 목록을 여기에 둡니다. 예를 들어 "폭력, 혐오 표현, 성적 콘텐츠, 자해, 범죄 행위 전반에 걸쳐" 같은 식입니다. 이 값은 제품의 한 화면 안에서는 고정해 두는 것이 좋습니다.
  • 정책은 예/아니오 질문으로 표현: <Query>는 반드시 하나의 예/아니오 질문이어야 합니다. "이 텍스트가 의도적인 신체적 위해를 서술하는가?" 처럼 질문형으로 쓰고, 서술문이나 키워드, 추상적 라벨을 넣지 않습니다.
  • 여러 정책을 한 번에 훑을 때: 전체적인 안전/유해 판정이 필요하면 <Instruct>에 범주들을 나열하고 <Query>"이 콘텐츠는 유해한가?" 처럼 넓은 질문 하나로 던집니다.
  • 프롬프트-응답 문서는 일관된 구분자로: [User] ... [Assistant] ... 같은 형식이면 무엇이든 좋습니다. 모델이 다양한 형식으로 학습되었기 때문에 특정 구분자를 고집할 필요가 없습니다.

한계와 유의사항

모델 카드는 세 가지 한계를 명시하고 있습니다. 실제 서비스에 얹기 전에 반드시 검토해야 할 부분입니다.

  • 고르지 않은 커버리지: 학습 데이터에 고르지 않게 반영된 언어와 도메인에 따라 신뢰도가 달라집니다. 한국어가 지원 언어 목록에 있긴 하지만, 앞서 본 RTP-LX 다국어 결과가 보여주듯 언어별 편차는 실재합니다. 도입 전 자체 데이터로 한국어 성능을 직접 측정하는 편이 안전합니다.
  • 잔여 라벨 노이즈: 다중 모델 검증과 일관성 필터링을 거쳤음에도, 합성 데이터와 공개 안전성 데이터에는 편향과 노이즈가 남아 있습니다.
  • 적대적 입력과 긴 문서: 인코딩되거나 음차 표기된 텍스트 같은 난독화 입력, 그리고 매우 긴 문서에서는 신뢰도가 떨어집니다. 학습 시퀀스 길이가 32K였다는 점도 함께 고려해야 합니다.

여기에 더해, 안전성 점수가 연속값이라는 특성은 양날의 검입니다. 임계값을 서비스에 맞게 조정할 수 있다는 것은 곧 그 임계값을 정하는 책임이 운영자에게 넘어온다는 뜻이기도 합니다. Shieldstral 자체는 "무엇이 유해한가" 에 대한 답을 갖고 있지 않고, 주어진 질문에 대해 보정된 확률을 돌려줄 뿐입니다.

마치며: 고정 분류 체계 이후의 콘텐츠 모더레이션

Shieldstral이 던지는 메시지는 모델 크기 경쟁보다는 문제 정의에 관한 것입니다. 콘텐츠 모더레이션을 "미리 정한 범주 중 무엇에 해당하는가" 가 아니라 "지금 이 질문에 대해 예인가 아니오인가" 로 바꾸면, 서로 호환되지 않던 데이터셋들이 하나의 학습 프레임 안으로 들어오고, 그 규모의 힘으로 3B 모델이 20B 모델과 어깨를 나란히 하게 됩니다.

실무적으로는 세 가지가 매력적입니다. 첫째, 제품마다 다른 안전성 기준을 재학습 없이 프롬프트로 표현할 수 있습니다. 둘째, 단일 토큰 출력이라 추론 비용과 지연 시간이 예측 가능하고, 16GB GPU 한 장이면 자체 호스팅이 됩니다. 셋째, Apache 2.0이라 상업 서비스에 그대로 넣을 수 있습니다. 반면 다국어 편차, 난독화 입력 취약성, 정책 하나당 호출 하나라는 구조적 비용(정책이 10개면 호출도 10번)은 설계 단계에서 계산에 넣어야 합니다.

Mistral은 다국어 커버리지, 긴 문서에 대한 견고성, 더 넓은 멀티모달 안전성을 계속 밀고 나가겠다고 밝혔습니다. 커뮤니티가 이 위에 무엇을 만드는지 보고 싶다는 말도 덧붙였습니다.

:scroll: Shieldstral 소개 블로그

:page_facing_up: Shieldstral 기술 보고서 논문

:hugs: Shieldstral 1.0 3B 모델 (Hugging Face)

:github: Axolotl의 Shieldstral 미세조정 예제

라이선스

Shieldstral은 Apache License 2.0으로 배포되고 있어, 연구 목적은 물론 상업적 용도로도 자유롭게 사용 및 수정이 가능합니다. 다만 모델 카드는 제3자의 지적 재산권을 포함한 권리를 침해하는 방식으로 모델을 사용해서는 안 된다는 조건을 함께 명시하고 있습니다.

더 읽어보기




이 글은 GPT 모델로 정리한 초안을 바탕으로 한 것으로, 원문의 내용 또는 의도와 다르게 정리된 내용이 있을 수 있습니다. 관심있는 내용이시라면 원문도 함께 참고해주세요! 읽으시면서 어색하거나 잘못된 내용을 발견하시면 댓글로 알려주시기를 부탁드립니다. :hugs:

이 글이 유용하셨다면 아래:down_right_arrow:쪽 좋아요:+1:를 눌러주세요 — :pytorch:파이토치 한국 사용자 모임:south_korea:이 새로운 소식을 정리하고 공유하는 데 힘이 됩니다! :star_struck: