ابزارهای داخلی و فراخوانی توابع را ترکیب کنید

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 ، 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 تعبیه شده است. متن بدون امضاهای فکری قابل بازسازی نیست؛ اگر امضاهای فکری را برای همه بخش‌ها در هر نوبت برنگردانید، مدل خطا می‌دهد.
    • در تمام قسمت‌ها یافت می‌شود.

داده‌های مختص ابزار

برخی از ابزارهای داخلی، آرگومان‌های داده‌ای قابل مشاهده توسط کاربر را که مختص نوع ابزار هستند، برمی‌گردانند.

ابزار آرگومان‌های فراخوانی ابزار قابل مشاهده توسط کاربر (در صورت وجود) پاسخ ابزار قابل مشاهده توسط کاربر (در صورت وجود)
جستجوی گوگل queries search_suggestions
گوگل مپ queries places
google_maps_widget_context_token
متن_URL urls
آدرس‌های اینترنتی (URL) که باید مرور شوند
urls_metadata
retrieved_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 استفاده می‌کند)

قدم بعدی چیست؟