الجمع بين الأدوات المضمّنة واستدعاء الدوال

يتيح 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();

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
  }
}'

آلية العمل

تستخدم نماذج Gemini 3 ميزة "تداول سياق الأدوات" لتفعيل مجموعات الأدوات المضمّنة والمخصّصة. تتيح ميزة "تداول سياق الأدوات" الحفاظ على سياق الأدوات المضمّنة وعرضه ومشاركته مع الأدوات المخصّصة في المكالمة نفسها من وقت لآخر.

تفعيل دمج الأدوات

  • يجب ضبط العلامة include_server_side_tool_invocations على true لتفعيل تداول سياق الأداة.
  • أدرِج function_declarations مع الأدوات المضمّنة التي تريد استخدامها لتفعيل السلوك المدمج.
    • في حال عدم تضمين function_declarations، سيظلّ تداول سياق الأداة يعمل على الأدوات المضمّنة، طالما تم ضبط العلامة.

أجزاء تعرضها واجهة برمجة التطبيقات

في ردّ واحد، تعرض واجهة برمجة التطبيقات الجزءين toolCall وtoolResponse لطلب استخدام الأداة المضمّنة. بالنسبة إلى طلب البيانات من الدالة (الأداة المخصّصة)، تعرض واجهة برمجة التطبيقات جزء طلب البيانات functionCall، ويقدّم المستخدم جزء functionResponse في الجولة التالية.

  • toolCall وtoolResponse: تعرض واجهة برمجة التطبيقات هذين الجزأين للحفاظ على سياق الأدوات التي يتم تشغيلها من جهة الخادم ونتيجة تنفيذها في الجولة التالية.
  • functionCall وfunctionResponse: ترسل واجهة برمجة التطبيقات طلب استدعاء الدالة إلى المستخدم ليملأه، ويرسل المستخدم النتيجة مرة أخرى في رد الدالة (هذه الأجزاء هي معيارية لجميع عمليات استدعاء الدوال في Gemini API، وليست فريدة لميزة الجمع بين الأدوات).
  • (أداة تنفيذ الرموز البرمجية فقط) executableCode وcodeExecutionResult: عند استخدام أداة "تنفيذ الرموز البرمجية"، بدلاً من functionCall وfunctionResponse، تعرض واجهة برمجة التطبيقات executableCode (الرمز البرمجي الذي أنشأه النموذج والمخصّص للتنفيذ) وcodeExecutionResult (نتيجة الرمز البرمجي القابل للتنفيذ).

يجب إعادة جميع الأجزاء، بما في ذلك جميع الحقول التي تحتوي عليها، إلى النموذج في كل دورة للحفاظ على السياق وتفعيل مجموعات الأدوات.

الحقول المهمة في الأجزاء التي تم إرجاعها

ستتضمّن بعض الأجزاء التي تعرضها واجهة برمجة التطبيقات الحقول id وtool_type وthought_signature. هذه الحقول ضرورية للحفاظ على سياق الأداة (وبالتالي ضرورية لدمج الأدوات)، لذا عليك تضمين جميع الأجزاء كما وردت في الردّ في طلباتك اللاحقة.

  • id: معرّف فريد يربط بين طلب واستجابته. يتم id ضبطه على جميع الردود على طلبات الدوال، بغض النظر عن تداول سياق الأداة. يجب تقديم id نفسه في ردّ الدالة الذي توفّره واجهة برمجة التطبيقات في استدعاء الدالة. تشارك الأدوات المضمّنة تلقائيًا id بين طلب الأداة واستجابة الأداة.
    • يظهر في جميع الأجزاء ذات الصلة بالأدوات: toolCall وtoolResponse وfunctionCall وfunctionResponse وexecutableCode وcodeExecutionResult
  • tool_type: تحدّد الأداة المحدّدة المستخدَمة، سواء كانت أداة مضمّنة حرفية (مثل URL_CONTEXT) أو اسم دالة (مثل getWeather).
    • تم العثور عليه في الأجزاء toolCall وtoolResponse.
  • thought_signature: السياق الفعلي المشفّر المضمّن في كل جزء تعرضه واجهة برمجة التطبيقات. لا يمكن إعادة إنشاء السياق بدون توقيعات الأفكار، وإذا لم تعرض توقيعات الأفكار لجميع الأجزاء في كل دورة، سيحدث خطأ في النموذج.
    • تم العثور عليه في جميع الأجزاء.

البيانات الخاصة بالأداة

تعرض بعض الأدوات المضمّنة وسيطات بيانات مرئية للمستخدم خاصة بنوع الأداة.

الأداة وسيطات استدعاء الأداة المرئية للمستخدم (إن وُجدت) ردّ الأداة المرئي للمستخدم (إن وُجد)
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: حالة التصفّح
FILE_SEARCH بدون بدون

مثال على بنية طلب الجمع بين الأدوات

تعرض بنية الطلب التالية بنية طلب السؤال: "ما هي أقصى مدينة تقع في شمال الولايات المتحدة؟ كيف سيكون الطقس هناك اليوم؟". تجمع هذه الإضافة بين ثلاث أدوات: أدوات 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 نموذج التسعير الخاص به على مستوى طلب البحث، لذا لن يتم تحصيل رسوم مضاعفة مقابل الرموز المميزة (راجِع صفحة الأسعار).

يمكنك الاطّلاع على صفحة الرموز المميزة للحصول على مزيد من المعلومات.

القيود

  • الوضع التلقائي هو الوضع VALIDATED (الوضع AUTO غير متاح) عند تفعيل العلامة include_server_side_tool_invocations
  • تعتمد الأدوات المضمّنة، مثل google_search، على معلومات الموقع الجغرافي والوقت الحالي، لذا إذا كان system_instruction أو function_declaration.description يتضمّن معلومات متضاربة حول الموقع الجغرافي والوقت، قد لا تعمل ميزة دمج الأدوات بشكل جيد.

الأدوات المتوافقة

يتم تطبيق تداول سياق الأداة العادي على الأدوات من جهة الخادم (المضمّنة). "تنفيذ الرمز" هي أيضًا أداة من جهة الخادم، ولكنّها تتضمّن حلاً مدمجًا خاصًا بها لتداول السياق. إنّ استخدام الكمبيوتر واستدعاء الدوال هما أداتان من جهة العميل، وتتضمّنان أيضًا حلولاً مدمجة لتداول السياق.

الأداة جهة التنفيذ إتاحة تداول السياق
بحث Google من جهة الخادم متاح
خرائط Google من جهة الخادم متاح
سياق عنوان URL من جهة الخادم متاح
البحث عن الملفات من جهة الخادم متاح
تنفيذ الرمز من جهة الخادم متوافق (مضمّن، يستخدم الأجزاء executableCode وcodeExecutionResult)
استخدام الكمبيوتر من جهة العميل متوافق (مضمّن، يستخدم الأجزاء functionCall وfunctionResponse)
الدوال المخصّصة من جهة العميل متوافق (مضمّن، يستخدم الأجزاء functionCall وfunctionResponse)

الخطوات التالية