개요
gemini-3-pro-image(즉, Nano Banana Pro)는 엄격한 콘텐츠 안전 제어를 적용하며, 여러 단계에서 정책을 준수하지 않는 요청을 거부합니다. 단순히 “생성 실패”라는 메시지만으로는 사용자가 문제를 이해하는 데 도움이 되지 않습니다. 적절한 오류 처리를 위해서는 다음이 필요합니다.
- 거부 사유를 정확하게 식별 — 콘텐츠 위반, 지식 베이스 제한, 기술 오류를 구분합니다
- 사용자에게 친절한 메시지 제공 — 기술 오류를 이해하기 쉬운 설명으로 바꿉니다
- 실행 가능한 제안 제공 — 요청을 어떻게 조정해야 성공할 수 있는지 안내합니다
- 기술 세부 정보 전체 보존 — 개발자가 디버깅할 수 있도록 합니다
요청이 HTTP 200을 반환했지만 이미지가 없는 경우, 이는 대개 Google 측에서 내린 안전성 판단입니다. APIYI의 투명 프록시는 결과를 그대로 전달할 뿐입니다. 저희도 고객이 이미지를 성공적으로 생성하기를 바랍니다. 감지 및 메시지 처리 로직은 애플리케이션 측에서 구현해야 합니다.
Google 콘텐츠 검토 정책 (2026 업데이트)
Google의 이미지 생성은 2단계 안전 메커니즘을 사용합니다.- 구성 가능한 필터: 괴롭힘, 혐오 발언, 성적으로 노골적인 콘텐츠, 위험한 콘텐츠의 네 가지 범위를 다루며,
safetySettings을 통해 조정할 수 있습니다 - 내장 보호 조치: 아동 안전과 같은 핵심 유해 행위에 대해서는 항상 활성화되어 있으며, 매개변수를 통해 비활성화할 수 없습니다
- 생성형 AI 금지 사용 정책:
policies.google.com/terms/generative-ai/use-policy - 생성형 콘텐츠 일반 오류 참고 자료:
ai.google.dev/api/generate-content
세 가지 핵심 진단 지표
우선순위가 가장 높은 것부터 낮은 순서대로 확인하십시오:1. candidatesTokenCount (최우선 순위) ⭐
- 위치:
response.usageMetadata.candidatesTokenCount - 의미: API가 생성한 후보 콘텐츠의 token 수
- 규칙:
0값은 요청이 콘텐츠 검토 단계에서 완전히 거부되었음을 의미하며, 후보 콘텐츠가 전혀 생성되지 않았습니다. 이는 가장 엄격한 거부입니다.
candidatesTokenCount이 0이라고 해서 항상 정책 위반을 의미하는 것은 아닙니다. 다른 두 가지 일반적인 경우를 구분해야 합니다:- 응답에
promptFeedback.blockReason이 있고candidates가 없는 경우: 생성 전에 제공업체의 검사에 의해 입력이 차단되었습니다.OTHER은 단일 참조 이미지로 인해 트리거되는 경우가 많습니다. blockReason: OTHER 문제 해결을 참조하십시오. finishReason이NO_IMAGE인 경우: 대개 prompt에서 모델에 제안서나 분석 작성을 요청하여 이미지 의도가 불분명한 경우입니다. NO_IMAGE 문제 해결을 참조하십시오.
2. finishReason (두 번째 우선순위)
- 위치:
response.candidates[0].finishReason - 규칙:
STOP이외의 모든 값은 특별한 처리가 필요한 비정상적인 완료를 나타냅니다.
finishReason 값은 다음과 같습니다 (Nano Banana 시리즈에 IMAGE_ 접두사가 붙은 이미지 전용 값이 추가되었습니다):
3. 텍스트 거부 설명 (중요)
- 위치:
response.candidates[0].content.parts[].text - 규칙:
finishReason이STOP이지만parts에 이미지 데이터 없이text만 포함되어 있는 경우, API는 이미지가 아닌 거부 설명을 반환한 것입니다. 텍스트는 중국어 또는 영어일 수 있으며, 예는 다음과 같습니다:
오류 시나리오 빠른 참조
처리 흐름(결정 순서)
핵심 코드 구현
위의 검사들을 하나의 파싱 함수로 결합합니다:소비자 친화적 메시지
설계 원칙: 명확하고 간결함, 긍정적인 안내, 실행 가능함, 비난 없음. 권장 템플릿:- 소비자 사용자: 기본적으로 친절한 설명 + 수정 제안만 표시합니다
- 비즈니스 / 도구 제공자: 기본적으로 기술 세부 정보(
finishReason,candidatesTokenCount등)를 펼쳐서 표시합니다 - 개발자: 전체 JSON 응답을 볼 수 있도록 “펼치기/접기” 토글을 제공합니다
모범 사례
- 우선순위에 따라 엄격하게 확인합니다:
candidatesTokenCount→finishReason→parts→ 데이터 추출 → 키워드 감지 - thoughtSignature를 확인하기 전에 텍스트를 먼저 수집합니다: 거부 설명을 잃지 않기 위함입니다
- 전체 응답을 유지합니다: 개발/테스트 도구는 문제 해결을 위해 항상 원시 JSON을 저장해야 합니다
- 중국어와 영어 거부 텍스트를 지원합니다: Google은 중국어나 영어를 반환할 수 있으므로 키워드 매칭은 둘 다를 포괄해야 합니다
- 점진적 폴백을 적용합니다: 스마트 감지가 성공하면 구체적인 메시지를 표시하고, 그렇지 않으면 API 텍스트를 직접 표시하며, 그다음에는 친숙한
finishReason이름을 사용하고, 마지막에만 일반 메시지로 폴백합니다 - “알 수 없는 오류”는 절대 표시하지 않습니다: 항상 실행 가능한 제안이나 전체 응답을 포함해야 합니다
자주 묻는 질문
왜 같은 prompt가 때로는 성공하고 때로는 실패합니까?
왜 같은 prompt가 때로는 성공하고 때로는 실패합니까?
Google의 안전 필터링은 무작위성과 문맥 의존성이 있습니다. 참조 이미지의 내용과 prompt를 결합하는 방식이 모두 판단에 영향을 미칩니다. 문구를 조정하거나 더 간접적인 표현을 사용해 보십시오.
어떻게 콘텐츠 문제인지 기술 문제인지 구분합니까?
어떻게 콘텐츠 문제인지 기술 문제인지 구분합니까?
candidatesTokenCount: 0 또는 finishReason: PROHIBITED_CONTENT → 콘텐츠 문제; Failed to fetch 또는 HTTP 오류 → 기술 문제; API 텍스트 설명 → 보통 콘텐츠 문제입니다.일반 사용자는 기술 정보를 얼마나 보아야 합니까?
일반 사용자는 기술 정보를 얼마나 보아야 합니까?
단계적 표시: 기본적으로는 친절한 설명 + 수정 제안을 보여주고, 필요하면 기술 세부 정보를 펼쳐 보이며, 개발 모드에서는 전체 JSON 응답을 표시합니다.
모든 finishReason마다 별도 처리를 작성해야 합니까?
모든 finishReason마다 별도 처리를 작성해야 합니까?
아닙니다. 매핑 테이블과 일반적인 폴백이면 충분합니다:
reasonMessages[finishReason] || 그런 다음 원시 값을 표시합니다.