Gemini 모델은 안전을 우선시하도록 설계되었습니다. 하지만 특히 선정적인 프롬프트가 작성되는 경우 유해한 대답이 생성될 수 있습니다. 안전을 강화하고 오용을 최소화하기 위해 잠재적으로 유해한 대답을 차단하도록 안전 필터를 구성할 수 있습니다.
다음과 같은 두 가지 안전 보호 기능이 제공됩니다.
기본 제공되는 핵심 보호 기능:
- 모든 Gemini 모델에는 심각한 피해 (예: 아동 착취, 사이버 공격, 위험한 무기)에 대한 기본 제공 보호 기능이 포함되어 있습니다.
- 이러한 보호 조치는 항상 활성 상태이며 모든 프롬프트와 대답에 자동으로 적용되며 수정하거나 사용 중지할 수 없습니다.
구성 가능한 안전 필터:
- Gemini API는 앱의 안전 설정을 사용하여 정의하는 추가 구성 가능한 안전 필터를 제공합니다.
- 이 설정을 사용하면 괴롭힘, 증오심 표현, 음란물, 위험한 콘텐츠라는 네 가지 주요 피해 카테고리에서 콘텐츠가 차단되는 기준점을 제어할 수 있습니다.
중요 안전 개념
Gemini 모델의 안전을 다룰 때 이해해야 할 몇 가지 중요한 개념은 다음과 같습니다.
안전 필터: Google의 안전 측정기준에 따라 프롬프트와 모델 대답을 평가하는 서버 측 분류기입니다. 필터는 구성된 안전 설정에 따라 콘텐츠를 차단합니다.
안전 등급: 모델이 응답 객체에서 반환하는 평가 메타데이터입니다. 평점은 각 피해 카테고리에서 감지된 잠재적 피해의 확률과 심각도를 나타냅니다.
지원되는 모델
gemini-4-argongemini-3.8-flash(및 이전gemini-3.7-flash,gemini-3.6-flash,gemini-3.5-flash)gemini-3.5-flash-lite(및 이전gemini-3.1-flash-lite)gemini-nano-banana-2.1(Nano Banana 2.1)gemini-3.1-flash-image(Nano Banana 2)gemini-3.1-flash-lite-image(Nano Banana 2 Lite)gemini-3-pro-image(Nano Banana Pro)
gemini-3.1-pro-preview 모델과 범용 및 이미지 생성 Gemini 2.5 모델 (지원 중단됨)도 이 기능을 지원합니다.
앱에서 안전 설정 구성
|
Gemini API 제공업체를 클릭하여 이 페이지에서 제공업체별 콘텐츠와 코드를 확인합니다. |
GenerativeModel 인스턴스를 초기화하는 과정에서 안전 설정을 구성합니다. 구성은 해당 모델 인스턴스의 전체 기간 동안 유지됩니다.
이 페이지 뒷부분에서 사용 가능한 유해 카테고리와 각 카테고리에 설정할 수 있는 기준점에 대해 알아보세요.
Swift
GenerativeModel 인스턴스를 만들 때 SafetySetting를 구성합니다.
import FirebaseAILogic
let safetySettings = [
SafetySetting(harmCategory: .harassment, threshold: .blockOnlyHigh),
SafetySetting(harmCategory: .hateSpeech, threshold: .blockMediumAndAbove)
]
// Specify the safety settings as part of creating the `GenerativeModel` instance.
let model = FirebaseAI.firebaseAI(backend: .googleAI()).generativeModel(
modelName: "GEMINI_MODEL_NAME",
safetySettings: safetySettings
)
// ...
Kotlin
GenerativeModel 인스턴스를 만들 때 SafetySetting를 구성합니다.
// ...
val safetySettings = listOf(
SafetySetting(HarmCategory.HARASSMENT, HarmBlockThreshold.ONLY_HIGH),
SafetySetting(HarmCategory.HATE_SPEECH, HarmBlockThreshold.MEDIUM_AND_ABOVE)
)
// Specify the safety settings as part of creating the `GenerativeModel` instance.
val model = Firebase.ai(backend = GenerativeBackend.googleAI()).generativeModel(
modelName = "GEMINI_MODEL_NAME",
safetySettings = safetySettings
)
// ...
Java
GenerativeModel 인스턴스를 만들 때 SafetySetting를 구성합니다.
// ...
List safetySettings = List.of(
new SafetySetting(HarmCategory.HARASSMENT, HarmBlockThreshold.ONLY_HIGH),
new SafetySetting(HarmCategory.HATE_SPEECH, HarmBlockThreshold.MEDIUM_AND_ABOVE)
);
// Specify the safety settings as part of creating the `GenerativeModel` instance.
GenerativeModelFutures model = GenerativeModelFutures.from(
FirebaseAI.getInstance(GenerativeBackend.googleAI())
.generativeModel(
/* modelName */ "GEMINI_MODEL_NAME",
/* generationConfig is optional */ null,
safetySettings
)
);
// ...
Web
GenerativeModel 인스턴스를 만들 때 SafetySetting를 구성합니다.
import { HarmBlockThreshold, HarmCategory, getAI, getGenerativeModel, GoogleAIBackend } from "firebase/ai";
// ...
const ai = getAI(firebaseApp, { backend: new GoogleAIBackend() });
const safetySettings = [
{
category: HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
},
{
category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
},
];
// Specify the safety settings as part of creating the `GenerativeModel` instance.
const model = getGenerativeModel(ai, {
model: "GEMINI_MODEL_NAME",
safetySettings,
});
// ...
Dart
GenerativeModel 인스턴스를 만들 때 SafetySetting를 구성합니다.
import 'package:firebase_ai/firebase_ai.dart';
final safetySettings = [
SafetySetting(HarmCategory.harassment, HarmBlockThreshold.high),
SafetySetting(HarmCategory.hateSpeech, HarmBlockThreshold.medium),
];
// Specify the safety settings as part of creating the `GenerativeModel` instance.
final model = FirebaseAI.googleAI().generativeModel(
model: 'GEMINI_MODEL_NAME',
safetySettings: safetySettings,
);
// ...
Unity
GenerativeModel 인스턴스를 만들 때 SafetySetting를 구성합니다.
// ...
var safetySettings = new SafetySetting[] {
new SafetySetting(HarmCategory.Harassment, SafetySetting.HarmBlockThreshold.OnlyHigh),
new SafetySetting(HarmCategory.HateSpeech, SafetySetting.HarmBlockThreshold.MediumAndAbove)
};
// Specify the safety settings as part of creating the `GenerativeModel` instance.
var ai = FirebaseAI.GetInstance(FirebaseAI.Backend.GoogleAI());
var model = ai.GetGenerativeModel(
modelName: "GEMINI_MODEL_NAME",
safetySettings: safetySettings
);
// ...
사용 가능한 유해 카테고리
안전 필터는 다음 구성 가능한 유해 카테고리를 기준으로 프롬프트와 모델 응답을 평가합니다.
| 유해 카테고리 | 설명 |
|---|---|
HARM_CATEGORY_HARASSMENT |
개인 또는 정체성을 대상으로 위협하거나 협박하거나 괴롭히거나 모욕하는 부정적인 댓글 |
HARM_CATEGORY_HATE_SPEECH |
보호 대상 속성 (예: 인종, 민족, 종교, 장애, 연령, 국적, 군필 여부, 성적 지향, 성 정체성)을 근거로 개인이나 집단을 공격하거나, 비하하거나, 증오심을 조장하거나, 폭력을 선동하는 콘텐츠 |
HARM_CATEGORY_SEXUALLY_EXPLICIT |
성행위, 포르노 또는 기타 외설적이고 선정적인 콘텐츠에 대한 언급이 포함되어 있습니다. |
HARM_CATEGORY_DANGEROUS_CONTENT |
유해한 행위, 불법 상품 및 서비스, 무기, 자해 또는 위험한 활동을 조장, 촉진, 장려하거나 이에 대한 지침을 제공합니다. |
HARM_CATEGORY_CIVIC_INTEGRITY |
유권자를 오도하거나 시민 및 선거 절차를 저해하는 데 사용될 수 있는 콘텐츠 (일부 모델 및 지역에서 지원됨) |
구성 불가능한 안전 필터
구성 가능한 카테고리 외에도 모든 요청은 조정할 수 없는 시스템 수준 필터를 통과합니다.
아동 성적 학대 콘텐츠 (CSAM) / 금지된 콘텐츠: 금지된 콘텐츠로 신고된 프롬프트 또는 대답은 즉시 차단됩니다(
PROHIBITED_CONTENT).민감한 개인 식별 정보 (SPII): 민감한 개인 정보 (예: 금융 계좌 번호 또는 주민등록번호)를 노출할 위험이 있는 대답은 차단됩니다 (
SPII).
기준점 설정
앱에서 제어하려는 각 유해 카테고리에 대해 기준을 설정해야 합니다. 평가된 콘텐츠가 이 기준점을 충족하거나 초과하면 콘텐츠가 차단됩니다.
안전 평가 작동 방식: 확률과 심각도
안전 필터는 다음 두 가지 측정기준으로 콘텐츠를 평가합니다.
확률: 콘텐츠가 특정 유해성 카테고리에 속할 가능성에 대한 모델의 신뢰도입니다.
심각도: 콘텐츠가 유해한 경우 잠재적인 피해의 규모 또는 정도입니다.
각 측정기준에는 NEGLIGIBLE, LOW, MEDIUM, HIGH 중 하나의 수준이 할당됩니다.
콘텐츠는 심각도 수준이 낮고 확률이 높을 수 있고(예: 가벼운 코미디 농담 또는 친근한 모욕) 심각도 수준이 높고 확률이 낮을 수 있습니다(예: 폭력을 언급하는 의학적 또는 역사적 토론).
사용 가능한 피해 차단 기준점
앱에서 제어하려는 유해 카테고리에 대해 다음 기준을 설정할 수 있습니다.
| 임곗값 | 설명 | 허용되는 수준 |
|---|---|---|
BLOCK_LOW_AND_ABOVE |
가장 강력한 제한입니다. 확률 (또는 심각도)이 LOW, MEDIUM 또는 HIGH인 경우 콘텐츠를 차단합니다.
|
NEGLIGIBLE만 허용
|
BLOCK_MEDIUM_AND_ABOVE |
보통 수준의 제한입니다. 가능성 (또는 심각도)이 MEDIUM 또는 HIGH인 경우 콘텐츠를 차단합니다.
|
NEGLIGIBLE 및 LOW 허용 |
BLOCK_ONLY_HIGH |
가장 경미한 제한이 적용되는 활성 필터입니다. 가능성 (또는 심각도)이 HIGH인 경우에만 콘텐츠를 차단합니다.
|
NEGLIGIBLE, LOW, MEDIUM 허용
|
BLOCK_NONE |
이 카테고리에서는 자동 응답 차단이 사용 중지되어 있습니다. 앱에서 맞춤 검토를 수행할 수 있도록 안전 등급 메타데이터는 계속 계산되어 응답과 함께 반환됩니다. | 모든 콘텐츠 허용됨 |
OFF |
이 카테고리의 안전 필터를 완전히 사용 중지합니다. 자동 차단이 발생하지 않으며 안전 등급 메타데이터가 반환되지 않습니다. | 모든 콘텐츠 허용됨 |
안전 등급 검사 및 차단된 콘텐츠 처리
콘텐츠는 요청 중에 다음 두 단계에서 차단될 수 있습니다.
프롬프트 차단됨 (
PromptFeedback): 모델이 출력을 생성하기 전에 입력 프롬프트가 안전 필터를 위반했습니다. 응답 후보가 반환되지 않습니다.대답 후보 차단됨 (
finishReason == SAFETY): 모델이 구성된 기준점을 초과하는 대답 후보를 평가하거나 생성했습니다. 생성된 후보 텍스트가 삭제되거나 수정됩니다.
SafetyRating 객체
평가된 모든 프롬프트 또는 대답 후보에는 SafetyRating 객체의 배열이 포함됩니다. 각 등급은 다음을 제공합니다.
Gemini Developer API 및 Agent Platform Gemini API (formerly Vertex AI) 모두에서 사용할 수 있는 속성:
category: 평가된HarmCategory입니다.probability: 불연속 평가(NEGLIGIBLE,LOW,MEDIUM또는HIGH)입니다.blocked: 이 특정 등급으로 인해 콘텐츠가 차단된 경우true입니다.
Agent Platform Gemini API (formerly Vertex AI)에서 사용할 수 있는 추가 속성:
probabilityScore:0.0~1.0사이의 부동 소수점 신뢰도 점수입니다.severity: 개별 심각도 수준(NEGLIGIBLE,LOW,MEDIUM또는HIGH)입니다.severityScore:0.0~1.0사이의 부동 소수점 심각도 점수입니다.
SafetyRating 객체 예시
다음 예시는 안전 필터에 의해 대답 후보가 차단된 경우의 원시 JSON 응답 페이로드를 보여줍니다.
{
"candidates": [
{
"finishReason": "SAFETY",
"safetyRatings": [
{
"category": "HARM_CATEGORY_HARASSMENT",
"probability": "NEGLIGIBLE",
"blocked": false
},
{
"category": "HARM_CATEGORY_HATE_SPEECH",
"probability": "NEGLIGIBLE",
"blocked": false
},
{
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
"probability": "NEGLIGIBLE",
"blocked": false
},
{
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
"probability": "HIGH",
"blocked": true
}
]
}
],
"usageMetadata": {
"promptTokenCount": 24,
"totalTokenCount": 24
}
}
코드의 안전 오류 포착
콘텐츠가 차단되면 클라이언트 SDK는 차단을 예외 또는 오류 코드로 표시하므로 앱에서 이를 원활하게 처리할 수 있습니다.
Swift
GenerateContentError.promptBlocked 또는 GenerateContentError.responseStoppedEarly를 포착할 수 있습니다.
do {
let response = try await model.generateContent("Your prompt here")
print(response.text ?? "No text generated.")
} catch GenerateContentError.promptBlocked(let response) {
// The input prompt was blocked
if let feedback = response.promptFeedback {
let reason = feedback.blockReason?.rawValue ?? "unknown"
print("Prompt blocked for reason: \(reason)")
for rating in feedback.safetyRatings {
let cat = rating.category.rawValue
let prob = rating.probability.rawValue
print("Category: \(cat), probability: \(prob)")
}
}
} catch GenerateContentError.responseStoppedEarly(let reason, let response) {
// Candidate response was blocked or stopped early
if reason == .safety {
print("Response blocked due to safety.")
if let candidate = response.candidates.first {
for rating in candidate.safetyRatings where rating.blocked {
print("Blocked by category: \(rating.category.rawValue)")
}
}
}
} catch {
print("Unexpected error: \(error)")
}
Kotlin
PromptBlockedException를 포착하거나 candidate.finishReason를 검사할 수 있습니다.
try {
val response = model.generateContent("Your prompt here")
val candidate = response.candidates.firstOrNull()
if (candidate?.finishReason == FinishReason.SAFETY) {
val blockedRating =
candidate.safetyRatings.firstOrNull { it.blocked }
println("Response blocked by category: ${blockedRating?.category}")
} else {
println(response.text)
}
} catch (e: PromptBlockedException) {
val reason = e.response?.promptFeedback?.blockReason
println("Prompt was blocked: $reason")
} catch (e: Exception) {
println("Error generating content: ${e.message}")
}
Java
PromptBlockedException를 포착하거나 candidate.getFinishReason()를 검사할 수 있습니다.
try {
GenerateContentResponse response = model.generateContent("Your prompt here").get();
Candidate candidate = response.getCandidates().isEmpty() ? null : response.getCandidates().get(0);
if (candidate != null && candidate.getFinishReason() == FinishReason.SAFETY) {
SafetyRating blockedRating = null;
for (SafetyRating rating : candidate.getSafetyRatings()) {
if (Boolean.TRUE.equals(rating.getBlocked())) {
blockedRating = rating;
break;
}
}
System.out.println("Response blocked by category: " +
(blockedRating != null ? blockedRating.getCategory() : "unknown"));
} else {
System.out.println(response.getText());
}
} catch (ExecutionException e) {
if (e.getCause() instanceof PromptBlockedException) {
PromptBlockedException pbe = (PromptBlockedException) e.getCause();
GenerateContentResponse blockedResponse = pbe.getResponse();
String reason = (blockedResponse != null && blockedResponse.getPromptFeedback() != null)
? String.valueOf(blockedResponse.getPromptFeedback().getBlockReason())
: "unknown";
System.out.println("Prompt was blocked: " + reason);
} else {
System.out.println("Error generating content: " + e.getMessage());
}
} catch (InterruptedException e) {
System.out.println("Generation was interrupted: " + e.getMessage());
}
Web
promptFeedback 및 candidate.finishReason를 검사할 수 있습니다.
try {
const response = await model.generateContent("Your prompt here");
// Check if the prompt was blocked
if (response.promptFeedback?.blockReason) {
console.warn(`Prompt blocked: ${response.promptFeedback.blockReason}`);
return;
}
const candidate = response.candidates?.[0];
if (candidate?.finishReason === "SAFETY") {
const blockedRating = candidate.safetyRatings?.find((r) => r.blocked);
console.warn(`Response blocked by category: ${blockedRating?.category}`);
} else {
console.log(response.text);
}
} catch (error) {
console.error("Error generating content:", error);
}
Dart
promptFeedback 및 candidate.finishReason를 검사할 수 있습니다.
try {
final response = await model.generateContent([Content.text('Your prompt here')]);
// Check if the prompt was blocked
if (response.promptFeedback?.blockReason != null) {
print('Prompt blocked: ${response.promptFeedback?.blockReason}');
return;
}
final candidate = response.candidates.firstOrNull;
if (candidate?.finishReason == FinishReason.safety) {
final blockedRating =
candidate?.safetyRatings?.where((r) => r.isBlocked == true).firstOrNull;
print('Response blocked by category: ${blockedRating?.category.name}');
} else {
print(response.text);
}
} catch (e) {
print('Error generating content: $e');
}
Unity
PromptFeedback 및 candidate.FinishReason를 검사할 수 있습니다.
try {
var response = await model.GenerateContentAsync("Your prompt here");
// Check if the prompt was blocked
if (response.PromptFeedback?.BlockReason != null) {
Debug.LogWarning($"Prompt blocked: {response.PromptFeedback.BlockReason}");
return;
}
var candidate = response.Candidates.FirstOrDefault();
if (candidate?.FinishReason == FinishReason.Safety) {
var blockedRating = candidate.SafetyRatings?.FirstOrDefault(r => r.Blocked);
Debug.LogWarning($"Response blocked by category: {blockedRating?.Category}");
} else {
Debug.Log(response.Text);
}
} catch (Exception ex) {
Debug.LogError($"Error generating content: {ex.Message}");
}
책임감 있는 앱 디자인을 위한 권장사항
심층 방어: 안전 필터는 가드레일이지 지침이 아닙니다. 안전 설정을 명시적인 시스템 요청 사항 및 타겟팅된 프롬프트 설계와 결합하여 어조와 범위를 안내합니다.
원활한 사용자 피드백: 콘텐츠가 차단될 때 비정상 종료되거나 빈 화면이 표시되지 않습니다.
finishReason == SAFETY또는PromptBlockedException를 감지하고 콘텐츠 가이드라인에 따라 요청을 처리할 수 없음을 사용자에게 알리는 친절한 메시지를 표시합니다.커스텀 검토에
BLOCK_NONE사용: 이미 자체 클라이언트 측 또는 서버 측 검토 파이프라인이 있는 경우 임곗값을BLOCK_NONE로 설정하여 자동 차단 없이 모델의safetyRatings를 수신하고 앱에서 커스텀 검토 정책을 시행할 수 있습니다.서비스 약관 검토: 제한이 적은 설정(
BLOCK_ONLY_HIGH또는BLOCK_NONE)을 사용하는 경우 앱이 Google의 금지된 사용 정책을 계속 준수하는지 확인합니다.
콘텐츠 생성을 제어하는 다른 옵션
- 프롬프트 설계에 대해 자세히 알아보고 모델이 필요에 맞는 출력을 생성하도록 영향을 줄 수 있습니다.
- 모델 파라미터를 구성하여 모델이 대답을 생성하는 방식(예: 최대 출력 토큰, 반복되는 출력 토큰의 확률 등)을 제어합니다.
- 시스템 요청 사항을 설정하여 모델의 동작을 조정합니다. 이 기능은 모델이 최종 사용자의 추가 안내에 노출되기 전에 추가하는 서문과 같습니다.
- 프롬프트와 함께 응답 스키마를 전달하여 특정 출력 스키마를 지정합니다. 이 기능은 JSON 출력을 생성할 때 흔히 사용되지만, 모델이 특정 라벨이나 태그를 사용하도록 하려는 경우와 같은 분류 작업에도 사용할 수 있습니다.