Объедините встроенные инструменты и вызов функций.

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

Вот пример, позволяющий комбинировать встроенные и пользовательские инструменты с помощью google_search и пользовательской функции getWeather :

Python

from google import genai
from google.genai import types

client = genai.Client()

getWeather = {
    "name": "getWeather",
    "description": "Gets the weather for a requested city.",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "The city and state, e.g. Utqiaġvik, Alaska",
            },
        },
        "required": ["city"],
    },
}

# Turn 1: Initial request with Google Search (built-in) and getWeather (custom) tools enabled
response = client.models.generate_content(
    model="gemini-3-flash-preview",
    contents="What is the northernmost city in the United States? What's the weather like there today?",
    config=types.GenerateContentConfig(
      tools=[
        types.Tool(
          google_search=types.ToolGoogleSearch(),  # Built-in tool
          function_declarations=[getWeather]       # Custom tool
        ),
      ],
      include_server_side_tool_invocations=True
    ),
)

for part in response.candidates[0].content.parts:
    if part.tool_call:
        print(f"Tool call: {part.tool_call.tool_type} (ID: {part.tool_call.id})")
    if part.tool_response:
        print(f"Tool response: {part.tool_response.tool_type} (ID: {part.tool_response.id})")
    if part.function_call:
        print(f"Function call: {part.function_call.name} (ID: {part.function_call.id})")

# Turn 2: Manually build history to circulate both tool and function context
history = [
    types.Content(
        role="user",
        parts=[types.Part(text="What is the northernmost city in the United States? What's the weather like there today?")]
    ),
    # Response from Turn 1 includes tool_call, tool_response, and thought_signatures
    response.candidates[0].content,
    # Return the function_response
    types.Content(
        role="user",
        parts=[types.Part(
            function_response=types.FunctionResponse(
                name="getWeather",
                response={"response": "Very cold. 22 degrees Fahrenheit."},
                id=response.candidates[0].content.parts[2].function_call.id # Match the ID from the function_call
            )
        )]
    )
]

response_2 = client.models.generate_content(
    model="gemini-3-flash-preview",
    contents=history,
    config=types.GenerateContentConfig(
      tools=[
        types.Tool(
          google_search=types.ToolGoogleSearch(),
          function_declarations=[getWeather]
        ),
      ],
      # This flag needs to be enabled for built-in tool context circulation and tool combination
      include_server_side_tool_invocations=True
    ),
)

for part in response_2.candidates[0].content.parts:
    if part.text:
        print(part.text)

JavaScript

import { GoogleGenAI } from '@google/genai';

const client = new GoogleGenAI({});

const getWeather = {
    name: "getWeather",
    description: "Get the weather in a given location",
    parameters: {
        type: "OBJECT",
        properties: {
            location: {
                type: "STRING",
                description: "The city and state, e.g. San Francisco, CA"
            }
        },
        required: ["location"]
    }
};

async function run() {
    const model = client.getGenerativeModel({
        model: "gemini-3-flash-preview",
    });

    const tools = [
      { googleSearch: {} },
      { functionDeclarations: [getWeather] }
    ];
    // This flag needs to be enabled for built-in tool context circulation and tool combination
    const toolConfig = { includeServerSideToolInvocations: true };

    // Turn 1: Initial request with Google Search (built-in) and getWeather (custom) tools enabled
    const result1 = await model.generateContent({
        contents: [{role: "user", parts: [{text: "What is the northernmost city in the United States? What's the weather like there today?"}]}],
        tools: tools,
        toolConfig: toolConfig,
    });

    const response1 = result1.response;

    for (const part of response1.candidates[0].content.parts) {
        if (part.toolCall) {
            console.log(`Tool call: ${part.toolCall.toolType} (ID: ${part.toolCall.id})`);
        }
        if (part.toolResponse) {
            console.log(`Tool response: ${part.toolResponse.toolType} (ID: ${part.toolResponse.id})`);
        }
        if (part.functionCall) {
            console.log(`Function call: ${part.functionCall.name} (ID: ${part.functionCall.id})`);
        }
    }

    const functionCallId = response1.candidates[0].content.parts.find(p => p.functionCall)?.functionCall?.id;

    // Turn 2: Manually build history to circulate both tool and function context
    const history = [
        {
            role: "user",
            parts:[{text: "What is the northernmost city in the United States? What's the weather like there today?"}]
        },
        // Response from Turn 1 includes tool_call, tool_response, and thought_signatures
        response1.candidates[0].content,
        // Return the function_response
        {
            role: "user",
            parts: [{
                functionResponse: {
                    name: "getWeather",
                    response: {response: "Very cold. 22 degrees Fahrenheit."},
                    id: functionCallId // Match the ID from the function_call
                }
            }]
        }
    ];

    const result2 = await model.generateContent({
        contents: history,
        tools: tools,
        toolConfig: toolConfig,
    });

    for (const part of result2.response.candidates[0].content.parts) {
        if (part.text) {
            console.log(part.text);
        }
    }
}

run();

Идти

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/google/generative-ai-go/genai"
    "google.golang.org/api/option"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY")))
    if err != nil {
        log.Exit(err)
    }
    defer client.Close()

    getWeather := &genai.FunctionDeclaration{
        Name:        "getWeather",
        Description: "Get the weather in a given location",
        Parameters: &genai.Schema{
            Type: genai.Object,
            Properties: map[string]*genai.Schema{
                "location": {
                    Type:        genai.String,
                    Description: "The city and state, e.g. San Francisco, CA",
                },
            },
            Required: []string{"location"},
        },
    }

    model := client.GenerativeModel("gemini-3-flash-preview")
    model.Tools = []*genai.Tool{
        {GoogleSearch: &genai.GoogleSearch{}}, // Built-in tool
        {FunctionDeclarations: []*genai.FunctionDeclaration{getWeather}}, // Custom tool
    }
    ist := true
    model.ToolConfig = &genai.ToolConfig{
        IncludeServerSideToolInvocations: &ist, // This flag needs to be enabled for built-in tool context circulation and tool combination
    }

    chat := model.StartChat()

    // Turn 1: Initial request with Google Search (built-in) and getWeather (custom) tools enabled
    prompt := genai.Text("What is the northernmost city in the United States? What's the weather like there today?")
    resp1, err := chat.SendMessage(ctx, prompt)
    if err != nil {
        log.Exitf("SendMessage failed: %v", err)
    }

    if resp1 == nil || len(resp1.Candidates) == 0 || resp1.Candidates[0].Content == nil {
        log.Exit("empty response from model")
    }

    var functionCallID string
    for _, part := range resp1.Candidates[0].Content.Parts {
        switch p := part.(type) {
        case genai.FunctionCall:
            fmt.Printf("Function call: %s (ID: %s)\n", p.Name, p.ID)
            if p.Name == "getWeather" {
                functionCallID = p.ID
            }
        case genai.ToolCallPart:
            fmt.Printf("Tool call: %s (ID: %s)\n", p.ToolType, p.ID)
        case genai.ToolResponsePart:
            fmt.Printf("Tool response: %s (ID: %s)\n", p.ToolType, p.ID)
        }
    }

    if functionCallID == "" {
        log.Exit("no getWeather function call in response")
    }

    // Turn 2: Provide function result back to model.
    // Chat history automatically includes tool_call, tool_response, and thought_signatures from Turn 1.
    fr := genai.FunctionResponse{
        Name: "getWeather",
        ID:   functionCallID,
        Response: map[string]any{
            "response": "Very cold. 22 degrees Fahrenheit.",
        },
    }

    resp2, err := chat.SendMessage(ctx, fr)
    if err != nil {
        log.Exitf("SendMessage for turn 2 failed: %v", err)
    }

    if resp2 == nil || len(resp2.Candidates) == 0 || resp2.Candidates[0].Content == nil {
        log.Exit("empty response from model in turn 2")
    }

    for _, part := range resp2.Candidates[0].Content.Parts {
        if txt, ok := part.(genai.Text); ok {
            fmt.Println(string(txt))
        }
    }
}

ОТДЫХ

# Turn 1: Initial request with Google Search (built-in) and getWeather (custom) tools enabled
curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-3-flash-preview:generateContent" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
  "contents": [{
    "role": "user",
    "parts": [{
      "text": "What is the northernmost city in the United States? What'\''s the weather like there today?"
    }]
  }],
  "tools": [{
    "googleSearch": {}
  }, {
    "functionDeclarations": [{
      "name": "getWeather",
      "description": "Get the weather in a given location",
      "parameters": {
          "type": "OBJECT",
          "properties": {
              "location": {
                  "type": "STRING",
                  "description": "The city and state, e.g. San Francisco, CA"
              }
          },
          "required": ["location"]
      }
    }]
  }],
  "toolConfig": {
    "includeServerSideToolInvocations": true
  }
}'

# Turn 2: Manually build history to circulate both tool and function context
# The following request assumes you have captured candidates[0].content from Turn 1 response,
# and extracted function_call.id for getWeather.
# Replace FUNCTION_CALL_ID and insert candidate content from turn 1.
curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-3-flash-preview:generateContent" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
  "contents": [
    {
      "role": "user",
      "parts": [{"text": "What is the northernmost city in the United States? What'\''s the weather like there today?"}]
    },
    YOUR_CANDIDATE_CONTENT_FROM_TURN_1_RESPONSE,
    {
      "role": "user",
      "parts": [{
        "functionResponse": {
          "name": "getWeather",
          "id": "FUNCTION_CALL_ID",
          "response": {"response": "Very cold. 22 degrees Fahrenheit."}
        }
      }]
    }
  ],
  "tools": [{
    "googleSearch": {}
  }, {
    "functionDeclarations": [{
      "name": "getWeather",
      "description": "Get the weather in a given location",
      "parameters": {
          "type": "OBJECT",
          "properties": {
              "location": {
                  "type": "STRING",
                  "description": "The city and state, e.g. San Francisco, CA"
              }
          },
          "required": ["location"]
      }
    }]
  }],
  "toolConfig": {
    "includeServerSideToolInvocations": true
  }
}'

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

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

Включить комбинацию инструментов

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

API возвращает части

В одном ответе API возвращает части toolCall и toolResponse для вызова встроенного инструмента. Для вызова функции (пользовательского инструмента) API возвращает часть functionCall , а часть functionResponse пользователь предоставляет на следующем этапе.

  • toolCall и toolResponse : API возвращает эти части, чтобы сохранить контекст выполнения инструментов на стороне сервера и результат их выполнения для следующего хода.
  • functionCall и functionResponse : API отправляет пользователю вызов функции для заполнения, а пользователь отправляет результат обратно в ответе функции (эти части являются стандартными для всех вызовов функций в API Gemini, а не уникальными для функции комбинирования инструментов).
  • (Только для инструмента выполнения кода ) executableCode и codeExecutionResult : При использовании инструмента выполнения кода вместо functionCall и functionResponse API возвращает executableCode (код, сгенерированный моделью, который должен быть выполнен) и codeExecutionResult (результат выполнения кода).

Для сохранения контекста и обеспечения возможности комбинирования инструментов необходимо на каждом этапе возвращать все части модели, включая все содержащиеся в них поля .

Критические поля в возвращенных деталях

API возвращает некоторые части кода, включая поля id , tool_type и thought_signature . Эти поля имеют решающее значение для поддержания контекста инструмента (и, следовательно, для комбинаций инструментов); в последующих запросах необходимо возвращать все части кода в том виде, в котором они были предоставлены в ответе .

  • id : Уникальный идентификатор, сопоставляющий вызов с ответом. id устанавливается для всех ответов на вызовы функций , независимо от контекста инструмента. Необходимо указать тот же id в ответе на вызов функции, который API предоставляет в вызове функции. Встроенные инструменты автоматически используют один и тот id как при вызове, так и при ответе на вызов.
    • Встречается во всех компонентах, связанных с инструментом: toolCall , toolResponse , functionCall , functionResponse , executableCode , codeExecutionResult
  • tool_type : Указывает конкретный используемый инструмент; это может быть имя встроенного инструмента (например, URL_CONTEXT ) или функции (например, getWeather ).
    • Найдено в частях toolCall и toolResponse .
  • thought_signature : Фактический зашифрованный контекст, встроенный в каждую часть, возвращаемую API . Контекст невозможно восстановить без сигнатур мыслей; если вы не возвращаете сигнатуры мыслей для всех частей на каждом шагу, модель выдаст ошибку.
    • Встречается во всех частях.

Данные, специфичные для инструмента

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

Инструмент Аргументы вызова инструмента, видимые пользователю (если таковые имеются) Ответ инструмента, видимый пользователю (если таковой имеется)
GOOGLE_SEARCH queries search_suggestions
GOOGLE_MAPS queries places
google_maps_widget_context_token
URL_CONTEXT urls
URL-адреса для просмотра
urls_metadata
retrieved_url : просмотренные URL-адреса
url_retrieval_status : Статус просмотра
ПОИСК_ФАЙЛА Никто Никто

Пример структуры запроса на комбинацию инструментов

Следующая структура запроса демонстрирует структуру запроса: «Какой самый северный город в Соединенных Штатах? Какая там сегодня погода?». Она объединяет три инструмента: встроенные инструменты Gemini google_search и code_execution , а также пользовательскую функцию get_weather .

{
  "model": "models/gemini-3-flash-preview",
  "contents": [{
    "parts": [{
      "text": "What is the northernmost city in the United States? What's the weather like there today?"
    }],
    "role": "user"
  }, {
    "parts": [{
      "thoughtSignature": "...",
      "toolCall": {
        "toolType": "GOOGLE_SEARCH_WEB",
        "args": {
          "queries": ["northernmost city in the United States"]
        },
        "id": "a7b3k9p2"
      }
    }, {
      "thoughtSignature": "...",
      "toolResponse": {
        "toolType": "GOOGLE_SEARCH_WEB",
        "response": {
          "search_suggestions": "..."
        },
        "id": "a7b3k9p2"
      }
    }, {
      "functionCall": {
        "name": "getWeather",
        "args": {
          "city": "Utqiaġvik, Alaska"
        },
        "id": "m4q8z1v6"
      },
      "thoughtSignature": "..."
    }],
    "role": "model"
  }, {
    "parts": [{
      "functionResponse": {
        "name": "getWeather",
        "response": {
          "response": "Very cold. 22 degrees Fahrenheit."
        },
        "id": "m4q8z1v6"
      }
    }],
    "role": "user"
  }],
  "tools": [{
    "functionDeclarations": [{
      "name": "getWeather"
    }]
  }, {
    "googleSearch": {
    }
  }, {
    "codeExecution": {
    }
  }],
  "toolConfig": {
    "includeServerSideToolInvocations": true
  }
}

Токены и цены

Обратите внимание, что части toolCall и toolResponse в запросах учитываются в prompt_token_count . Поскольку эти промежуточные шаги инструмента теперь видны и возвращаются вам, они являются частью истории диалога. Это относится только к запросам , а не к ответам .

Инструмент поиска Google является исключением из этого правила. Google Search уже применяет собственную модель ценообразования на уровне запроса, поэтому токены не облагаются двойной оплатой (см. страницу «Цены» ).

Для получения более подробной информации ознакомьтесь со страницей «Токены» .

Ограничения

  • При включении флага include_server_side_tool_invocations по умолчанию используется режим VALIDATED (режим AUTO не поддерживается).
  • Встроенные инструменты, такие как google_search полагаются на информацию о местоположении и текущем времени, поэтому, если в вашем system_instruction или function_declaration.description содержится противоречивая информация о местоположении и времени, функция комбинирования инструментов может работать некорректно.

Поддерживаемые инструменты

Стандартная циркуляция контекста применяется к встроенным инструментам на стороне сервера. Выполнение кода также является инструментом на стороне сервера, но имеет собственное встроенное решение для циркуляции контекста. Использование компьютера и вызов функций являются инструментами на стороне клиента и также имеют встроенные решения для циркуляции контекста.

Инструмент Сторона исполнения Поддержка контекстного распространения
Поиск Google на стороне сервера Поддерживается
Google Карты на стороне сервера Поддерживается
Контекст URL на стороне сервера Поддерживается
Поиск файлов на стороне сервера Поддерживается
Выполнение кода на стороне сервера Поддерживается (встроенная функция, использует части executableCode и codeExecutionResult )
Использование компьютера На стороне клиента Поддерживается (встроено, использует части functionCall и functionResponse )
Пользовательские функции На стороне клиента Поддерживается (встроено, использует части functionCall и functionResponse )

Что дальше?