Подписи мыслей

Сигнатуры мыслей представляют собой зашифрованные представления внутреннего мыслительного процесса модели и используются для сохранения контекста рассуждений при многооборотном взаимодействии. При использовании моделей мышления (таких как серии Gemini 3 и 2.5) API может возвращать поле thoughtSignature в составе содержимого ответа (например, text или functionCall частей).

Как правило, если вы получаете сигнатуру мысли в ответе модели, вы должны передать её обратно в том же виде, в котором она была получена, при отправке истории разговора в следующем шаге. При использовании Gemini 3 Pro необходимо передавать сигнатуры мысли во время вызова функции, иначе вы получите ошибку валидации (код статуса 4xx).

Как это работает

На рисунке ниже наглядно показано значение терминов «поворот» и «шаг» применительно к вызову функций в API Gemini. «Поворот» — это единичный, полный обмен данными в диалоге между пользователем и моделью. «Шаг» — это более детальное действие или операция, выполняемая моделью, часто в рамках более крупного процесса для завершения хода.

Диаграмма поворотов и шагов вызова функций

В этом документе основное внимание уделено обработке вызовов функций в Gemini 3 Pro. Информация о расхождениях с версией 2.5 приведена в разделе, посвященном поведению модели .

Gemini 3 Pro возвращает сигнатуры мыслей для всех ответов модели (ответов API) при вызове функции. Сигнатуры мыслей отображаются в следующих случаях:

  • При наличии параллельных вызовов функций первая часть вызова функции, возвращаемая ответом модели, будет иметь сигнатуру мысли.
  • При последовательных вызовах функций (многошаговых) каждый вызов функции будет иметь сигнатуру, и вам необходимо будет передать все сигнатуры обратно.
  • Ответы модели без вызова функции вернут сигнатуру мысли внутри последней части, возвращаемой моделью.

В следующей таблице представлена ​​визуализация многошаговых вызовов функций, объединяющая определения поворотов и шагов с концепцией сигнатур, представленной выше:

Повернуть

Шаг

Запрос пользователя

Модель ответа

ФункцияОтвет

1

1

request1 = user_prompt FC1 + signature FR1

1

2

request2 = request1 + (FC1 + signature) + FR1 FC2 + signature FR2

1

3

request3 = request2 + (FC2 + signature) + FR2 text_output

(без FC)

Никто

Сигнатуры в частях вызова функций

Когда Gemini генерирует functionCall , он полагается на thought_signature для правильной обработки выходных данных инструмента в следующем ходу.

  • Поведение :
    • Одиночный вызов функции : часть functionCall будет содержать thought_signature .
    • Параллельные вызовы функций : если модель генерирует параллельные вызовы функций в ответе, thought_signature добавляется только к первой части functionCall . Последующие части functionCall в том же ответе не будут содержать сигнатуру.
  • Требование : Вы должны вернуть эту подпись именно в той части, в которой она была получена при обратной отправке истории разговора.
  • Проверка : строгая проверка применяется ко всем вызовам функций в текущем ходу. (Требуется только текущий ход; проверка на предыдущих ходах не выполняется.)
    • API просматривает историю (от самых новых к самым старым), чтобы найти самое последнее сообщение пользователя со стандартным содержимым (например, text ) (которое будет началом текущего хода). Это не будет functionResponse .
    • Все ходы functionCall модели, происходящие после этого конкретного сообщения об использовании, считаются частью хода.
    • Первая часть functionCall на каждом шаге текущего хода должна включать свою thought_signature .
    • Если вы пропустите thought_signature для первой части functionCall на любом этапе текущего хода, запрос завершится ошибкой 400.
  • Если не будут возвращены надлежащие подписи, вот как вы получите ошибку
    • gemini-3-pro-preview : Отсутствие подписей приведёт к ошибке 400. Текст будет выглядеть следующим образом:
      • В вызове функции <Function Call> в блоке контента <index of contents array> отсутствует thought_signature . Например, в вызове функции FC1 в блоке контента 1. отсутствует thought_signature .

Пример последовательного вызова функции

В этом разделе показан пример множественных вызовов функций, где пользователь задает сложный вопрос, требующий выполнения нескольких задач.

Давайте рассмотрим пример вызова многооборотной функции, в котором пользователь задает сложный вопрос, требующий выполнения нескольких задач: "Check flight status for AA100 and book a taxi if delayed" .

Повернуть

Шаг

Запрос пользователя

Модель ответа

ФункцияОтвет

1

1

request1="Check flight status for AA100 and book a taxi 2 hours before if delayed." FC1 ("check_flight") + signature FR1

1

2

request2 = request1 + FC1 ("check_flight") + signature + FR1 FC2("book_taxi") + signature FR2

1

3

request3 = request2 + FC2 ("book_taxi") + signature + FR2 text_output

(без FC)

None

Следующий код иллюстрирует последовательность, представленную в таблице выше.

Поворот 1, Шаг 1 (запрос пользователя)

{
  "contents": [
    {
      "role": "user",
      "parts": [
        {
          "text": "Check flight status for AA100 and book a taxi 2 hours before if delayed."
        }
      ]
    }
  ],
  "tools": [
    {
      "functionDeclarations": [
        {
          "name": "check_flight",
          "description": "Gets the current status of a flight",
          "parameters": {
            "type": "object",
            "properties": {
              "flight": {
                "type": "string",
                "description": "The flight number to check"
              }
            },
            "required": [
              "flight"
            ]
          }
        },
        {
          "name": "book_taxi",
          "description": "Book a taxi",
          "parameters": {
            "type": "object",
            "properties": {
              "time": {
                "type": "string",
                "description": "time to book the taxi"
              }
            },
            "required": [
              "time"
            ]
          }
        }
      ]
    }
  ]
}

Ход 1, Шаг 1 (Модель ответа)

{
"content": {
        "role": "model",
        "parts": [
          {
            "functionCall": {
              "name": "check_flight",
              "args": {
                "flight": "AA100"
              }
            },
            "thoughtSignature": "<Signature A>"
          }
        ]
  }
}

Поворот 1, шаг 2 (ответ пользователя — отправка выходных данных инструмента) Поскольку этот ход пользователя содержит только functionResponse (без нового текста), мы все еще находимся на повороте 1. Мы должны сохранить <Signature_A> .

{
      "role": "user",
      "parts": [
        {
          "text": "Check flight status for AA100 and book a taxi 2 hours before if delayed."
        }
      ]
    },
    {
        "role": "model",
        "parts": [
          {
            "functionCall": {
              "name": "check_flight",
              "args": {
                "flight": "AA100"
              }
            },
            "thoughtSignature": "<Signature A>" //Required and Validated
          }
        ]
      },
      {
        "role": "user",
        "parts": [
          {
            "functionResponse": {
              "name": "check_flight",
              "response": {
                "status": "delayed",
                "departure_time": "12 PM"
                }
              }
            }
        ]
}

Поворот 1, Шаг 2 (Модель) Теперь модель решает заказать такси на основе предыдущих выходных данных инструмента.

{
      "content": {
        "role": "model",
        "parts": [
          {
            "functionCall": {
              "name": "book_taxi",
              "args": {
                "time": "10 AM"
              }
            },
            "thoughtSignature": "<Signature B>"
          }
        ]
      }
}

Поворот 1, Шаг 3 (Пользователь — Отправка выходных данных инструмента) Чтобы отправить подтверждение бронирования такси, мы должны включить подписи для ВСЕХ вызовов функций в этом цикле ( <Signature A> + <Signature B> ).

{
      "role": "user",
      "parts": [
        {
          "text": "Check flight status for AA100 and book a taxi 2 hours before if delayed."
        }
      ]
    },
    {
        "role": "model",
        "parts": [
          {
            "functionCall": {
              "name": "check_flight",
              "args": {
                "flight": "AA100"
              }
            },
            "thoughtSignature": "<Signature A>" //Required and Validated
          }
        ]
      },
      {
        "role": "user",
        "parts": [
          {
            "functionResponse": {
              "name": "check_flight",
              "response": {
                "status": "delayed",
                "departure_time": "12 PM"
              }
              }
            }
        ]
      },
      {
        "role": "model",
        "parts": [
          {
            "functionCall": {
              "name": "book_taxi",
              "args": {
                "time": "10 AM"
              }
            },
            "thoughtSignature": "<Signature B>" //Required and Validated
          }
        ]
      },
      {
        "role": "user",
        "parts": [
          {
            "functionResponse": {
              "name": "book_taxi",
              "response": {
                "booking_status": "success"
              }
              }
            }
        ]
    }
}

Пример параллельного вызова функции

Давайте рассмотрим пример вызова параллельной функции, где пользователь спрашивает: "Check weather in Paris and London" чтобы увидеть, где модель выполняет проверку.

Повернуть

Шаг

Запрос пользователя

Модель ответа

ФункцияОтвет

1

1

request1="Проверьте погоду в Париже и Лондоне"

FC1 («Париж») + подпись

FC2 («Лондон»)

ФР1

1

2

запрос 2 = запрос1 + FC1 («Париж») + подпись + FC2 («Лондон»)

текстовый_вывод

(без FC)

Никто

Следующий код иллюстрирует последовательность, представленную в таблице выше.

Поворот 1, Шаг 1 (запрос пользователя)

{
  "contents": [
    {
      "role": "user",
      "parts": [
        {
          "text": "Check the weather in Paris and London."
        }
      ]
    }
  ],
  "tools": [
    {
      "functionDeclarations": [
        {
          "name": "get_current_temperature",
          "description": "Gets the current temperature for a given location.",
          "parameters": {
            "type": "object",
            "properties": {
              "location": {
                "type": "string",
                "description": "The city name, e.g. San Francisco"
              }
            },
            "required": [
              "location"
            ]
          }
        }
      ]
    }
  ]
}

Ход 1, Шаг 1 (Модель ответа)

{
  "content": {
    "parts": [
      {
        "functionCall": {
          "name": "get_current_temperature",
          "args": {
            "location": "Paris"
          }
        },
        "thoughtSignature": "<Signature_A>"// INCLUDED on First FC
      },
      {
        "functionCall": {
          "name": "get_current_temperature",
          "args": {
            "location": "London"
          }// NO signature on subsequent parallel FCs
        }
      }
    ]
  }
}

Поворот 1, Шаг 2 (Ответ пользователя — Отправка выходных данных инструмента) Мы должны сохранить <Signature_A> в первой части точно так же, как получено.

[
  {
    "role": "user",
    "parts": [
      {
        "text": "Check the weather in Paris and London."
      }
    ]
  },
  {
    "role": "model",
    "parts": [
      {
        "functionCall": {
          "name": "get_current_temperature",
          "args": {
            "city": "Paris"
          }
        },
        "thought_signature": "<Signature_A>" // MUST BE INCLUDED
      },
      {
        "functionCall": {
          "name": "get_current_temperature",
          "args": {
            "city": "London"
          }
        }
      } // NO SIGNATURE FIELD
    ]
  },
  {
    "role": "user",
    "parts": [
      {
        "functionResponse": {
          "name": "get_current_temperature",
          "response": {
            "temp": "15C"
          }
        }
      },
      {
        "functionResponse": {
          "name": "get_current_temperature",
          "response": {
            "temp": "12C"
          }
        }
      }
    ]
  }
]

Подписи в functionCall частях вызова

Gemini также может возвращать thought_signatures в заключительной части ответа в частях, не являющихся вызовами функций.

  • Поведение : Конечная часть содержимого ( text, inlineData… ), возвращаемая моделью, может содержать thought_signature .
  • Рекомендация : рекомендуется возвращать эти подписи, чтобы гарантировать, что модель поддерживает высокое качество рассуждений, особенно для сложных инструкций или моделируемых рабочих процессов агентов.
  • Валидация : API не требует строгой проверки. Если вы её пропустите, ошибка блокировки не возникнет, хотя производительность может снизиться.

Текстовое/контекстное рассуждение (без проверки)

Ход 1, Шаг 1 (Модель ответа)

{
  "role": "model",
  "parts": [
    {
      "text": "I need to calculate the risk. Let me think step-by-step...",
      "thought_signature": "<Signature_C>" // OPTIONAL (Recommended)
    }
  ]
}

Поворот 2, Шаг 1 (Пользователь)

[
  { "role": "user", "parts": [{ "text": "What is the risk?" }] },
  {
    "role": "model", 
    "parts": [
      {
        "text": "I need to calculate the risk. Let me think step-by-step...",
        // If you omit <Signature_C> here, no error will occur.
      }
    ]
  },
  { "role": "user", "parts": [{ "text": "Summarize it." }] }
]

Подписи для совместимости с OpenAI

В следующих примерах показано, как обрабатывать подписи мыслей для API завершения чата с использованием совместимости с OpenAI .

Пример последовательного вызова функции

Это пример вызова нескольких функций, когда пользователь задает сложный вопрос, требующий выполнения нескольких задач.

Давайте рассмотрим пример вызова многооборотной функции, в котором пользователь спрашивает Check flight status for AA100 and book a taxi if delayed и вы увидите, что происходит, когда пользователь задает сложный вопрос, требующий выполнения нескольких задач.

Повернуть

Шаг

Запрос пользователя

Модель ответа

ФункцияОтвет

1

1

request1="Check the weather in Paris and London" FC1 ("Paris") + signature

FC2 («Лондон»)

FR1

1

2

request 2 = request1 + FC1 ("Paris") + signature + FC2 ("London") text_output

(без FC)

None

Следующий код проходит по заданной последовательности.

Поворот 1, Шаг 1 (Запрос пользователя)

{
  "model": "google/gemini-3-pro-preview",
  "messages": [
    {
      "role": "user",
      "content": "Check flight status for AA100 and book a taxi 2 hours before if delayed."
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "check_flight",
        "description": "Gets the current status of a flight",
        "parameters": {
          "type": "object",
          "properties": {
            "flight": {
              "type": "string",
              "description": "The flight number to check."
            }
          },
          "required": [
            "flight"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "book_taxi",
        "description": "Book a taxi",
        "parameters": {
          "type": "object",
          "properties": {
            "time": {
              "type": "string",
              "description": "time to book the taxi"
            }
          },
          "required": [
            "time"
          ]
        }
      }
    }
  ]
}

Поворот 1, Шаг 1 (Модель ответа)

{
      "role": "model",
        "tool_calls": [
          {
            "extra_content": {
              "google": {
                "thought_signature": "<Signature A>"
              }
            },
            "function": {
              "arguments": "{\"flight\":\"AA100\"}",
              "name": "check_flight"
            },
            "id": "function-call-1",
            "type": "function"
          }
        ]
    }

Поворот 1, шаг 2 (Ответ пользователя — Отправка выходных данных инструмента)

Поскольку этот ход пользователя содержит только functionResponse (без нового текста), мы все еще находимся на шаге 1 и должны сохранить <Signature_A> .

"messages": [
    {
      "role": "user",
      "content": "Check flight status for AA100 and book a taxi 2 hours before if delayed."
    },
    {
      "role": "model",
        "tool_calls": [
          {
            "extra_content": {
              "google": {
                "thought_signature": "<Signature A>" //Required and Validated
              }
            },
            "function": {
              "arguments": "{\"flight\":\"AA100\"}",
              "name": "check_flight"
            },
            "id": "function-call-1",
            "type": "function"
          }
        ]
    },
    {
      "role": "tool",
      "name": "check_flight",
      "tool_call_id": "function-call-1",
      "content": "{\"status\":\"delayed\",\"departure_time\":\"12 PM\"}"                 
    }
  ]

Поворот 1, Шаг 2 (Модель)

Теперь модель принимает решение заказать такси на основе предыдущих результатов инструмента.

{
"role": "model",
"tool_calls": [
{
"extra_content": {
"google": {
"thought_signature": "<Signature B>"
}
            },
            "function": {
              "arguments": "{\"time\":\"10 AM\"}",
              "name": "book_taxi"
            },
            "id": "function-call-2",
            "type": "function"
          }
       ]
}

Поворот 1, Шаг 3 (Пользователь — отправка выходных данных инструмента)

Чтобы отправить подтверждение бронирования такси, мы должны включить подписи для ВСЕХ вызовов функций в этом цикле ( <Signature A> + <Signature B> ).

"messages": [
    {
      "role": "user",
      "content": "Check flight status for AA100 and book a taxi 2 hours before if delayed."
    },
    {
      "role": "model",
        "tool_calls": [
          {
            "extra_content": {
              "google": {
                "thought_signature": "<Signature A>" //Required and Validated
              }
            },
            "function": {
              "arguments": "{\"flight\":\"AA100\"}",
              "name": "check_flight"
            },
            "id": "function-call-1d6a1a61-6f4f-4029-80ce-61586bd86da5",
            "type": "function"
          }
        ]
    },
    {
      "role": "tool",
      "name": "check_flight",
      "tool_call_id": "function-call-1d6a1a61-6f4f-4029-80ce-61586bd86da5",
      "content": "{\"status\":\"delayed\",\"departure_time\":\"12 PM\"}"                 
    },
    {
      "role": "model",
        "tool_calls": [
          {
            "extra_content": {
              "google": {
                "thought_signature": "<Signature B>" //Required and Validated
              }
            },
            "function": {
              "arguments": "{\"time\":\"10 AM\"}",
              "name": "book_taxi"
            },
            "id": "function-call-65b325ba-9b40-4003-9535-8c7137b35634",
            "type": "function"
          }
        ]
    },
    {
      "role": "tool",
      "name": "book_taxi",
      "tool_call_id": "function-call-65b325ba-9b40-4003-9535-8c7137b35634",
      "content": "{\"booking_status\":\"success\"}"
    }
  ]

Пример параллельного вызова функции

Давайте рассмотрим пример вызова параллельной функции, где пользователи спрашивают: "Check weather in Paris and London" , и вы увидите, где модель выполняет проверку.

Повернуть

Шаг

Запрос пользователя

Модель ответа

ФункцияОтвет

1

1

request1="Check the weather in Paris and London" FC1 ("Paris") + signature

FC2 («Лондон»)

FR1

1

2

request 2 = request1 + FC1 ("Paris") + signature + FC2 ("London") text_output

(без FC)

None

Вот код для прохождения заданной последовательности.

Поворот 1, Шаг 1 (Запрос пользователя)

{
  "contents": [
    {
      "role": "user",
      "parts": [
        {
          "text": "Check the weather in Paris and London."
        }
      ]
    }
  ],
  "tools": [
    {
      "functionDeclarations": [
        {
          "name": "get_current_temperature",
          "description": "Gets the current temperature for a given location.",
          "parameters": {
            "type": "object",
            "properties": {
              "location": {
                "type": "string",
                "description": "The city name, e.g. San Francisco"
              }
            },
            "required": [
              "location"
            ]
          }
        }
      ]
    }
  ]
}

Поворот 1, Шаг 1 (Модель ответа)

{
"role": "assistant",
        "tool_calls": [
          {
            "extra_content": {
              "google": {
                "thought_signature": "<Signature A>" //Signature returned
              }
            },
            "function": {
              "arguments": "{\"location\":\"Paris\"}",
              "name": "get_current_temperature"
            },
            "id": "function-call-f3b9ecb3-d55f-4076-98c8-b13e9d1c0e01",
            "type": "function"
          },
          {
            "function": {
              "arguments": "{\"location\":\"London\"}",
              "name": "get_current_temperature"
            },
            "id": "function-call-335673ad-913e-42d1-bbf5-387c8ab80f44",
            "type": "function" // No signature on Parallel FC
          }
        ]
}

Поворот 1, шаг 2 (Ответ пользователя — Отправка выходных данных инструмента)

Необходимо сохранить <Signature_A> в первой части точно в том виде, в котором вы ее получили.

"messages": [
    {
      "role": "user",
      "content": "Check the weather in Paris and London."
    },
    {
      "role": "assistant",
        "tool_calls": [
          {
            "extra_content": {
              "google": {
                "thought_signature": "<Signature A>" //Required
              }
            },
            "function": {
              "arguments": "{\"location\":\"Paris\"}",
              "name": "get_current_temperature"
            },
            "id": "function-call-f3b9ecb3-d55f-4076-98c8-b13e9d1c0e01",
            "type": "function"
          },
          {
            "function": { //No Signature
              "arguments": "{\"location\":\"London\"}",
              "name": "get_current_temperature"
            },
            "id": "function-call-335673ad-913e-42d1-bbf5-387c8ab80f44",
            "type": "function"
          }
        ]
    },
    {
      "role":"tool",
      "name": "get_current_temperature",
      "tool_call_id": "function-call-f3b9ecb3-d55f-4076-98c8-b13e9d1c0e01",
      "content": "{\"temp\":\"15C\"}"
    },    
    {
      "role":"tool",
      "name": "get_current_temperature",
      "tool_call_id": "function-call-335673ad-913e-42d1-bbf5-387c8ab80f44",
      "content": "{\"temp\":\"12C\"}"
    }
  ]

Часто задаваемые вопросы

  1. Как перенести историю из другой модели в Gemini 3 Pro с частью вызова функции в текущем ходе и шаге? Мне нужно предоставить части вызова функции, которые не были сгенерированы API и, следовательно, не имеют связанной сигнатуры мысли?

    Хотя внедрение пользовательских блоков вызовов функций в запрос настоятельно не рекомендуется, в случаях, когда этого нельзя избежать, например, при предоставлении модели информации о вызовах функций и ответах, которые были выполнены клиентом детерминированно, или при передаче трассировки из другой модели, которая не включает сигнатуры мыслей, вы можете задать следующие фиктивные сигнатуры "context_engineering_is_the_way_to_go" или "skip_thought_signature_validator" в поле сигнатуры мыслей, чтобы пропустить проверку.

  2. Я отправляю обратно чередующиеся параллельные вызовы функций и ответы, а API возвращает 400. Почему?

    Когда API возвращает параллельные вызовы функций «FC1 + сигнатура, FC2», ожидаемый ответ пользователя — «FC1 + сигнатура, FC2, FR1, FR2». Если же они чередуются в виде «FC1 + сигнатура, FR1, FC2, FR2», API вернёт ошибку 400.

  3. При потоковой передаче и отсутствии возврата вызова функции я не могу найти сигнатуру мысли.

    При ответе модели, не содержащей FC, на потоковый запрос модель может вернуть сигнатуру мысли в части с пустым текстовым содержимым. Рекомендуется анализировать весь запрос до тех пор, пока модель не вернет finish_reason .

Поведение мыслительной сигнатуры по модельным рядам

Модели Gemini 3 Pro и Gemini 2.5 ведут себя по-разному с сигнатурами мыслей в вызовах функций:

  • Если в ответе есть вызовы функций,
    • Gemini 3 Pro всегда будет содержать сигнатуру в первой части вызова функции. Возвращать эту часть обязательно .
    • В Gemini 2.5 подпись будет в первой части (независимо от типа). Возвращать эту часть необязательно .
  • Если в ответе нет вызовов функций,
    • Если модель сгенерирует мысль, то на последней части будет размещена подпись Gemini 3 Pro.
    • У Gemini 2.5 не будет подписи ни в одной из частей.

Информацию о поведении, характерном для моделей Gemini 2.5, см. на странице «Мышление» .