|
|
Exécuter dans Google Colab
|
|
|
Afficher la source sur GitHub
|
Lorsque vous utilisez un modèle d'intelligence artificielle (IA) générative tel que Gemma, vous pouvez l'utiliser pour exploiter des interfaces de programmation afin d'effectuer des tâches ou de répondre à des questions. Le fait de donner des instructions à un modèle en définissant une interface de programmation, puis en envoyant une requête qui utilise cette interface est appelé appel de fonction.
Ce guide explique comment utiliser Gemma 4 dans l'écosystème Hugging Face.
Ce notebook s'exécutera sur un GPU T4.
Installer des packages Python
Installez les bibliothèques Hugging Face requises pour exécuter le modèle Gemma et envoyer des requêtes.
# Install PyTorch & other librariespip install torch accelerate# Install the transformers librarypip install transformers
Charger le modèle
Utilisez les bibliothèques transformers pour créer une instance de processor et de model à l'aide des classes AutoProcessor et AutoModelForImageTextToText, comme illustré dans l'exemple de code suivant :
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]
Transmettre des outils
Vous pouvez transmettre des outils au modèle à l'aide de la fonction apply_chat_template() via l'argument tools. Il existe deux méthodes pour définir ces outils :
- Schéma JSON : vous pouvez créer manuellement un dictionnaire JSON définissant le nom, la description et les paramètres de la fonction (y compris les types et les champs obligatoires).
- Fonctions Python brutes : vous pouvez transmettre des fonctions Python réelles. Le système génère automatiquement le schéma JSON requis en analysant les indications de type, les arguments et les chaînes de documentation de la fonction. Pour obtenir les meilleurs résultats, les chaînes de documentation doivent respecter le guide de style Python de Google.
Vous trouverez ci-dessous l'exemple avec le schéma 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>
Et le même exemple avec la fonction Python brute.
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>
Séquence complète d'appel de fonction
Cette section présente un cycle en trois étapes pour connecter le modèle à des outils externes : le tour du modèle pour générer des objets d'appel de fonction, le tour du développeur pour analyser et exécuter du code (tel qu'une API météo) et la réponse finale où le modèle utilise la sortie de l'outil pour répondre à l'utilisateur.
Tour du modèle
Voici le prompt de l'utilisateur "Hey, what's the weather in Tokyo right now?" et l'outil [get_current_weather]. Gemma génère un objet d'appel de fonction comme suit.
# 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>
Tour du développeur
Votre application doit analyser la réponse du modèle pour extraire le nom et les arguments de la fonction, puis ajouter tool_calls et tool_responses avec le rôle 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
}
]
En cas de requêtes indépendantes multiples :
"tool_responses": [
{
"name": function_name_1,
"response": function_response_1
},
{
"name": function_name_2,
"response": function_response_2
}
]
Réponse finale
Enfin, Gemma lit la réponse de l'outil et répond à l'utilisateur.
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.
Vous pouvez consulter l'historique complet du chat ci-dessous.
# 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|>
Appel de fonction avec Thinking
En utilisant un processus de raisonnement interne, le modèle améliore considérablement la précision de ses appels de fonction. Cela permet de prendre des décisions plus précises concernant le moment où un outil doit être déclenché et la manière de définir ses paramètres.
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'} } }]
Traitez l'appel d'outil et obtenez la réponse finale.
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!"
}
]
Remarque importante : schémas automatiques et manuels
Lorsque vous vous appuyez sur la conversion automatique des fonctions Python en schéma JSON, la sortie générée ne répond pas toujours à des attentes spécifiques concernant les paramètres complexes.
Si une fonction utilise un objet personnalisé (comme une classe de configuration) comme argument, le convertisseur automatique peut le décrire simplement comme un "objet" générique sans détailler ses propriétés internes.
Dans ce cas, il est préférable de définir manuellement le schéma JSON pour s'assurer que les propriétés imbriquées (telles que le thème ou la taille de la police dans un objet de configuration) sont explicitement définies pour le modèle.
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"
]
}
}
}
Résumé et étapes suivantes
Vous avez établi comment créer une application capable d'appeler des fonctions avec Gemma 4. Le workflow est établi selon un cycle en quatre étapes :
- Définir des outils : créez les fonctions que votre modèle peut utiliser, en spécifiant les arguments et les descriptions (par exemple, une fonction de recherche météo).
- Tour du modèle : le modèle reçoit le prompt de l'utilisateur et une liste d'outils disponibles, et renvoie un objet d'appel de fonction structuré au lieu de texte brut.
- Tour du développeur : le développeur analyse cette sortie à l'aide d'expressions régulières pour extraire les noms et les arguments des fonctions, exécute le code Python réel et ajoute les résultats à l'historique du chat à l'aide du rôle d'outil spécifique.
- Réponse finale : le modèle traite le résultat de l'exécution de l'outil pour générer une réponse finale en langage naturel pour l'utilisateur.
Pour en savoir plus, consultez la documentation suivante.
Exécuter dans Google Colab
Afficher la source sur GitHub