Gemini با حفظ و افشای تاریخچهی زمینهی فراخوانیهای ابزار، امکان ترکیب ابزارهای داخلی مانند google_search و فراخوانی تابع (که به عنوان ابزارهای سفارشی نیز شناخته میشوند) را در یک نسل فراهم میکند. ترکیب ابزارهای داخلی و سفارشی، گردشهای کاری پیچیده و عاملمحور را امکانپذیر میکند، به عنوان مثال، مدل میتواند قبل از فراخوانی منطق کسبوکار خاص شما، خود را در دادههای وب در لحظه مستقر کند.
در اینجا مثالی آورده شده است که ترکیب ابزارهای داخلی و سفارشی را با google_search و یک تابع سفارشی getWeather فعال میکند:
پایتون
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)
جاوا اسکریپت
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) فراخوانی تابع را برای پر کردن به کاربر ارسال میکند و کاربر نتیجه را در پاسخ تابع بازمیگرداند (این بخشها برای همه فراخوانیهای تابع در رابط برنامهنویسی کاربردی Gemini استاندارد هستند و مختص ویژگی ترکیب ابزار نیستند). - (فقط ابزار اجرای کد )
executableCodeوcodeExecutionResult: هنگام استفاده از ابزار اجرای کد، به جایfunctionCallوfunctionResponse، APIexecutableCode(کدی که توسط مدلی که قرار است اجرا شود تولید میشود) و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 تعبیه شده است. متن بدون امضاهای فکری قابل بازسازی نیست؛ اگر امضاهای فکری را برای همه بخشها در هر نوبت برنگردانید، مدل خطا میدهد.- در تمام قسمتها یافت میشود.
دادههای مختص ابزار
برخی از ابزارهای داخلی، آرگومانهای دادهای قابل مشاهده توسط کاربر را که مختص نوع ابزار هستند، برمیگردانند.
| ابزار | آرگومانهای فراخوانی ابزار قابل مشاهده توسط کاربر (در صورت وجود) | پاسخ ابزار قابل مشاهده توسط کاربر (در صورت وجود) |
|---|---|---|
| جستجوی گوگل | queries | search_suggestions |
| گوگل مپ | queries | placesgoogle_maps_widget_context_token |
| متن_URL | urlsآدرسهای اینترنتی (URL) که باید مرور شوند | urls_metadataretrieved_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 شمارش میشوند. از آنجایی که این مراحل میانی ابزار اکنون قابل مشاهده و به شما بازگردانده میشوند، بخشی از تاریخچه مکالمه هستند. این فقط در مورد درخواستها صدق میکند، نه پاسخها .
ابزار جستجوی گوگل از این قاعده مستثنی است. جستجوی گوگل از قبل مدل قیمتگذاری خود را در سطح پرسوجو اعمال میکند، بنابراین توکنها دو برابر هزینه نمیشوند (به صفحه قیمتگذاری مراجعه کنید).
برای اطلاعات بیشتر صفحه توکنها را مطالعه کنید.
محدودیتها
- وقتی پرچم
include_server_side_tool_invocationsفعال باشد، پیشفرض روی حالتVALIDATED(حالتAUTOپشتیبانی نمیشود) است - ابزارهای داخلی مانند
google_searchبه اطلاعات مکان و زمان فعلی متکی هستند، بنابراین اگرsystem_instructionیاfunction_declaration.descriptionشما اطلاعات مکان و زمان متناقضی داشته باشند، ممکن است ویژگی ترکیب ابزار به خوبی کار نکند.
ابزارهای پشتیبانی شده
ابزار استاندارد گردش متن برای ابزارهای سمت سرور (توکار) اعمال میشود. اجرای کد نیز یک ابزار سمت سرور است، اما راهحل توکار خود را برای گردش متن دارد. استفاده از کامپیوتر و فراخوانی تابع، ابزارهای سمت کلاینت هستند و همچنین راهحلهای توکار برای گردش متن دارند.
| ابزار | سمت اجرا | پشتیبانی از گردش متن |
|---|---|---|
| جستجوی گوگل | سمت سرور | پشتیبانی شده |
| نقشههای گوگل | سمت سرور | پشتیبانی شده |
| متن URL | سمت سرور | پشتیبانی شده |
| جستجوی فایل | سمت سرور | پشتیبانی شده |
| اجرای کد | سمت سرور | پشتیبانی شده (داخلی، از بخشهای executableCode و codeExecutionResult استفاده میکند) |
| استفاده از کامپیوتر | سمت کلاینت | پشتیبانیشده (توکار، از بخشهای functionCall و functionResponse استفاده میکند) |
| توابع سفارشی | سمت کلاینت | پشتیبانیشده (توکار، از بخشهای functionCall و functionResponse استفاده میکند) |
قدم بعدی چیست؟
- درباره فراخوانی تابع در API مربوط به Gemini بیشتر بدانید.
- ابزارهای پشتیبانی شده را بررسی کنید: