รวมเครื่องมือในตัวและการเรียกฟังก์ชัน

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 การหมุนเวียนบริบทของเครื่องมือจะยังคงทำงานกับเครื่องมือในตัวที่รวมไว้ ตราบใดที่ตั้งค่าแฟล็กไว้

API จะแสดงผลบางส่วน

ในการตอบกลับครั้งเดียว API จะแสดงผลส่วน toolCall และ toolResponse สำหรับการเรียกเครื่องมือในตัว สำหรับการเรียกฟังก์ชัน (เครื่องมือที่กำหนดเอง) API จะแสดงผลส่วนการเรียก functionCall ซึ่งผู้ใช้จะระบุส่วน functionResponse ในเทิร์นถัดไป

  • toolCall และ toolResponse: API จะแสดงผลส่วนเหล่านี้เพื่อเก็บรักษาบริบทของเครื่องมือที่ทำงานฝั่งเซิร์ฟเวอร์และผลลัพธ์ของการดำเนินการสำหรับเทิร์นถัดไป
  • functionCall และ functionResponse: API จะส่งการเรียกใช้ฟังก์ชันให้ผู้ใช้กรอกข้อมูล และผู้ใช้จะส่งผลลัพธ์กลับมาในการตอบกลับฟังก์ชัน (ส่วนเหล่านี้เป็นส่วนมาตรฐานของการเรียกฟังก์ชันทั้งหมดใน Gemini API ไม่ได้มีเฉพาะฟีเจอร์การรวมเครื่องมือ)
  • (เครื่องมือการรันโค้ดเท่านั้น) executableCode และ codeExecutionResult: เมื่อใช้เครื่องมือการรันโค้ด API จะแสดงผล executableCode (โค้ดที่โมเดลสร้างขึ้นเพื่อรัน) และ codeExecutionResult (ผลลัพธ์ของโค้ดที่รันได้) แทน functionCall และ functionResponse

คุณต้องส่งคืนทุกส่วน รวมถึงทุกช่องที่ส่วนเหล่านั้น มี กลับไปยังโมเดลในแต่ละเทิร์นเพื่อรักษาบริบทและเปิดใช้การรวมเครื่องมือ

ช่องที่สำคัญในส่วนที่แสดงผล

บางส่วนที่ 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 แสดงผล คุณจะสร้างบริบทขึ้นใหม่ไม่ได้หากไม่มีลายเซ็นความคิด หากไม่ส่งคืนลายเซ็นความคิดสำหรับทุกส่วนในทุกเทิร์น โมเดลจะแสดงข้อผิดพลาด
    • พบใน ทุก ส่วน

ข้อมูลเฉพาะของเครื่องมือ

เครื่องมือในตัวบางรายการจะแสดงผลอาร์กิวเมนต์ข้อมูลที่ผู้ใช้มองเห็นได้ซึ่งเฉพาะเจาะจงกับประเภทเครื่องมือ

เครื่องมือ อาร์กิวเมนต์การเรียกเครื่องมือที่ผู้ใช้มองเห็นได้ (หากมี) การตอบกลับเครื่องมือที่ผู้ใช้มองเห็นได้ (หากมี)
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 ไม่มี ไม่มี

โครงสร้างคำขอการรวมเครื่องมือตัวอย่าง

โครงสร้างคำขอต่อไปนี้แสดงโครงสร้างคำขอของข้อความแจ้ง "เมืองที่อยู่เหนือสุดในสหรัฐอเมริกาคือเมืองใด สภาพอากาศที่นั่นวันนี้เป็นอย่างไร" โดยจะรวมเครื่องมือ 3 รายการ ได้แก่ เครื่องมือ 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 Search เป็นข้อยกเว้นของกฎนี้ Google Search ใช้โมเดลการกำหนดราคาของตัวเองอยู่แล้วในระดับคําค้นหา ดังนั้นระบบจึงไม่เรียกเก็บเงินโทเค็นซ้ำ (ดูหน้าการกำหนดราคา)

อ่านข้อมูลเพิ่มเติมได้ที่หน้าโทเค็น

ข้อจำกัด

  • ค่าเริ่มต้นเป็นโหมด VALIDATED (AUTO ไม่รองรับ) เมื่อเปิดใช้แฟล็ก include_server_side_tool_invocations
  • เครื่องมือในตัว เช่น google_search อาศัยข้อมูลตำแหน่งและเวลาปัจจุบัน ดังนั้นหาก system_instruction หรือ function_declaration.description มีข้อมูลตำแหน่งและเวลาที่ขัดแย้งกัน ฟีเจอร์การรวมเครื่องมืออาจทำงานได้ไม่ดี

เครื่องมือที่รองรับ

การหมุนเวียนบริบทของเครื่องมือมาตรฐานใช้กับเครื่องมือฝั่งเซิร์ฟเวอร์ (ในตัว) การรันโค้ดเป็นเครื่องมือฝั่งเซิร์ฟเวอร์เช่นกัน แต่มีโซลูชันในตัวสำหรับการหมุนเวียนบริบท การใช้คอมพิวเตอร์และการเรียกฟังก์ชันเป็นเครื่องมือฝั่งไคลเอ็นต์ และมีโซลูชันในตัวสำหรับการหมุนเวียนบริบทเช่นกัน

เครื่องมือ ฝั่งการดำเนินการ การรองรับการหมุนเวียนบริบท
Google Search ฝั่งเซิร์ฟเวอร์ รองรับ
Google Maps ฝั่งเซิร์ฟเวอร์ รองรับ
บริบท URL ฝั่งเซิร์ฟเวอร์ รองรับ
การค้นหาไฟล์ ฝั่งเซิร์ฟเวอร์ รองรับ
การรันโค้ด ฝั่งเซิร์ฟเวอร์ รองรับ (ในตัว ใช้ส่วน executableCode และ codeExecutionResult)
การใช้คอมพิวเตอร์ ฝั่งไคลเอ็นต์ รองรับ (ในตัว ใช้ส่วน functionCall และ functionResponse)
ฟังก์ชันที่กำหนดเอง ฝั่งไคลเอ็นต์ รองรับ (ในตัว ใช้ส่วน functionCall และ functionResponse)

ขั้นตอนถัดไป