การเรียกใช้ฟังก์ชันด้วย Gemma 4

ดูที่ ai.google.dev เรียกใช้ใน Google Colab เรียกใช้ใน Kaggle เปิดใน Vertex AI ดูแหล่งข้อมูลใน GitHub

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

คู่มือนี้แสดงกระบวนการใช้ Gemma 4 ภายในระบบนิเวศของ Hugging Face

Notebook นี้จะทำงานบน GPU T4

ติดตั้งแพ็กเกจ Python

ติดตั้งไลบรารี Hugging Face ที่จำเป็นสำหรับการเรียกใช้โมเดล Gemma และส่งคำขอ

# Install PyTorch & other libraries
pip install torch accelerate

# Install the transformers library
pip install transformers

โหลดโมเดล

ใช้transformersไลบรารีเพื่อสร้างอินสแตนซ์ของ processor และ model โดยใช้คลาส AutoProcessor และ AutoModelForImageTextToText ตามที่แสดงในตัวอย่างโค้ดต่อไปนี้

MODEL_ID = "google/gemma-4-E2B-it" # @param ["google/gemma-4-E2B-it","google/gemma-4-E4B-it", "google/gemma-4-31B-it", "google/gemma-4-26B-A4B-it"]

from transformers import AutoProcessor, AutoModelForMultimodalLM

model = AutoModelForMultimodalLM.from_pretrained(MODEL_ID, dtype="auto", device_map="auto")
processor = AutoProcessor.from_pretrained(MODEL_ID)
Loading weights:   0%|          | 0/2011 [00:00<?, ?it/s]

เครื่องมือส่ง

คุณส่งเครื่องมือไปยังโมเดลได้โดยใช้ฟังก์ชัน apply_chat_template() ผ่านอาร์กิวเมนต์ tools การกำหนดเครื่องมือเหล่านี้ทำได้ 2 วิธี ดังนี้

  • สคีมา JSON: คุณสร้างพจนานุกรม JSON ด้วยตนเองเพื่อกำหนดชื่อฟังก์ชัน คำอธิบาย และพารามิเตอร์ (รวมถึงประเภทและฟิลด์ที่จำเป็น) ได้
  • ฟังก์ชัน Python ดิบ: คุณส่งฟังก์ชัน Python จริงได้ ระบบจะสร้างสคีมา JSON ที่จำเป็นโดยอัตโนมัติด้วยการแยกวิเคราะห์คำแนะนำประเภท อาร์กิวเมนต์ และสตริงเอกสารของฟังก์ชัน เพื่อให้ได้ผลลัพธ์ที่ดีที่สุด Docstring ควรเป็นไปตามคู่มือการเขียนโค้ด Python ของ Google

ตัวอย่างที่มีสคีมา JSON มีดังนี้

from transformers import TextStreamer

weather_function_schema = {
    "type": "function",
    "function": {
        "name": "get_current_temperature",
        "description": "Gets the current temperature for a given location.",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The city name, e.g. San Francisco",
                },
            },
            "required": ["location"],
        },
    }
}

message = [
    {
        "role": "system", "content": "You are a helpful assistant."
    },
    {
        "role": "user", "content": "What's the temperature in London?"
    }
]

text = processor.apply_chat_template(message, tools=[weather_function_schema], tokenize=False, add_generation_prompt=True)
inputs = processor(text=text, return_tensors="pt").to(model.device)
streamer = TextStreamer(processor)
outputs = model.generate(**inputs, streamer=streamer, max_new_tokens=64)
<bos><|turn>system
You are a helpful assistant.<|tool>declaration:get_current_temperature{description:<|"|>Gets the current temperature for a given location.<|"|>,parameters:{properties:{location:{description:<|"|>The city name, e.g. San Francisco<|"|>,type:<|"|>STRING<|"|>} },required:[<|"|>location<|"|>],type:<|"|>OBJECT<|"|>} }<tool|><turn|>
<|turn>user
What's the temperature in London?<turn|>
<|turn>model
<|tool_call>call:get_current_temperature{location:<|"|>London<|"|>}<tool_call|><|tool_response>

และตัวอย่างเดียวกันกับฟังก์ชัน Python ดิบ

from transformers.utils import get_json_schema

def get_current_temperature(location: str):
    """
    Gets the current temperature for a given location.

    Args:
        location: The city name, e.g. San Francisco
    """
    return "15°C"

message = [
    {
        "role": "user", "content": "What's the temperature in London?"
    }
]

text = processor.apply_chat_template(message, tools=[get_json_schema(get_current_temperature)], tokenize=False, add_generation_prompt=True)
inputs = processor(text=text, return_tensors="pt").to(model.device)
streamer = TextStreamer(processor)
outputs = model.generate(**inputs, streamer=streamer, max_new_tokens=256)
<bos><|turn>system
<|tool>declaration:get_current_temperature{description:<|"|>Gets the current temperature for a given location.<|"|>,parameters:{properties:{location:{description:<|"|>The city name, e.g. San Francisco<|"|>,type:<|"|>STRING<|"|>} },required:[<|"|>location<|"|>],type:<|"|>OBJECT<|"|>} }<tool|><turn|>
<|turn>user
What's the temperature in London?<turn|>
<|turn>model
<|tool_call>call:get_current_temperature{location:<|"|>London<|"|>}<tool_call|><|tool_response>

ลําดับการเรียกใช้ฟังก์ชันทั้งหมด

ส่วนนี้แสดงวงจร 3 ขั้นตอนสำหรับการเชื่อมต่อโมเดลกับเครื่องมือภายนอก ได้แก่ เทิร์นของโมเดลเพื่อสร้างออบเจ็กต์การเรียกใช้ฟังก์ชัน เทิร์นของนักพัฒนาซอฟต์แวร์เพื่อแยกวิเคราะห์และเรียกใช้โค้ด (เช่น API สภาพอากาศ) และการตอบกลับสุดท้ายที่โมเดลใช้เอาต์พุตของเครื่องมือเพื่อตอบคำถามของผู้ใช้

ตาของโมเดล

นี่คือพรอมต์ของผู้ใช้ "Hey, what's the weather in Tokyo right now?" และเครื่องมือ [get_current_weather] Gemma จะสร้างออบเจ็กต์การเรียกใช้ฟังก์ชันดังนี้

# Define a function that our model can use.
def get_current_weather(location: str, unit: str = "celsius"):
    """
    Gets the current weather in a given location.

    Args:
        location: The city and state, e.g. "San Francisco, CA" or "Tokyo, JP"
        unit: The unit to return the temperature in. (choices: ["celsius", "fahrenheit"])

    Returns:
        temperature: The current temperature in the given location
        weather: The current weather in the given location
    """
    return {"temperature": 15, "weather": "sunny"}

prompt = "Hey, what's the weather in Tokyo right now?"
tools = [get_current_weather]

message = [
    {
        "role": "system", "content": "You are a helpful assistant."
    },
    {
        "role": "user", "content": prompt
    },
]

text = processor.apply_chat_template(message, tools=tools, tokenize=False, add_generation_prompt=True)
inputs = processor(text=text, return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=128)
generated_tokens = out[0][len(inputs["input_ids"][0]):]
output = processor.decode(generated_tokens, skip_special_tokens=False)

print(f"Prompt: {prompt}")
print(f"Tools: {tools}")
print(f"Output: {output}")
Prompt: Hey, what's the weather in Tokyo right now?
Tools: [<function get_current_weather at 0x7cef824ece00>]
Output: <|tool_call>call:get_current_weather{location:<|"|>Tokyo, JP<|"|>}<tool_call|><|tool_response>

ตาของนักพัฒนาแอป

แอปพลิเคชันควรแยกวิเคราะห์การตอบกลับของโมเดลเพื่อดึงชื่อฟังก์ชันและอาร์กิวเมนต์ แล้วต่อท้าย tool_calls และ tool_responses ด้วยassistantบทบาท

import re
import json

def extract_tool_calls(text):
    def cast(v):
        try: return int(v)
        except:
            try: return float(v)
            except: return {'true': True, 'false': False}.get(v.lower(), v.strip("'\""))

    return [{
        "name": name,
        "arguments": {
            k: cast((v1 or v2).strip())
            for k, v1, v2 in re.findall(r'(\w+):(?:<\|"\|>(.*?)<\|"\|>|([^,}]*))', args)
        }
    } for name, args in re.findall(r"<\|tool_call>call:(\w+)\{(.*?)\}<tool_call\|>", text, re.DOTALL)]

calls = extract_tool_calls(output)
if calls:
    # Call the function and get the result
    #####################################
    # WARNING: This is a demonstration. #
    #####################################
    # Using globals() to call functions dynamically can be dangerous in
    # production. In a real application, you should implement a secure way to
    # map function names to actual function calls, such as a predefined
    # dictionary of allowed tools and their implementations.
    results = [
        {"name": c['name'], "response": globals()[c['name']](**c['arguments'])}
        for c in calls
    ]

    message.append({
        "role": "assistant",
        "tool_calls": [
            {"function": call} for call in calls
        ],
        "tool_responses": results
    })
    print(json.dumps(message[-1], indent=2))
{
  "role": "assistant",
  "tool_calls": [
    {
      "function": {
        "name": "get_current_weather",
        "arguments": {
          "location": "Tokyo, JP"
        }
      }
    }
  ],
  "tool_responses": [
    {
      "name": "get_current_weather",
      "response": {
        "temperature": 15,
        "weather": "sunny"
      }
    }
  ]
}
"tool_responses": [
  {
    "name": function_name,
    "response": function_response
  }
]

ในกรณีที่มีคำขอหลายรายการที่แยกกัน

"tool_responses": [
  {
    "name": function_name_1,
    "response": function_response_1
  },
  {
    "name": function_name_2,
    "response": function_response_2
  }
]

การตอบกลับสุดท้าย

สุดท้าย Gemma จะอ่านคำตอบของเครื่องมือและตอบกลับผู้ใช้

text = processor.apply_chat_template(message, tools=tools, tokenize=False, add_generation_prompt=True)
inputs = processor(text=text, return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=128)
generated_tokens = out[0][len(inputs["input_ids"][0]):]
output = processor.decode(generated_tokens, skip_special_tokens=True)
print(f"Output: {output}")
message[-1]["content"] = output
Output: The current weather in Tokyo is 15 degrees and sunny.

คุณดูประวัติการแชททั้งหมดได้ที่ด้านล่าง

# full history
print(json.dumps(message, indent=2))

print("-"*80)
output = processor.decode(out[0], skip_special_tokens=False)
print(f"Output: {output}")
[
  {
    "role": "system",
    "content": "You are a helpful assistant."
  },
  {
    "role": "user",
    "content": "Hey, what's the weather in Tokyo right now?"
  },
  {
    "role": "assistant",
    "tool_calls": [
      {
        "function": {
          "name": "get_current_weather",
          "arguments": {
            "location": "Tokyo, JP"
          }
        }
      }
    ],
    "tool_responses": [
      {
        "name": "get_current_weather",
        "response": {
          "temperature": 15,
          "weather": "sunny"
        }
      }
    ],
    "content": "The current weather in Tokyo is 15 degrees and sunny."
  }
]
--------------------------------------------------------------------------------
Output: <bos><|turn>system
You are a helpful assistant.<|tool>declaration:get_current_weather{description:<|"|>Gets the current weather in a given location.<|"|>,parameters:{properties:{location:{description:<|"|>The city and state, e.g. "San Francisco, CA" or "Tokyo, JP"<|"|>,type:<|"|>STRING<|"|>},unit:{description:<|"|>The unit to return the temperature in.<|"|>,enum:[<|"|>celsius<|"|>,<|"|>fahrenheit<|"|>],type:<|"|>STRING<|"|>} },required:[<|"|>location<|"|>],type:<|"|>OBJECT<|"|>} }<tool|><turn|>
<|turn>user
Hey, what's the weather in Tokyo right now?<turn|>
<|turn>model
<|tool_call>call:get_current_weather{location:<|"|>Tokyo, JP<|"|>}<tool_call|><|tool_response>response:get_current_weather{temperature:15,weather:<|"|>sunny<|"|>}<tool_response|>The current weather in Tokyo is 15 degrees and sunny.<turn|>

การเรียกใช้ฟังก์ชันด้วยโมเดลการคิด

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

prompt = "Hey, I'm in Seoul. Is it good for running now?"
message = [
    {
        "role": "system", "content": "You are a helpful assistant."
    },
    {
        "role": "user", "content": prompt
    },
]

text = processor.apply_chat_template(message, tools=tools, tokenize=False, add_generation_prompt=True, enable_thinking=True)
inputs = processor(text=text, return_tensors="pt").to(model.device)
input_len = inputs["input_ids"].shape[-1]

out = model.generate(**inputs, max_new_tokens=1024)
output = processor.decode(out[0][input_len:], skip_special_tokens=False)
result = processor.parse_response(output)

for key, value in result.items():
  if key == "role":
    print(f"Role: {value}")
  elif key == "thinking":
    print(f"\n=== Thoughts ===\n{value}")
  elif key == "content":
    print(f"\n=== Answer ===\n{value}")
  elif key == "tool_calls":
    print(f"\n=== Tool Calls ===\n{value}")
  else:
    print(f"\n{key}: {value}...\n")
Role: assistant

=== Thoughts ===

1.  **Analyze the Request:** The user is asking if it's "good for running now" in "Seoul".

2.  **Identify Necessary Information:** To determine if it's good for running, I need current weather information (temperature, precipitation, etc.) for Seoul.

3.  **Examine Available Tools:** The available tool is `get_current_weather(location, unit)`.

4.  **Determine Tool Arguments:**
    *   `location`: The user specified "Seoul".
    *   `unit`: The user did not specify a unit (Celsius or Fahrenheit).

5.  **Formulate the Tool Call:** I need to call `get_current_weather` with the location. Since the user didn't specify a unit, I can either omit it (if the tool defaults are acceptable) or choose a common one. However, the tool definition requires `location` but `unit` is optional.

6.  **Construct the Response Strategy:**
    *   Call the tool to get the weather data for Seoul.
    *   Once the data is received, I can advise the user on whether it's suitable for running.

7.  **Generate Tool Call:**

    ```json
    {
      "toolSpec": {
        "name": "get_current_weather",
        "args": {
          "location": "Seoul"
        }
      }
    }
    ```
    (Self-correction: The `unit` parameter is optional in the definition, so just providing the location is sufficient to proceed.)

8.  **Final Output Generation:** Present the tool call to the user/system.

=== Tool Calls ===
[{'type': 'function', 'function': {'name': 'get_current_weather', 'arguments': {'location': 'Seoul'} } }]

ประมวลผลการเรียกใช้เครื่องมือและรับคำตอบสุดท้าย

calls = extract_tool_calls(output)
if calls:
    # Call the function and get the result
    #####################################
    # WARNING: This is a demonstration. #
    #####################################
    # Using globals() to call functions dynamically can be dangerous in
    # production. In a real application, you should implement a secure way to
    # map function names to actual function calls, such as a predefined
    # dictionary of allowed tools and their implementations.
    results = [
        {"name": c['name'], "response": globals()[c['name']](**c['arguments'])}
        for c in calls
    ]

    message.append({
        "role": "assistant",
        "tool_calls": [
            {"function": call} for call in calls
        ],
        "tool_responses": results
    })

text = processor.apply_chat_template(message, tools=tools, tokenize=False, add_generation_prompt=True)
inputs = processor(text=text, return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=128)
generated_tokens = out[0][len(inputs["input_ids"][0]):]
output = processor.decode(generated_tokens, skip_special_tokens=True)
print(f"Output: {output}")
message[-1]["content"] = output

print("-"*80)
print("Full History")
print("-"*80)
print(json.dumps(message, indent=2))
Output: The current weather in Seoul is 15 degrees Celsius and sunny. That sounds like great weather for a run!
--------------------------------------------------------------------------------
Full History
--------------------------------------------------------------------------------
[
  {
    "role": "system",
    "content": "You are a helpful assistant."
  },
  {
    "role": "user",
    "content": "Hey, I'm in Seoul. Is it good for running now?"
  },
  {
    "role": "assistant",
    "tool_calls": [
      {
        "function": {
          "name": "get_current_weather",
          "arguments": {
            "location": "Seoul"
          }
        }
      }
    ],
    "tool_responses": [
      {
        "name": "get_current_weather",
        "response": {
          "temperature": 15,
          "weather": "sunny"
        }
      }
    ],
    "content": "The current weather in Seoul is 15 degrees Celsius and sunny. That sounds like great weather for a run!"
  }
]

ข้อควรระวังที่สำคัญ: สคีมาอัตโนมัติเทียบกับสคีมาที่สร้างขึ้นเอง

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

หากฟังก์ชันใช้ออบเจ็กต์ที่กำหนดเอง (เช่น คลาส Config) เป็นอาร์กิวเมนต์ ตัวแปลงอัตโนมัติอาจอธิบายเป็นเพียง "ออบเจ็กต์" ทั่วไปโดยไม่ระบุรายละเอียดพร็อพเพอร์ตี้ภายใน

ในกรณีเหล่านี้ เราขอแนะนำให้กำหนดสคีมา JSON ด้วยตนเองเพื่อให้แน่ใจว่าได้กำหนดพร็อพเพอร์ตี้ที่ซ้อนกัน (เช่น theme หรือ font_size ภายในออบเจ็กต์ config) อย่างชัดเจนสำหรับโมเดล

import json
from transformers.utils import get_json_schema

class Config:
    def __init__(self):
        self.theme = "light"
        self.font_size = 14

def update_config(config: Config):
    """
    Updates the configuration of the system.

    Args:
        config: A Config object

    Returns:
        True if the configuration was successfully updated, False otherwise.
    """

update_config_schema = {
    "type": "function",
    "function": {
        "name": "update_config",
        "description": "Updates the configuration of the system.",
        "parameters": {
            "type": "object",
            "properties": {
                "config": {
                    "type": "object",
                    "description": "A Config object",
                    "properties": {"theme": {"type": "string"}, "font_size": {"type": "number"} },
                    },
                },
            "required": ["config"],
            },
        },
    }

print(f"--- [Automatic] ---")
print(json.dumps(get_json_schema(update_config), indent=2))

print(f"\n--- [Manual Schemas] ---")
print(json.dumps(update_config_schema, indent=2))
--- [Automatic] ---
{
  "type": "function",
  "function": {
    "name": "update_config",
    "description": "Updates the configuration of the system.",
    "parameters": {
      "type": "object",
      "properties": {
        "config": {
          "type": "object",
          "description": "A Config object"
        }
      },
      "required": [
        "config"
      ]
    }
  }
}

--- [Manual Schemas] ---
{
  "type": "function",
  "function": {
    "name": "update_config",
    "description": "Updates the configuration of the system.",
    "parameters": {
      "type": "object",
      "properties": {
        "config": {
          "type": "object",
          "description": "A Config object",
          "properties": {
            "theme": {
              "type": "string"
            },
            "font_size": {
              "type": "number"
            }
          }
        }
      },
      "required": [
        "config"
      ]
    }
  }
}

สรุปและขั้นตอนถัดไป

คุณได้สร้างวิธีการสร้างแอปพลิเคชันที่เรียกฟังก์ชันด้วย Gemma 4 เวิร์กโฟลว์จะสร้างขึ้นผ่านวงจร 4 ขั้นตอน ดังนี้

  1. กำหนดเครื่องมือ: สร้างฟังก์ชันที่โมเดลใช้ได้ โดยระบุอาร์กิวเมนต์และคำอธิบาย (เช่น ฟังก์ชันการค้นหาสภาพอากาศ)
  2. เทิร์นของโมเดล: โมเดลจะได้รับพรอมต์ของผู้ใช้และรายการเครื่องมือที่พร้อมใช้งาน โดยจะแสดงผลออบเจ็กต์การเรียกใช้ฟังก์ชันที่มีโครงสร้างแทนข้อความธรรมดา
  3. ถึงคราวของนักพัฒนาแอป: นักพัฒนาแอปจะแยกวิเคราะห์เอาต์พุตนี้โดยใช้นิพจน์ทั่วไปเพื่อดึงชื่อฟังก์ชันและอาร์กิวเมนต์ จากนั้นจะรันโค้ด Python จริง และผนวกผลลัพธ์เข้ากับประวัติการแชทโดยใช้บทบาทเครื่องมือที่เฉพาะเจาะจง
  4. คำตอบสุดท้าย: โมเดลจะประมวลผลผลการดำเนินการของเครื่องมือเพื่อสร้างคำตอบสุดท้ายในภาษาธรรมชาติสำหรับผู้ใช้

ดูข้อมูลเพิ่มเติมได้ในเอกสารประกอบต่อไปนี้