# Ошибка Thought Signature в Nano Banana 2: 400 на втором ходе

> Второй ход в Nano Banana 2 падает с 400, если прошлую картинку отправили без подписи мышления (thought signature). Помогают previous_interaction_id и чат SDK.

- URL: https://blog.laozhang.ai/ru/posts/nano-banana-2-thought-signature-error
- Published: 2026-03-09
- Updated: 2026-10-05
- Author: LaoZhang AI Team (https://blog.laozhang.ai/ru/about)
- Topic: Руководства по API
- Tags: Nano Banana 2, Thought Signature, Gemini API, Редактирование изображений, Ошибки API

---
Ошибка вида `Image part is missing a thought_signature in content position 2, part position 1` означает одно: в запросе на второй ход лежит изображение, которое раньше сгенерировала сама модель, но без подписи мышления (thought signature), пришедшей вместе с ним. Nano Banana 2 (`gemini-3.1-flash-image`) такой запрос отклоняет с HTTP 400 `INVALID_ARGUMENT`. Чинится это не подстановкой какой-то строки, а тем, чтобы ответ модели попадал в следующий запрос без изменений. Проще всего вести диалог через Interactions API с `previous_interaction_id`: тогда подписи хранит сервер. В `generateContent` используйте чат SDK или добавляйте в историю объект ответа целиком. Если историю собирает фреймворк, обновите его или откройте issue с точным текстом ошибки.

## Что значит «Image part is missing a thought_signature»

Подпись мышления — это зашифрованное представление внутренних рассуждений модели. По [руководству Google о мышлении](https://ai.google.dev/gemini-api/docs/thinking) она нужна, чтобы модель продолжала ход рассуждений между ходами диалога. Расшифровать или собрать её вручную нельзя, её можно только вернуть такой, какой она пришла. Отдельная страница `/thought-signatures`, на которую ссылаются старые сообщения об ошибке, теперь перенаправляет в это руководство.

В `generateContent` у подписи нет своего блока: это метаданные, прикреплённые к одной из частей ответа (`parts`), например к части с картинкой (`inlineData`), к последней текстовой части или к вызову функции. Когда приложение пересобирает историю «по смыслу» (взяло текст, взяло байты изображения, положило в новую часть с ролью `model`), метаданные теряются. На первом ходе всё работает, потому что модели ещё нечего проверять. Второй ход отправляет её же картинку без подписи и получает 400.

Позиции в тексте ошибки подсказывают, где искать: `content position` указывает на элемент массива `contents`, `part position` — на часть внутри него. С какого числа начинается счёт, Google не поясняет, поэтому надёжнее найти в истории ход модели с изображением и проверить, есть ли у его частей поле `thoughtSignature`.

Та же причина выглядит по-разному в зависимости от интерфейса:

| Где | Как выглядит |
| --- | --- |
| `generateContent`, HTTP-ответ | 400 `INVALID_ARGUMENT`, текст про отсутствующую `thought_signature` |
| `generateContent`, поле `finishReason` | `MISSING_THOUGHT_SIGNATURE` («в запросе не хватает хотя бы одной подписи мышления») |
| Interactions API | код ошибки `missing_thought_signature` |

Значения из второй и третьей строк перечислены в [справочнике generateContent](https://ai.google.dev/api/generate-content) и на странице [ошибок API](https://ai.google.dev/gemini-api/docs/api-errors). Если в ответе вообще нет картинки и при этом нет ошибки, причина другая — разбор по полям ответа есть в статье [«Nano Banana не генерирует изображение в API: как найти причину»](https://blog.laozhang.ai/ru/posts/nano-banana-2-200-ok-no-image).

## Почему ошибка появилась на Nano Banana 2, а на Nano Banana Pro её не было

Код, который работал с Nano Banana Pro, может сломаться на Nano Banana 2, хотя обе модели относятся к Gemini 3. Страница Google Cloud [Thought signatures](https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/thinking/thought-signatures) прямо говорит, что Gemini 3 Pro Image (`gemini-3-pro-image`) не проверяет подписи и не возвращает 400, если их не вернули. Возвращать их всё равно нужно, иначе модель теряет контекст между правками.

Про Nano Banana 2 в той же документации отдельного правила нет. Зато есть сообщение разработчиков: в [issue #12988 в репозитории Vercel AI SDK](https://github.com/vercel/ai/issues/12988), открытом 2 марта 2026 года, второй ход после генерации картинки в `gemini-3.1-flash-image-preview` упал с 400 `INVALID_ARGUMENT` и тем самым текстом про `content position 2, part position 1`. SDK отправлял прошлое изображение без подписи. Тот же сценарий, по словам автора, работал с `gemini-2.5-flash-image`. Судя по этому отчёту, Nano Banana 2 подписи частей с изображением проверяет, а Pro, по документации, при пропуске подписи ошибку не возвращает. Полагаться на это исключение не стоит: в [отчёте о плагине Dify за декабрь 2025 года](https://github.com/langgenius/dify-official-plugins/issues/2262) та же 400 с «Image part is missing a thought_signature» пришла от предварительной версии Nano Banana Pro.

Оба названия из того отчёта уже недоступны. Предварительная версия `gemini-3.1-flash-image-preview` отключена 25 июня 2026 года, `gemini-2.5-flash-image` — 2 октября 2026 года (по [странице выводимых из эксплуатации моделей](https://ai.google.dev/gemini-api/docs/deprecations)). Текущие ID: `gemini-3.1-flash-image` для Nano Banana 2 и `gemini-3-pro-image` для Nano Banana Pro. Если вы переносите код со старых ID, проверяйте именно второй и последующие ходы, а не только первую генерацию.

## Способ 1: Interactions API и previous_interaction_id

[Гайд Google по генерации изображений](https://ai.google.dev/gemini-api/docs/image-generation) сейчас построен на Interactions API, и многоходовое редактирование там делается через `previous_interaction_id`. В режиме с состоянием (хранение включено, следующий запрос ссылается на прошлый) сервер сам держит историю вместе с блоками мышления и подписями. По руководству о мышлении, в этом режиме «ничего делать с подписями не нужно». Для новой интеграции это самый короткий путь: ошибке просто неоткуда взяться.

```python
# Пример не запускался; формы вызовов взяты из гайда Google по изображениям.
import base64
from google import genai

client = genai.Client()  # ключ из переменной окружения GEMINI_API_KEY

first = client.interactions.create(
    model="gemini-3.1-flash-image",
    input="Керамическая кружка на деревянном столе, мягкий утренний свет",
)
with open("mug_v1.png", "wb") as f:
    f.write(base64.b64decode(first.output_image.data))

# Второй ход: передаём только id прошлого шага, историю и подписи хранит сервер
second = client.interactions.create(
    model="gemini-3.1-flash-image",
    input="Сделай кружку тёмно-синей, остальное не меняй",
    previous_interaction_id=first.id,
)
with open("mug_v2.png", "wb") as f:
    f.write(base64.b64decode(second.output_image.data))
```

Если хранение (`store`) выключено и всю историю вы присылаете сами, это уже режим без состояния. Тогда правило из руководства строгое: блоки мышления нужно отправлять обратно ровно в том виде, в каком они пришли, ничего не удаляя и не меняя. Это касается и шагов встроенных инструментов вроде `google_search`: у них свои подписи, и их тоже нужно возвращать. Пример многоходового редактирования в гайде Google как раз использует поиск, так что этот случай легко пропустить.

## Способ 2: generateContent — чат SDK или ответ модели целиком

Если проект уже работает через `generateContent`, переписывать его на Interactions API не обязательно. В официальном SDK `google-genai` (`from google import genai`) подписи обрабатываются автоматически, когда вы пользуетесь чатом или добавляете в историю объект ответа модели без изменений. Это сказано на той же странице Google Cloud, и её пример многоходового редактирования изображений сделан через чат.

```python
# Пример не запускался; чат SDK сам возвращает подписи в следующий запрос.
from google import genai
from google.genai import types

client = genai.Client()
chat = client.chats.create(
    model="gemini-3.1-flash-image",
    config=types.GenerateContentConfig(response_modalities=["TEXT", "IMAGE"]),
)

def save_images(response, name):
    for i, part in enumerate(response.candidates[0].content.parts):
        if part.inline_data:
            with open(f"{name}_{i}.png", "wb") as f:
                f.write(part.inline_data.data)

r1 = chat.send_message("Керамическая кружка на деревянном столе")
save_images(r1, "mug_v1")

r2 = chat.send_message("Сделай кружку тёмно-синей, остальное не меняй")
save_images(r2, "mug_v2")
```

Обратите внимание: старый пакет `google-generativeai` с `genai.GenerativeModel` и `start_chat()` в текущей документации Google не используется. Если ваш код начинается с `import google.generativeai`, переход на `google-genai` стоит сделать заодно.

### Если историю хранит ваш код

Когда чат SDK не подходит (история лежит в базе, запросы идут с разных серверов), правило одно: ход модели кладётся в историю как есть, объектом `Content` из ответа, а не пересобирается из текста и байтов.

```python
# Правильно: ответ модели целиком, вместе с подписью на части с картинкой
history = [
    types.Content(role="user", parts=[types.Part(text=prompt_1)]),
    r1.candidates[0].content,
    types.Content(role="user", parts=[types.Part(text=prompt_2)]),
]
r2 = client.models.generate_content(
    model="gemini-3.1-flash-image",
    contents=history,
    config=types.GenerateContentConfig(response_modalities=["TEXT", "IMAGE"]),
)

# Так и получается 400: картинка модели пересобрана в новую часть без подписи
broken_turn = types.Content(
    role="model",
    parts=[types.Part.from_bytes(data=image_bytes, mime_type="image/png")],
)
```

Если историю нужно сохранить между сессиями, сохраняйте все части хода модели со всеми полями, включая `thoughtSignature` (в REST-ответе поле называется так, в Python SDK — `thought_signature`). Google Cloud перечисляет ещё три правила для ручной работы: возвращать подпись внутри той же части, в которой она пришла; не склеивать часть с подписью и часть без неё; не объединять две части с подписями, потому что строки подписей не складываются.

Отдельный крайний случай: старый диалог, где подписи не сохранились вовсе. Задокументированной замены подписи для частей с изображением нет. Остаётся начать новый диалог и передать последнюю картинку как входное изображение в сообщении пользователя: в истории тогда нет ходов модели, и проверять нечего. Контекст прошлых правок модель при этом не видит, так что задачу лучше описать в запросе заново.

### Потоковый ответ: подпись в части с пустым текстом

При потоковой генерации подпись может прийти в отдельной части с пустым текстом. Google Cloud советует разбирать все части до появления `finish_reason`. Цикл, который берёт только `chunk.text` или пропускает части с пустой строкой, подпись выбросит, и следующий ход упадёт. Если вы склеиваете поток в итоговый ответ сами, собирайте именно части (`parts`) со всеми полями, а не только текст.

![Потоковый ответ: сохранить все parts, включая пустой текст и метаданные подписи](https://blog.laozhang.ai/posts/ru/nano-banana-2-thought-signature-error/img/content-2.webp)



## Способ 3: фреймворк теряет подпись — Vercel AI SDK, n8n, Dify, LangGraph

Если вы не собираете запросы сами, а работаете через обёртку, ошибка почти всегда значит одно: библиотека хранит историю как «текст плюс вложения» и при следующем вызове пересобирает части без метаданных.

- **Vercel AI SDK.** Тот самый случай из issue #12988 исправлен изменением «fix missing support for image thought signatures», которое вошло в пакет `ai` версии 6.0.114. Если ошибка появилась на второй правке картинки, сначала обновите `ai` до 6.0.114 или новее.
- **n8n и плагин Gemini для Dify.** Похожие сообщения пользователей есть для обеих платформ. Какая версия узла или плагина это исправляет, смотрите в журнале изменений. Пока исправления нет, рабочий путь — HTTP-запрос к API напрямую, где ответ модели сохраняется целиком, либо Interactions API с `previous_interaction_id`.
- **LangGraph, LangChain и другие обёртки.** Проверьте, сохраняет ли конвертер сообщений метаданные отдельных частей ответа. Если в сохранённой истории у хода модели с картинкой нет `thought_signature`, проблема именно там.

Если обновление не помогло, откройте issue в репозитории фреймворка. Приложите точный текст ошибки с позициями, ID модели (`gemini-3.1-flash-image`) и фрагмент истории второго запроса без данных изображения. По этим трём вещам разработчики библиотеки быстро видят, на каком шаге пропадает подпись.

## Подписи при вызове функций в Gemini 3: что проверяется и когда возвращается 400

Если в том же диалоге модель вызывает функции (агентный сценарий, где картинка — один из шагов), правила строже, и они уже официально задокументированы. По странице Google Cloud, модели Gemini 3 возвращают 400, если не вернуть обязательную подпись, причём даже при минимальном уровне мышления.

![Подписи в вызовах функций Gemini 3: возвращать подписанные части и порядок параллельных вызовов](https://blog.laozhang.ai/posts/ru/nano-banana-2-thought-signature-error/img/content-1.webp)



- **Последовательные вызовы.** Ход начинается с последнего сообщения пользователя, которое не является ответом функции (`functionResponse`). Внутри хода каждый шаг с вызовом функции несёт подпись на первой части `functionCall`. Проверяются все шаги текущего хода, и пропуск любой из этих подписей даёт 400.
- **Параллельные вызовы.** Подпись есть только у первой части `functionCall`. Возвращать нужно сначала все вызовы, потом все ответы: `FC1+подпись, FC2, FR1, FR2`. Чередование `FC1, FR1, FC2, FR2` тоже даёт 400.
- **Части без вызова функций.** Подпись может прийти в последней части ответа. Вернуть её рекомендуется, но без неё ошибки не будет. Исключение, по сообщениям разработчиков, — части с изображением в Nano Banana 2 (см. выше).

`skip_thought_signature_validator` — это значение, которое Google разрешает записать в `thought_signature` для частей `functionCall`, сгенерированных не этим API, например при переносе истории от модели, которая подписей не выдаёт. Google называет его крайней мерой: оно ухудшает работу модели. Для частей с изображением такой вариант не описан, и рассчитывать на него при редактировании картинок не стоит.

В примерах Google Cloud для Chat Completions (OpenAI-совместимого интерфейса Vertex) подпись лежит в каждом элементе `tool_calls` по пути `extra_content.google.thought_signature`. Логика та же: элемент нужно вернуть в следующем запросе без изменений.

## Подпись мышления (thought signature): короткие ответы

### Можно ли подставить фиктивную подпись к картинке, чтобы убрать 400?

Задокументированного способа нет. `skip_thought_signature_validator` описан только для частей `functionCall`, которые API не генерировал, и даже там это крайняя мера. Для изображений рабочие варианты — вернуть настоящую подпись или начать новый диалог с картинкой во входном сообщении пользователя.

### Нужно ли возвращать подписи, если уровень мышления минимальный?

Да. Google Cloud пишет, что для моделей Gemini 3 подписи из прошлых ответов нужно возвращать и при минимальном уровне мышления, иначе на обязательных местах будет 400.

### Что значит «Thought signature is not valid»?

Подпись в запросе есть, но проверку не прошла. Google такие случаи по отдельности не расписывает. Правила Google для ручной работы с подписями указывают на три возможные причины: строку подписи изменили или перекодировали, перенесли в другую часть или склеили части между собой. Проверьте, что сохранённый ход модели совпадает с полученным ответом байт в байт.

### Можно ли сменить модель посреди диалога?

В Interactions API без состояния руководство Google велит при смене модели всё равно отправлять блоки мышления предыдущей модели, а совместимостью занимается сервер. Страница Google Cloud добавляет общее правило: историю передавайте либо полностью (мысли, вызовы функций, ответы), либо без этого контекста целиком. Частичная история ухудшает ответы.

### Где разобраны другие ошибки генерации изображений Gemini?

Ограничения по частоте, пустые ответы и сломанные параметры собраны в [разборе ошибок генерации изображений Gemini](https://blog.laozhang.ai/ru/posts/gemini-image-common-errors-fix). Сбои в приложении Gemini, а не в API, описаны в статье [«Nano Banana не работает в Gemini»](https://blog.laozhang.ai/ru/posts/nano-banana-not-working-gemini-image-errors), а сообщение «Something went wrong (5)» — в статье [«Nano Banana Pro: ошибка 5 в Gemini»](https://blog.laozhang.ai/ru/posts/nano-banana-pro-error-5). Базовая настройка ключа, моделей и кода на Python — в руководстве [Gemini Image API](https://blog.laozhang.ai/ru/posts/gemini-image-api-guide-2026).

## Официальная документация

Параметры запросов, цены и правила списания средств описаны в документации LaoZhang API для разработчиков: [биллинг и ошибки генерации изображений](https://docs.laozhang.ai/en/api-capabilities/image-billing-and-failures).

*Примечание: [laozhang.ai — наш собственный сервис](https://blog.laozhang.ai/ru/about#laozhang); его цены — наши тарифы, а не независимое сравнение.*

## Источники

Внешние страницы, на которые ссылается это руководство, в порядке упоминания. Последнее обновление: 2026-10-05.

- [руководству Google о мышлении](https://ai.google.dev/gemini-api/docs/thinking) (ai.google.dev)
- [справочнике generateContent](https://ai.google.dev/api/generate-content) (ai.google.dev)
- [ошибок API](https://ai.google.dev/gemini-api/docs/api-errors) (ai.google.dev)
- [Thought signatures](https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/thinking/thought-signatures) (docs.cloud.google.com)
- [issue #12988 в репозитории Vercel AI SDK](https://github.com/vercel/ai/issues/12988) (github.com)
- [отчёте о плагине Dify за декабрь 2025 года](https://github.com/langgenius/dify-official-plugins/issues/2262) (github.com)
- [странице выводимых из эксплуатации моделей](https://ai.google.dev/gemini-api/docs/deprecations) (ai.google.dev)
- [Гайд Google по генерации изображений](https://ai.google.dev/gemini-api/docs/image-generation) (ai.google.dev)
