Gemini permet de combiner des outils intégrés, tels
que google_search, et l'appel de fonction
(également appelé outils personnalisés) dans une seule génération en préservant et en exposant
l'historique du contexte des appels d'outils. Les combinaisons d'outils intégrés et personnalisés permettent de créer des workflows complexes et autonomes où, par exemple, le modèle peut s'appuyer sur des données Web en temps réel avant d'appeler votre logique métier spécifique.
Voici un exemple qui permet de combiner des outils intégrés et personnalisés avec google_search et une fonction personnalisée 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();
Go
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))
}
}
}
REST
# 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
}
}'
Fonctionnement
Les modèles Gemini 3 utilisent la circulation du contexte de l'outil pour permettre de combiner des outils intégrés et personnalisés. La circulation du contexte de l'outil permet de préserver et d'exposer le contexte des outils intégrés, et de le partager avec des outils personnalisés dans le même appel, d'un tour à l'autre.
Activer la combinaison d'outils
- Vous devez définir l'option
include_server_side_tool_invocationssurtruepour activer la circulation du contexte de l'outil. - Incluez les
function_declarations, ainsi que les outils intégrés que vous souhaitez utiliser, pour déclencher le comportement de combinaison.- Si vous n'incluez pas
function_declarations, la circulation du contexte de l'outil agira toujours sur les outils intégrés inclus, tant que l'option est définie.
- Si vous n'incluez pas
Parties renvoyées par l'API
Dans une seule réponse, l'API renvoie les parties toolCall et toolResponse pour l'appel d'outil intégré. Pour l'appel de fonction (outil personnalisé), l'API renvoie la partie d'appel functionCall, à laquelle l'utilisateur fournit la partie functionResponse au tour suivant.
toolCallettoolResponse: l'API renvoie ces parties pour préserver le contexte des outils exécutés côté serveur et le résultat de leur exécution pour le tour suivant.functionCalletfunctionResponse: l'API envoie l'appel de fonction à l'utilisateur pour qu'il le remplisse, et l'utilisateur renvoie le résultat dans la réponse de la fonction (ces parties sont standards pour tous les appels de fonction dans l'API Gemini, et ne sont pas propres à la fonctionnalité de combinaison d'outils).- (Outil d'exécution de code uniquement)
executableCodeetcodeExecutionResult: Lorsque vous utilisez l'outil d'exécution de code, au lieu defunctionCalletfunctionResponse, l'API renvoieexecutableCode(le code généré par le modèle qui est destiné à être exécuté) etcodeExecutionResult(le résultat du code exécutable).
Vous devez renvoyer toutes les parties, y compris tous les champs qu'elles contiennent, au modèle à chaque tour pour conserver le contexte et activer les combinaisons d'outils.
Champs critiques dans les parties renvoyées
Certaines parties renvoyées par l'API incluent les champs id,
tool_type et thought_signature. Ces champs sont essentiels pour conserver le contexte de l'outil (et donc pour les combinaisons d'outils). Vous devez renvoyer toutes les parties telles qu'elles sont indiquées dans la réponse dans vos requêtes suivantes.
id: identifiant unique qui mappe un appel à sa réponse.idest défini sur toutes les réponses d'appel de fonction, quelle que soit la circulation du contexte de l'outil. Vous devez fournir le mêmeiddans la réponse de la fonction que celui fourni par l'API dans l'appel de fonction. Les outils intégrés partagent automatiquement l'identre l'appel d'outil et la réponse de l'outil.- Se trouve dans toutes les parties liées à l'outil :
toolCall,toolResponse,functionCall,functionResponse,executableCode,codeExecutionResult
- Se trouve dans toutes les parties liées à l'outil :
tool_type: identifie l'outil spécifique utilisé ; le nom littéral de l'outil intégré ou (par exemple,URL_CONTEXT) ou de la fonction (par exemple,getWeather).- Se trouve dans les parties
toolCallettoolResponse.
- Se trouve dans les parties
thought_signature: contexte chiffré réel intégré dans chaque partie renvoyée par l'API. Le contexte ne peut pas être reconstruit sans les signatures de pensée. Si vous ne renvoyez pas les signatures de pensée pour toutes les parties à chaque tour, le modèle générera une erreur.- Se trouve dans toutes les parties.
Données spécifiques à l'outil
Certains outils intégrés renvoient des arguments de données visibles par l'utilisateur, spécifiques au type d'outil.
| Outil | Arguments d'appel d'outil visibles par l'utilisateur (le cas échéant) | Réponse de l'outil visible par l'utilisateur (le cas échéant) |
|---|---|---|
| GOOGLE_SEARCH | queries |
search_suggestions |
| GOOGLE_MAPS | queries |
placesgoogle_maps_widget_context_token |
| URL_CONTEXT | urlsURL à parcourir |
urls_metadataretrieved_url : URL parcouruesurl_retrieval_status : état de la navigation |
| FILE_SEARCH | Aucun | Aucun |
Exemple de structure de requête de combinaison d'outils
La structure de requête suivante montre la structure de requête de l'invite : "Quelle est la ville la plus au nord des États-Unis ? Quel temps fait-il aujourd'hui ?". Elle combine trois outils : les outils Gemini intégrés google_search et code_execution, et une fonction personnalisée 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
}
}
Jetons et tarifs
Notez que les parties toolCall et toolResponse des requêtes sont comptabilisées dans prompt_token_count. Étant donné que ces étapes intermédiaires de l'outil sont désormais visibles et vous sont renvoyées, elles font partie de l'historique des conversations. Cela ne s'applique qu'aux
cas de requêtes, et non aux réponses.
L'outil Recherche Google fait exception à cette règle. La recherche Google applique déjà son propre modèle de tarification au niveau de la requête. Les jetons ne sont donc pas facturés deux fois (consultez la page Tarifs).
Pour en savoir plus, consultez la page Jetons.
Limites
- Par défaut, le mode
VALIDATEDest activé (le modeAUTOn'est pas compatible) lorsque l'optioninclude_server_side_tool_invocationsest activée. - Les outils intégrés tels que
google_searchs'appuient sur des informations de localisation et d'heure actuelles. Par conséquent, si votresystem_instructionoufunction_declaration.descriptioncontient des informations de localisation et d'heure conflictuelles, la fonctionnalité de combinaison d'outils risque de ne pas fonctionner correctement.
Outils compatibles
La circulation standard du contexte de l'outil s'applique aux outils côté serveur (intégrés). L'exécution de code est également un outil côté serveur, mais elle dispose de sa propre solution intégrée pour la circulation du contexte. L'utilisation de l'ordinateur et l'appel de fonction sont des outils côté client, et disposent également de solutions intégrées pour la circulation du contexte.
| Outil | Côté exécution | Compatibilité avec la circulation du contexte |
|---|---|---|
| La recherche Google | Côté serveur | Compatible |
| Google Maps | Côté serveur | Compatible |
| Contexte de l'URL | Côté serveur | Compatible |
| Recherche de fichiers | Côté serveur | Compatible |
| Exécution de code | Côté serveur | Compatible (intégré, utilise les parties executableCode et codeExecutionResult) |
| Utilisation de l'ordinateur | Côté client | Compatible (intégré, utilise les parties functionCall et functionResponse) |
| Fonctions personnalisées | Côté client | Compatible (intégré, utilise les parties functionCall et functionResponse) |
Étape suivante
- En savoir plus sur l'appel de fonction dans l'API Gemini.
- Découvrez les outils compatibles :