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 même génération en conservant et en exposant l'historique du contexte des appels d'outils. Les combinaisons d'outils intégrées et personnalisées permettent de créer des workflows complexes et agentiques où, par exemple, le modèle peut s'ancrer dans des données Web en temps réel avant d'appeler votre logique métier spécifique.
Voici un exemple qui permet des combinaisons d'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 des outils pour permettre les combinaisons d'outils intégrés et personnalisés. La circulation du contexte des outils permet de préserver et d'exposer le contexte des outils intégrés, et de le partager avec les outils personnalisés lors du même appel, tour après tour.
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
function_declarations, ainsi que les outils intégrés que vous souhaitez utiliser, pour déclencher le comportement combiné.- Si vous n'incluez pas
function_declarations, la circulation du contexte d'outil agira toujours sur les outils intégrés inclus, à condition que l'indicateur soit défini.
- Si vous n'incluez pas
L'API renvoie des pièces
Dans une même 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 prochain tour.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 standard 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 censé ê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 maintenir le contexte et permettre les combinaisons d'outils.
Champs critiques dans les pièces renvoyées
Certaines parties renvoyées par l'API incluent les champs id, tool_type et thought_signature. Ces champs sont essentiels pour maintenir 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 ultérieures.
id: identifiant unique qui mappe un appel à sa réponse.idest défini sur toutes les réponses aux appels 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 la fonction. Les outils intégrés partagent automatiquement leidentre l'appel d'outil et la réponse de l'outil.- Présent dans toutes les parties liées aux outils :
toolCall,toolResponse,functionCall,functionResponse,executableCode,codeExecutionResult
- Présent dans toutes les parties liées aux outils :
tool_type: identifie l'outil spécifique utilisé, le nom de l'outil littéral intégré (par exemple,URL_CONTEXT) ou le nom de la fonction (par exemple,getWeather).- Trouvé dans les parties
toolCallettoolResponse.
- Trouvé dans les parties
thought_signature: contexte chiffré réel intégré à chaque partie renvoyée par l'API. Le contexte ne peut pas être reconstitué 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.- Trouvé 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 l'exploration |
| FILE_SEARCH | Aucun | Aucun |
Exemple de structure de demande de combinaison d'outils
La structure de requête suivante montre la structure de requête de la requête : "Quelle est la ville la plus au nord des États-Unis ? Quel temps fait-il là-bas aujourd'hui ?" Il combine trois outils : les outils Gemini intégrés google_search
et code_execution, ainsi qu'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 requêtes, et non aux réponses.
L'outil de recherche Google fait exception à cette règle. La recherche Google applique déjà son propre modèle de tarification au niveau des requêtes. 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
VALIDATED(le modeAUTOn'est pas pris en charge) est activé lorsque l'indicateurinclude_server_side_tool_invocationsest activé. - Les outils intégrés tels que
google_searchs'appuient sur des informations de localisation et d'heure actuelle. Par conséquent, si votresystem_instructionou votrefunction_declaration.descriptioncomporte des informations de localisation et d'heure incohérentes, la fonctionnalité de combinaison d'outils risque de ne pas fonctionner correctement.
Outils compatibles
La circulation standard du contexte d'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 fonctions sont des outils côté client qui 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 | Pris en charge (intégré, utilise les pièces executableCode et codeExecutionResult) |
| Utilisation de l'ordinateur | Côté client | Pris en charge (intégré, utilise les pièces functionCall et functionResponse) |
| Fonctions personnalisées | Côté client | Pris en charge (intégré, utilise les pièces functionCall et functionResponse) |
Étape suivante
- En savoir plus sur l'appel de fonction dans l'API Gemini
- Découvrez les outils compatibles :