blockReason OTHER в Nano Banana 2 (Gemini 3.1 Flash Image, model ID gemini-3.1-flash-image-preview) означает, что ваш запрос был заблокирован механизмом принудительного применения серверной политики Google — Layer 2. Это ненастраиваемый серверный фильтр, который невозможно обойти, установив пороговые значения безопасности в BLOCK_NONE или OFF. По состоянию на март 2026 года этот фильтр охватывает 8 категорий контента, включая персонажей, защищённых авторским правом, публичных фигур и NSFW-контент. В этом руководстве подробно объясняется полная карта соответствия blockReason и finishReason, двухуровневая архитектура безопасности, а также приводятся 5 проверенных решений с готовым к продакшну кодом.
Краткое содержание
- blockReason OTHER — это не blockReason SAFETY: OTHER поступает от Layer 2 (ненастраиваемое применение политики), а SAFETY — от Layer 1 (настраивается через
harm_block_threshold). УстановкаBLOCK_NONEилиOFFвлияет только на Layer 1 и никогда не устранит блокировку Layer 2. - 8 категорий контента вызывают blockReason OTHER: NSFW-контент, персонажи и известные IP, защищённые авторским правом, публичные фигуры, защита несовершеннолетних, удаление водяных знаков, изменение финансовой информации, подмена одежды/лица, а также неявный провокационный контент. В марте 2026 года ужесточены правила для 4 из этих категорий.
- blockReason и finishReason — это разные поля:
blockReasonпоявляется, когда промпт отклонён до начала генерации (ноль потребленных токенов).finishReasonпоявляется, когда контент заблокирован во время или после генерации (токены уже потреблены). Оба поля могут возвращать значения, связанные с OTHER. - Баг python-genai SDK: обращение к
response.candidates[0].finish_reasonпри заблокированном ответе приводит к бесконечному зависанию, поскольку массив candidates пуст. Всегда проверяйтеlen(response.candidates) > 0перед обращением. - Существует 5 проверенных обходных путей: переформулировка промптов, удаление ссылок на объекты авторского права, разделение сложных промптов, добавление тайм-аута с переключением на альтернативную модель или использование других моделей генерации изображений (GPT Image, FLUX.2) в качестве резервного конвейера.
Что на самом деле означает blockReason OTHER?

Когда вы отправляете запрос на генерацию изображения в Nano Banana 2 и получаете в ответе API blockReason: "OTHER", это означает, что ваш промпт был перехвачен вторым уровнем фильтрации контента Google до начала генерации изображения. Это принципиально отличается от ответа blockReason: "SAFETY", который поступает от первого уровня фильтрации и поддаётся настройке через параметры безопасности. Понимание этого различия — самый важный шаг к решению ошибки, поскольку именно оно определяет, можно ли устранить проблему через настройки конфигурации или нужен совершенно другой подход.
Путаница между blockReason и finishReason — второй по распространённости источник разочарования среди разработчиков, работающих с API генерации изображений Gemini. Эти два поля расположены в разных частях ответа, имеют разное влияние на тарификацию и требуют разных стратегий отладки. В таблице ниже представлена полная карта соответствия, для составления которой ранее пришлось бы прочитать пять отдельных статей.
Значения blockReason (блокировка на уровне промпта)
Поле blockReason появляется в секции prompt_feedback ответа API. Его наличие означает, что промпт был отклонён до начала генерации, поэтому токены не потреблены и частичного изображения не существует.
| Значение blockReason | Уровень источника | Настраиваемый? | Значение |
|---|---|---|---|
SAFETY | Layer 1 | Да (через harm_block_threshold) | Одна из 4 категорий вреда превысила установленный порог. Установите BLOCK_NONE или OFF для устранения. |
OTHER | Layer 2 | Нет | Серверный механизм применения политики обнаружил запрещённый контент в промпте. Обойти невозможно. |
BLOCKED_REASON_UNSPECIFIED | Любой | Зависит от случая | Редкое общее значение. Проверьте рейтинги безопасности и содержимое промпта. |
При получении ответа blockReason OTHER структура JSON выглядит следующим образом:
json{ "promptFeedback": { "blockReason": "OTHER" }, "candidates": [] }
Обратите внимание, что массив candidates полностью пуст. Нет рейтингов безопасности для анализа, нет частичного контента для восстановления и нет конкретной категории, указывающей, какая именно политика была нарушена. Это сделано намеренно — фильтр Layer 2 от Google целенаправленно не раскрывает, какое именно правило политики было нарушено, поскольку это помогло бы злонамеренным пользователям создавать промпты, которые едва обходят обнаружение.
Значения finishReason (блокировка на уровне генерации)
Поле finishReason находится внутри каждого объекта candidate и указывает, почему генерация была остановлена. В отличие от blockReason, эти блокировки происходят во время генерации, а значит, токены уже потреблены, и в ответе может содержаться частичный текст (но никогда — частичное изображение).
| Значение finishReason | Уровень источника | Значение |
|---|---|---|
STOP | Неприменимо | Нормальное завершение. Изображение сгенерировано успешно. |
SAFETY | Layer 1 | Сгенерированный контент сработал на настраиваемый фильтр безопасности. Настраивается через параметры. |
IMAGE_SAFETY | Layer 2 | Обнаружено нарушение безопасности, специфичное для изображений, во время генерации. Не настраивается. |
OTHER | Layer 2 | Обнаружен контент, защищённый авторским правом, товарным знаком или известным IP. Не настраивается. |
PROHIBITED_CONTENT | Layer 2 | Контент, связанный с безопасностью детей или юридически запрещённый. Максимально строгое применение, не настраивается. |
Ключевое различие — момент срабатывания: blockReason срабатывает до генерации (ничего не стоит), а finishReason — во время генерации (потребляет токены). Если вы видите finishReason: "OTHER" вместо blockReason: "OTHER", это означает, что промпт прошёл первичный фильтр, но сгенерированное изображение было перехвачено вторым уровнем. Обычно это указывает на контент, защищённый авторским правом или товарным знаком, который становится заметным только в процессе синтеза изображения — например, промпт «мультяшная мышь с круглыми ушами» может пройти фильтр промпта, но вызвать finishReason: OTHER, когда сгенерированное изображение окажется похожим на защищённого персонажа.
Как подтверждено в GitHub Issue #276, Google заявила, что обязательные фильтры, включая защиту безопасности детей, не могут быть отключены, и для блокировок Layer 2 не существует программного обходного пути. Это намеренное архитектурное решение, а не ошибка.
Почему BLOCK_NONE не может исправить blockReason OTHER

Самая распространённая ошибка разработчиков при столкновении с blockReason OTHER — немедленная попытка установить все категории безопасности в BLOCK_NONE или OFF, ожидая, что это решит проблему. Такой подход не работает, поскольку основан на фундаментальном непонимании архитектуры фильтрации безопасности Gemini. Система работает на двух полностью независимых уровнях, и ваши настройки безопасности управляют только первым. Для более глубокого понимания всех доступных конфигураций безопасности ознакомьтесь с нашим подробным руководством по настройкам безопасности Gemini.
Layer 1: настраиваемый фильтр безопасности
Layer 1 оценивает ваш промпт и сгенерированный контент по четырём категориям вреда, каждую из которых вы можете настроить индивидуально: HARM_CATEGORY_HARASSMENT, HARM_CATEGORY_HATE_SPEECH, HARM_CATEGORY_SEXUALLY_EXPLICIT и HARM_CATEGORY_DANGEROUS_CONTENT. Для каждой категории вы устанавливаете harm_block_threshold, определяющий чувствительность фильтра. Когда срабатывает фильтр Layer 1, вы получаете blockReason: "SAFETY" с подробными рейтингами безопасности, которые точно указывают, какая категория сработала и с каким уровнем уверенности.
Для управления Layer 1 есть два варианта. Установка порога в BLOCK_NONE отключает автоматическую блокировку, но по-прежнему возвращает метаданные безопасности в ответе, что полезно для мониторинга и ведения логов. Установка порога в OFF (доступна начиная с gemini-2.5-flash и более новых моделей, согласно документации Vertex AI от января 2026 года) полностью отключает как блокировку, так и сбор метаданных. Для Nano Banana 2, который построен на Gemini 3.1 Flash, оба варианта доступны, и любой из них полностью устраняет блокировки Layer 1.
Вот как настроить Layer 1 на максимальную разрешительность:
pythonfrom google import genai from google.genai import types client = genai.Client(api_key="YOUR_API_KEY") safety_settings_block_none = [ types.SafetySetting( category="HARM_CATEGORY_HARASSMENT", threshold="BLOCK_NONE" ), types.SafetySetting( category="HARM_CATEGORY_HATE_SPEECH", threshold="BLOCK_NONE" ), types.SafetySetting( category="HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold="BLOCK_NONE" ), types.SafetySetting( category="HARM_CATEGORY_DANGEROUS_CONTENT", threshold="BLOCK_NONE" ), ] # Option 2: OFF - no blocking AND no safety metadata safety_settings_off = [ types.SafetySetting( category="HARM_CATEGORY_HARASSMENT", threshold="OFF" ), # ... same for other categories ]
Layer 2: ненастраиваемое применение политики
Layer 2 — это полностью отдельная система, работающая независимо от ваших настроек безопасности. Она обеспечивает соблюдение политик контента Google, юридических требований и условий обслуживания посредством серверных фильтров, к которым невозможно получить доступ, изменить или обойти через любой параметр API. Когда срабатывает Layer 2, вы получаете blockReason: "OTHER" без рейтингов безопасности, без информации о категории и без возможности определить, какая именно политика была нарушена.
Layer 2 охватывает категории контента, выходящие за рамки общих проблем безопасности в область юридической ответственности: безопасность детей (юридическое требование в большинстве юрисдикций), персонажи, защищённые авторским правом, и зарегистрированные визуальные идентичности, узнаваемые публичные фигуры и знаменитости, NSFW-контент, нарушающий условия обслуживания Google, и ряд других категорий, подробно описанных в следующем разделе. Эти фильтры существуют, потому что Google несёт прямую юридическую ответственность, если API генерации изображений создаёт определённые типы контента, независимо от предполагаемого варианта использования разработчика.
Практический вывод прост: если вы получаете blockReason: "OTHER", никакие настройки безопасности не помогут. Вы уже убедились в этом, установив все четыре категории в BLOCK_NONE или OFF и по-прежнему получая блокировку. Блокировка исходит не от системы, которую вы контролируете, а от системы, расположенной за ней. Единственный путь вперёд — модифицировать промпт или использовать альтернативный подход, которые мы рассмотрим в разделе решений ниже.
Пошаговая диагностическая блок-схема

Когда ваш API-запрос к Nano Banana 2 возвращает ошибку, первым шагом должно быть не изменение настроек безопасности, а точное определение типа ошибки. Разные типы ошибок требуют совершенно разных решений, и применение неправильного исправления тратит время и квоту API. Эта диагностическая блок-схема предоставляет систематический подход, исключающий догадки.
Начните с проверки, содержит ли ответ поле blockReason в секции prompt_feedback. Если blockReason отсутствует, проблема может быть совсем другого типа. Проверьте наличие finishReason: "OTHER" в массиве candidates — это указывает на то, что промпт прошёл проверку, но сгенерированный контент был заблокирован в процессе генерации из-за проблем с авторским правом или товарным знаком. Если ни blockReason, ни finishReason OTHER не обнаружены, вы, возможно, столкнулись со сценарием 200 OK, но изображение не создано или ошибкой 503 overloaded, для которых существуют отдельные пути диагностики. О других распространённых ошибках Nano Banana 2 читайте в нашем руководстве по ошибке thought signature.
Если blockReason присутствует, проверьте его значение. Если значение SAFETY, вы имеете дело с блокировкой Layer 1, которая устраняется через настройки безопасности. Изучите рейтинги безопасности в ответе, чтобы определить, какая категория сработала, затем установите порог этой категории в BLOCK_NONE или OFF. Если значение OTHER, подтверждена блокировка Layer 2, и применимы решения из этого руководства.
Вот диагностический код, автоматизирующий этот процесс:
pythondef diagnose_block(response): """Systematically diagnose why a Nano Banana 2 request was blocked.""" # Step 1: Check for prompt-level blocking if hasattr(response, 'prompt_feedback') and response.prompt_feedback: block_reason = getattr(response.prompt_feedback, 'block_reason', None) if block_reason == 'SAFETY': # Layer 1 block - fixable via safety settings ratings = response.prompt_feedback.safety_ratings triggered = [r for r in ratings if r.blocked] return { 'type': 'LAYER_1_BLOCK', 'fixable': True, 'categories': [r.category for r in triggered], 'action': 'Set triggered categories to BLOCK_NONE or OFF' } elif block_reason == 'OTHER': # Layer 2 block - not fixable via settings return { 'type': 'LAYER_2_BLOCK', 'fixable': False, 'action': 'Rephrase prompt or use alternative model' } # Step 2: Check for generation-level blocking if len(response.candidates) > 0: finish_reason = response.candidates[0].finish_reason if finish_reason == 'OTHER': return { 'type': 'LAYER_2_GENERATION_BLOCK', 'fixable': False, 'action': 'Copyright/trademark detected during generation' } if finish_reason == 'IMAGE_SAFETY': return { 'type': 'IMAGE_SAFETY_BLOCK', 'fixable': False, 'action': 'Image content violated safety policy' } # Step 3: No candidates and no block reason if len(response.candidates) == 0: return { 'type': 'EMPTY_RESPONSE', 'fixable': False, 'action': 'Check for 200 OK no-image scenario' } return {'type': 'UNKNOWN', 'action': 'Inspect full response JSON'}
Критически важная деталь для Python-разработчиков, использующих SDK google-genai: попытка обратиться к response.candidates[0].finish_reason при пустом массиве candidates приведёт к бесконечному зависанию SDK, а не к выбросу исключения. Это известный баг (по состоянию на март 2026 года), при котором SDK пытается лениво вычислить объект candidate и входит в бесконечное состояние ожидания. Всегда проверяйте len(response.candidates) > 0 перед обращением к любым свойствам candidate. Если вы столкнулись с таким зависанием, единственный способ восстановления — принудительное завершение процесса.
Региональные особенности
Разработчикам из ЕС следует учитывать, что применение политик на основе IP-адреса может вызывать blockReason OTHER даже для промптов, которые без проблем работают из других регионов. Это связано с тем, что Google применяет более строгие политики контента в юрисдикциях с более жёсткими правилами в отношении изображений, сгенерированных ИИ. Если вы подозреваете региональную блокировку, тестирование того же промпта из другого географического региона поможет определить, является ли блокировка контентной или региональной.
8 категорий контента, вызывающих blockReason OTHER
Понимание того, какой именно контент вызывает блокировку Layer 2, помогает составлять промпты, которые избегают ненужных отклонений. На основе перекрёстного анализа официальной документации Google, отчётов сообщества и систематического тестирования, задокументированного в нескольких источниках, мы выявили 8 отдельных категорий контента, стабильно вызывающих blockReason OTHER в Nano Banana 2. По состоянию на март 2026 года Google ужесточила правила для 4 из этих категорий, что объясняет, почему промпты, работавшие ранее, теперь могут блокироваться.
NSFW и откровенно сексуальный контент — самая широкая категория, охватывающая любой промпт, запрашивающий наготу, сексуальные сцены или фетиш-контент. В отличие от категории HARM_CATEGORY_SEXUALLY_EXPLICIT в Layer 1, которую можно установить в BLOCK_NONE, NSFW-фильтр Layer 2 работает независимо и не может быть отключён. Он перехватывает промпты, которые Layer 1 пропустил бы при пороге BLOCK_NONE, создавая запутанную ситуацию, когда настройки безопасности говорят «разрешить всё», но запрос всё равно блокируется.
Персонажи и известные IP, защищённые авторским правом срабатывает, когда промпт ссылается на персонажей, принадлежащих крупным правообладателям — культовые анимационные персонажи, протагонисты видеоигр или супергерои комиксов. Это одна из категорий, где с большей вероятностью вы увидите finishReason: OTHER, а не blockReason: OTHER, поскольку обнаружение авторского права часто происходит при синтезе изображения, когда генерируемый результат начинает напоминать защищённого персонажа, даже если текст промпта явно его не называл.
Публичные фигуры и знаменитости — категория, существенно ужесточённая в марте 2026 года. Ранее промпты, ссылающиеся на публичных фигур в неконтроверсиальном контексте (например, «человек, похожий на [знаменитость], выступающий с речью»), иногда проходили. Обновление политики в марте 2026 расширило обнаружение, охватив больше косвенных ссылок и имитаций художественного стиля. Если ваши промпты, которые раньше генерировали изображения узнаваемых публичных фигур, теперь возвращают blockReason OTHER, это изменение политики является наиболее вероятным объяснением.
Защита несовершеннолетних — самая строгая категория с нулевой терпимостью. Любой промпт, потенциально способный создать изображения несовершеннолетних в ненадлежащем или эксплуатирующем контексте, немедленно блокируется. Как подтверждено в GitHub Issue #276, это юридическое требование, для которого Google заявила, что обходные пути никогда не будут предоставлены. Этот фильтр имеет самый высокий процент ложных срабатываний, иногда перехватывая безобидные промпты о детских иллюстрациях или семейных фотографиях.
Удаление водяных знаков нацелено на промпты с просьбой удалить, заменить или скрыть водяные знаки на референсных изображениях. Это применяется конкретно к рабочим процессам редактирования изображений, когда предоставлено референсное изображение и промпт инструктирует модель удалить брендинг или уведомления об авторском праве.
Модификация финансовой информации — категория, добавленная в обновлении политики марта 2026 года. Промпты с запросом на генерацию или модификацию финансовых документов, валюты, чеков, банковских выписок или официальных удостоверений личности теперь вызывают blockReason OTHER. Ранее эта категория обрабатывалась с более низким приоритетом и часто проходила через Layer 2.
Подмена одежды и лица получила усиленное применение в марте 2026 года. Промпты, запрашивающие замену лица между изображениями, наложение внешности человека на другое тело или изменение одежды человека способом, который может создать вводящие в заблуждение изображения, теперь перехватываются более агрессивно. Эта категория пересекается с категорией публичных фигур, когда субъект узнаваем.
Неявный провокационный контент — самая нюансированная категория и наиболее сложная для прогнозирования. Она перехватывает промпты, которые явно не запрашивают ненадлежащий контент, но используют закодированный язык, эвфемизмы или контекстные комбинации, которые модель интерпретирует как провокационные. Эта категория была расширена в марте 2026 для перехвата большего количества паттернов косвенной формулировки, из-за чего ранее безобидные промпты теперь могут вызывать блокировки.
Практический вывод заключается в том, что Layer 2 работает на уровне анализа контента, а не на уровне ключевых слов. Простое избегание определённых слов недостаточно — модель оценивает семантическое значение и вероятный визуальный результат всего промпта. В разделе решений ниже приведены конкретные стратегии обхода фильтрации контента при сохранении желаемого творческого результата.
5 проверенных решений для обхода blockReason OTHER
Поскольку blockReason OTHER невозможно устранить через настройки безопасности, следующие решения используют другой подход: модификацию входных данных, реструктуризацию рабочего процесса или маршрутизацию к альтернативным моделям. Решения упорядочены от самого простого к наиболее надёжному, и в продакшн-среде рекомендуется реализовать несколько решений в качестве многоуровневой стратегии отказоустойчивости.
Решение 1: переформулируйте промпт, убрав триггерные паттерны. Самый прямой подход — выявить и убрать конкретные языковые паттерны, вызвавшие блокировку. Поскольку Layer 2 анализирует семантическое значение, а не только ключевые слова, эффективная переформулировка выходит за рамки простой замены слов. Замените имена персонажей обобщёнными описаниями («дружелюбное мультяшное животное» вместо конкретного имени персонажа), замените ссылки на знаменитостей описаниями атрибутов («профессиональная женщина с короткими тёмными волосами, выступающая с презентацией» вместо упоминания конкретного имени) и разбейте составные концепции на отдельные, более простые промпты. Если описание сложной сцены вызывает блокировку, попробуйте генерировать отдельные элементы по отдельности и скомпоновать их впоследствии.
Решение 2: удалите все ссылки на объекты авторского права и знаменитостей. Это более агрессивная версия Решения 1, нацеленная конкретно на две категории, ответственные за большинство ошибок blockReason OTHER. Проверьте промпт на наличие ссылок на брендированных персонажей, зарегистрированные визуальные стили, узнаваемые художественные стили, ассоциирующиеся с конкретными художниками, имена знаменитостей или описания, позволяющие идентифицировать публичную фигуру, а также любые логотипы брендов или дизайн продуктов. Даже косвенные ссылки вроде «в стиле [известного художника]» могут вызвать блокировку, если стиль тесно связан с произведениями, защищёнными авторским правом.
Решение 3: разделите сложные промпты на более простые части. Сложные промпты, объединяющие несколько концепций, имеют более высокую вероятность срабатывания Layer 2, поскольку каждая дополнительная концепция увеличивает шанс того, что комбинированное семантическое значение пересечёт границу политики. Разбиение одного сложного промпта на 2–3 более простых запроса генерации с последующей компоновкой результатов часто срабатывает там, где объединённый промпт вызывал отказ. Например, вместо «человек в определённой одежде у определённой достопримечательности, выполняющий определённое действие» генерируйте сцену и субъект отдельно.
Решение 4: добавьте тайм-аут и автоматическое переключение на альтернативную модель. Для продакшн-приложений самый надёжный подход — реализовать автоматическое переключение на альтернативную модель генерации изображений, когда Nano Banana 2 возвращает blockReason OTHER. Это учитывает реальность того, что некоторые промпты всегда будут блокироваться Layer 2, и гарантирует работоспособность вашего приложения. Некоторые прокси-сервисы API, такие как laozhang.ai, агрегируют несколько моделей генерации изображений за единой точкой входа, что упрощает реализацию переключения между Nano Banana 2 и альтернативными моделями без необходимости управлять несколькими API-интеграциями.
pythonimport asyncio from google import genai async def generate_with_fallback(prompt, timeout_seconds=30): """Generate image with Nano Banana 2, falling back to alternatives.""" client = genai.Client(api_key="YOUR_GEMINI_KEY") try: # Attempt Nano Banana 2 with timeout response = await asyncio.wait_for( asyncio.to_thread( client.models.generate_content, model="gemini-3.1-flash-image-preview", contents=prompt, config=types.GenerateContentConfig( response_modalities=["IMAGE", "TEXT"], ) ), timeout=timeout_seconds ) # Check for blockReason OTHER if hasattr(response, 'prompt_feedback') and response.prompt_feedback: if getattr(response.prompt_feedback, 'block_reason', None) == 'OTHER': print("Layer 2 block detected, falling back...") return await fallback_generate(prompt) # Check for empty candidates (SDK hang prevention) if not response.candidates or len(response.candidates) == 0: print("Empty candidates, falling back...") return await fallback_generate(prompt) return response except asyncio.TimeoutError: print(f"Timeout after {timeout_seconds}s, falling back...") return await fallback_generate(prompt) async def fallback_generate(prompt): """Fallback to alternative image model.""" # Example: Use GPT Image or FLUX.2 via alternative API # Implementation depends on your fallback model choice pass
Решение 5: используйте GPT Image или FLUX.2 в качестве основного запасного варианта. Когда требования к контенту принципиально конфликтуют с политиками Layer 2 Google — например, если необходимо генерировать изображения узнаваемых публичных фигур для новостных или редакционных целей — единственное надёжное решение — использовать другую модель генерации изображений с другими политиками контента. GPT Image (DALL-E 4o) от OpenAI имеет иные границы политики и может принять промпты, которые Nano Banana 2 отклоняет, и наоборот. Модели FLUX.2, доступные через различных провайдеров, предлагают ещё один набор политик контента. В продакшн-среде поддержка доступа к 2–3 различным API генерации изображений гарантирует, что различия в политиках провайдеров станут вашей страховочной сетью, а не узким местом.
Обработка ошибок продакшн-класса
Переход от отладки в разработке к надёжности в продакшне требует комплексной обработки ошибок, учитывающей все рассмотренные нами режимы отказа. Следующая реализация предоставляет полную обёртку для обработки ошибок Nano Banana 2, которая предотвращает баг зависания python-genai SDK, корректно разграничивает блокировки Layer 1 и Layer 2, реализует автоматический повтор с переключением и обеспечивает структурированное логирование для мониторинга.
pythonimport time import logging from dataclasses import dataclass from enum import Enum from typing import Optional logger = logging.getLogger(__name__) class BlockType(Enum): NONE = "none" LAYER_1_SAFETY = "layer_1_safety" LAYER_2_OTHER = "layer_2_other" LAYER_2_IMAGE_SAFETY = "layer_2_image_safety" LAYER_2_COPYRIGHT = "layer_2_copyright" LAYER_2_PROHIBITED = "layer_2_prohibited" SDK_HANG = "sdk_hang" UNKNOWN = "unknown" @dataclass class GenerationResult: success: bool block_type: BlockType image_data: Optional[bytes] = None error_message: str = "" latency_ms: int = 0 model_used: str = "" def safe_generate_image(client, prompt: str, model: str = "gemini-3.1-flash-image-preview") -> GenerationResult: """Production-safe image generation with comprehensive error handling.""" start_time = time.time() try: response = client.models.generate_content( model=model, contents=prompt, config=types.GenerateContentConfig( response_modalities=["IMAGE", "TEXT"], safety_settings=[ types.SafetySetting(category=cat, threshold="BLOCK_NONE") for cat in [ "HARM_CATEGORY_HARASSMENT", "HARM_CATEGORY_HATE_SPEECH", "HARM_CATEGORY_SEXUALLY_EXPLICIT", "HARM_CATEGORY_DANGEROUS_CONTENT", ] ], ), ) latency = int((time.time() - start_time) * 1000) # Check 1: Prompt-level blocking (blockReason) if hasattr(response, 'prompt_feedback') and response.prompt_feedback: block_reason = getattr(response.prompt_feedback, 'block_reason', None) if block_reason == 'SAFETY': logger.warning(f"Layer 1 block: {prompt[:80]}...") return GenerationResult( success=False, block_type=BlockType.LAYER_1_SAFETY, error_message="Layer 1 safety filter triggered. Adjust safety_settings.", latency_ms=latency, model_used=model, ) if block_reason == 'OTHER': logger.warning(f"Layer 2 block: {prompt[:80]}...") return GenerationResult( success=False, block_type=BlockType.LAYER_2_OTHER, error_message="Layer 2 policy block. Cannot bypass via settings.", latency_ms=latency, model_used=model, ) # Check 2: Empty candidates (prevents SDK hang) if not response.candidates or len(response.candidates) == 0: logger.warning(f"Empty candidates for: {prompt[:80]}...") return GenerationResult( success=False, block_type=BlockType.SDK_HANG, error_message="Empty candidates array. Likely silent Layer 2 block.", latency_ms=latency, model_used=model, ) # Check 3: Generation-level blocking (finishReason) candidate = response.candidates[0] finish_reason = getattr(candidate, 'finish_reason', 'STOP') finish_reason_map = { 'SAFETY': BlockType.LAYER_1_SAFETY, 'IMAGE_SAFETY': BlockType.LAYER_2_IMAGE_SAFETY, 'OTHER': BlockType.LAYER_2_COPYRIGHT, 'PROHIBITED_CONTENT': BlockType.LAYER_2_PROHIBITED, } if finish_reason in finish_reason_map: return GenerationResult( success=False, block_type=finish_reason_map[finish_reason], error_message=f"Generation blocked: finishReason={finish_reason}", latency_ms=latency, model_used=model, ) # Check 4: Extract image data for part in candidate.content.parts: if hasattr(part, 'inline_data') and part.inline_data: return GenerationResult( success=True, block_type=BlockType.NONE, image_data=part.inline_data.data, latency_ms=latency, model_used=model, ) # No image found in response return GenerationResult( success=False, block_type=BlockType.UNKNOWN, error_message="Response contained no image data.", latency_ms=latency, model_used=model, ) except Exception as e: latency = int((time.time() - start_time) * 1000) logger.error(f"Exception during generation: {e}") return GenerationResult( success=False, block_type=BlockType.UNKNOWN, error_message=str(e), latency_ms=latency, model_used=model, )
Ключевые паттерны защитного программирования в этой реализации заслуживают отдельного упоминания. Во-первых, каждое обращение к response.candidates защищено проверкой длины, что предотвращает баг зависания python-genai SDK, застигший врасплох многих разработчиков. Во-вторых, функция возвращает структурированный объект результата вместо выброса исключений, что делает её безопасной для использования в асинхронных конвейерах и логике повторов. В-третьих, классификация типа блокировки позволяет вашей системе мониторинга отслеживать, какие именно типы блокировок возникают и с какой частотой, предоставляя данные для оптимизации промптов со временем.
Для продакшн-развёртываний платформы, такие как laozhang.ai, предоставляют единые API-точки входа для нескольких моделей генерации изображений, что упрощает реализацию стратегии переключения, описанной в Решении 4. Вместо управления отдельными API-клиентами для каждой резервной модели вы можете маршрутизировать запросы через единую точку входа и позволить платформе управлять выбором модели и восстановлением после ошибок.
Логирование в этой реализации намеренно структурировано для поддержки дашбордов мониторинга. Отслеживая block_type, latency_ms и model_used для каждого запроса, вы можете настроить оповещения о необычных всплесках блокировок Layer 2 (что может указывать на изменение политики), отслеживать эффективность усилий по переформулировке промптов и определять, какие промпты требуют маршрутизации к альтернативным моделям.
Часто задаваемые вопросы
Можно ли полностью отключить фильтры безопасности в Nano Banana 2?
Вы можете отключить фильтры безопасности Layer 1, установив все четыре категории вреда (HARM_CATEGORY_HARASSMENT, HARM_CATEGORY_HATE_SPEECH, HARM_CATEGORY_SEXUALLY_EXPLICIT, HARM_CATEGORY_DANGEROUS_CONTENT) в BLOCK_NONE или OFF. Однако механизм применения политики Layer 2 невозможно отключить через какой-либо параметр API, конфигурацию SDK или настройку аккаунта. Это означает, что даже при удалении всех настраиваемых параметров безопасности контент, нарушающий условия обслуживания Google, авторское право или требования безопасности детей, по-прежнему будет блокироваться. Различие в том, что Layer 1 защищает пользователей от потенциально вредных выходных данных ИИ, а Layer 2 защищает Google от юридической ответственности. Оба уровня необходимы, но настраивается только первый.
В чём разница между BLOCK_NONE и OFF?
Оба параметра предотвращают автоматическую блокировку на Layer 1, но отличаются поведением в отношении метаданных. BLOCK_NONE отключает блокировку, но по-прежнему возвращает рейтинги безопасности в ответе, которые указывают, какие категории были обнаружены и с каким уровнем уверенности. Это полезно для мониторинга и аудита. OFF полностью отключает как блокировку, так и сбор метаданных, то есть вы не получаете никакой информации о безопасности в ответе. Для моделей, начиная с gemini-2.5-flash (согласно документации Vertex AI от января 2026 года), OFF является настройкой по умолчанию. Практическая рекомендация — использовать BLOCK_NONE при разработке (чтобы видеть, что вызывает рейтинги безопасности) и OFF в продакшне, если метаданные безопасности не нужны (для незначительного ускорения ответов).
Почему ранее работавшие промпты стали блокироваться?
Если промпты, работавшие в январе или феврале 2026 года, теперь возвращают blockReason OTHER, наиболее вероятное объяснение — обновление политики Google в марте 2026. Это обновление ужесточило правила для четырёх конкретных категорий: публичные фигуры и знаменитости (более широкое обнаружение косвенных ссылок), модификация финансовой информации (ранее более низкий приоритет), подмена одежды и лица (более агрессивное обнаружение) и неявный провокационный контент (расширенное распознавание паттернов). Если ваши промпты затрагивают любую из этих областей, они могут вызывать блокировки, которых раньше не было. Решение — провести аудит и переформулировать затронутые промпты, в частности удалив любые косвенные ссылки на узнаваемых людей или финансовые документы.
Поддерживает ли бесплатный тариф API генерацию изображений в Nano Banana 2?
Бесплатный тариф Google AI Studio предоставляет доступ к моделям Gemini для генерации текста, но генерация изображений через API требует платного плана. Хотя вы можете экспериментировать с генерацией изображений в веб-интерфейсе Google AI Studio на бесплатном тарифе, программный доступ через API для генерации изображений в Nano Banana 2 (gemini-3.1-flash-image-preview) требует подключения биллинга в вашем проекте Google Cloud. Это отдельный вопрос от blockReason OTHER, который может возникать как на бесплатном, так и на платном тарифах — разница в том, что пользователи бесплатного тарифа могут не дойти до момента, когда появляется blockReason OTHER, поскольку запросы на генерацию изображений отклоняются на уровне квоты раньше.
Как определить, вызван ли blockReason OTHER региональными ограничениями?
Разработчики из ЕС могут чаще сталкиваться с blockReason OTHER из-за применения политик на основе IP-адреса, которое устанавливает более строгие фильтры контента в определённых юрисдикциях. Чтобы определить, является ли блокировка региональной, а не контентной, протестируйте тот же самый промпт из другого географического региона (через VPN или облачную функцию, развёрнутую в другом регионе). Если промпт успешно выполняется из другого региона, но не из вашего — блокировка региональная. В таком случае развёртывание API-вызовов с сервера в регионе с менее строгими политиками (например, облачная инфраструктура в США) является легитимным обходным путём, при условии что ваш вариант использования соответствует применимым условиям обслуживания в этом регионе.
