Tutorial sulla chiamata di funzione

La chiamata di funzioni semplifica l'ottenimento di output di dati strutturati dai modelli generativi. Puoi quindi utilizzare questi output per chiamare altre API e restituire al modello i dati di risposta pertinenti. In altre parole, le chiamate di funzione ti aiutano a collegare i modelli generativi a sistemi esterni in modo che i contenuti generati includano le informazioni più aggiornate e accurate.

Puoi fornire ai modelli Gemini descrizioni delle funzioni. Si tratta di funzioni che scrivi nel linguaggio della tua app (ovvero non sono funzioni Google Cloud). Il modello potrebbe chiederti di chiamare una funzione e di inviare nuovamente il risultato per aiutarlo a gestire la tua query.

Se non l'hai ancora fatto, consulta la sezione Introduzione alle chiamate di funzione per saperne di più. Puoi anche provare questa funzionalità in Google Colab o visualizzare il codice di esempio nel repository Gemini API Cookbook.

API di esempio per il controllo dell'illuminazione

Immagina di avere un sistema di controllo dell'illuminazione di base con un'API (Application Programming Interface) e di voler consentire agli utenti di controllare le luci tramite semplici richieste di testo. Puoi utilizzare la funzionalità di chiamata di funzione per interpretare le richieste di modifica dell'illuminazione da parte degli utenti e tradurle in chiamate API per impostare i valori di illuminazione. Questo ipotetico sistema di controllo dell'illuminazione ti consente di regolare la luminosità della luce e la sua temperatura di colore, definite come due parametri distinti:

Parametro Tipo Obbligatorio Descrizione
brightness numero Livello di illuminazione da 0 a 100. 0 corrisponde a off e 100 a luminosità massima.
colorTemperature stringa Temperatura di colore della lampada, che può essere daylight, cool o warm.

Per semplicità, questo sistema di illuminazione immaginario ha una sola luce, quindi l'utente non deve specificare una stanza o una posizione. Ecco un esempio di richiesta JSON che puoi inviare all'API di controllo dell'illuminazione per impostare il livello di illuminazione al 50% utilizzando la temperatura di colore della luce diurna:

{
  "brightness": "50",
  "colorTemperature": "daylight"
}

Questo tutorial mostra come configurare una chiamata di funzione per l'API Gemini per interpretare le richieste di illuminazione degli utenti e mapparle alle impostazioni dell'API per controllare i valori di luminosità e temperatura di colore di una luce.

Prima di iniziare: configura il progetto e la chiave API

Prima di chiamare l'API Gemini, devi configurare il progetto e la chiave API.

Definire una funzione API

Crea una funzione che effettui una richiesta API. Questa funzione deve essere definita all'interno del codice dell'applicazione, ma potrebbe chiamare servizi o API esterni all'applicazione. L'API Gemini non chiama questa funzione direttamente, quindi puoi controllare come e quando viene eseguita tramite il codice dell'applicazione. A scopo dimostrativo, questo tutorial definisce una funzione API simulata che restituisce solo i valori di illuminazione richiesti:

def set_light_values(brightness: int, color_temp: str) -> dict[str, int | str]:
    """Set the brightness and color temperature of a room light. (mock API).

    Args:
        brightness: Light level from 0 to 100. Zero is off and 100 is full brightness
        color_temp: Color temperature of the light fixture, which can be `daylight`, `cool` or `warm`.

    Returns:
        A dictionary containing the set brightness and color temperature.
    """
    return {
        "brightness": brightness,
        "colorTemperature": color_temp
    }

Quando crei una funzione da utilizzare in una chiamata di funzione dal modello, devi includere il maggior numero possibile di dettagli nelle descrizioni della funzione e dei parametri. Il modello generativo utilizza queste informazioni per determinare quale funzione selezionare e come fornire i valori per i parametri nella chiamata della funzione.

Dichiarare le funzioni durante l'inizializzazione del modello

Quando vuoi utilizzare la chiamata di funzioni, definisci le funzioni come strumenti in GenerateContentConfig, insieme ad altre impostazioni relative alla generazione (ad esempio i token di temperatura o di interruzione).

from google.genai import types

config = types.GenerateContentConfig(tools=[set_light_values])

Può essere definito anche come dizionario Python.

config = {
    'tools': [set_light_values],
}

Generare una chiamata di funzione

Dopo aver definito le dichiarazioni delle funzioni, puoi chiedere al modello di usarle. Puoi generare contenuti direttamente o utilizzando l'interfaccia chat.

from google import genai

client = genai.Client()

# Generate directly with generate_content.
response = client.models.generate_content(
    model='gemini-2.0-flash',
    config=config,
    contents='Turn the lights down to a romantic level'
)
print(response.text)

# Use the chat interface.
chat = client.chats.create(model='gemini-2.0-flash', config=config)
response = chat.send_message('Turn the lights down to a romantic level')
print(response.text)

Nell'SDK Python, le funzioni vengono chiamate automaticamente. Se vuoi gestire ogni chiamata di funzione o eseguire un'altra logica tra le chiamate, puoi disattivarla tramite il flag nella configurazione di generazione.

from google.genai import types

# Use strong types.
config = types.GenerateContentConfig(
    tools=[set_light_values],
    automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True)
)

# Use a dictionary.
config = {
    'tools': [set_light_values],
    'automatic_function_calling': {'disable': True},
}

Chiamata di funzioni parallele

Oltre alla chiamata di funzioni di base descritta sopra, puoi anche chiamare più funzioni in un unico passaggio. Questa sezione mostra un esempio di come utilizzare la chiamata di funzioni parallele.

Definisci gli strumenti.

def power_disco_ball(power: bool) -> bool:
    """Powers the spinning disco ball."""
    print(f"Disco ball is {'spinning!' if power else 'stopped.'}")
    return True


def start_music(energetic: bool, loud: bool) -> str:
    """Play some music matching the specified parameters.

    Args:
      energetic: Whether the music is energetic or not.
      loud: Whether the music is loud or not.

    Returns: The name of the song being played.
    """
    print(f"Starting music! {energetic=} {loud=}")
    return "Never gonna give you up."


def dim_lights(brightness: float) -> bool:
    """Dim the lights.

    Args:
      brightness: The brightness of the lights, 0.0 is off, 1.0 is full.
    """
    print(f"Lights are now set to {brightness:.0%}")
    return True

Ora chiama il modello con un'istruzione che potrebbe utilizzare tutti gli strumenti specificati. Questo esempio utilizza un tool_config. Per scoprire di più, puoi leggere l'articolo sulla configurazione della chiamata di funzione.

# Set the model up with tools.
house_fns = [power_disco_ball, start_music, dim_lights]

config = {
    # Set the available functions.
    'tools': house_fns,
    # Disable AFC so you can inspect the results first.
    'automatic_function_calling': {'disable': True},
    # Force the model to act (call 'any' function), instead of chatting.
    'tool_config': {
        'function_calling_config': {
            'mode': 'any'
        }
    }
}

# Call the API.
chat = client.chats.create(model='gemini-2.0-flash', config=config)
response = chat.send_message('Turn this place into a party!')

# Print out each of the function calls requested from this single call.
for fn in response.function_calls:
  args = ", ".join(f"{key}={val}" for key, val in fn.args.items())
  print(f"{fn.name}({args})")
power_disco_ball(power=True)
start_music(energetic=True, loud=True)
dim_lights(brightness=0.3)

Ciascuno dei risultati stampati riflette una singola chiamata di funzione richiesta dal modello. Per inviare i risultati, includi le risposte nello stesso ordine in cui sono state richieste.

Il modo più semplice per farlo è lasciare abilitata l'opzione automatic_function_calling, in modo che l'SDK gestisca automaticamente le chiamate alle funzioni e il passaggio della risposta.

config = {
    'tools': house_fns,
}

# Call the API.
chat = client.chats.create(model='gemini-2.0-flash', config=config)
response = chat.send_message('Do everything you need to this place into party!')

print(response.text)
Disco ball is spinning!
Starting music! energetic=True loud=True
Lights are now set to 50%
Alright, I've turned on the disco ball, started playing "Never gonna give you up.", and dimmed the lights. Let's get this party started!

Mappatura dei tipi di dati delle chiamate di funzione

L'estrazione automatica dello schema dalle funzioni Python non funziona in tutti i casi. Ad esempio, non gestisce i casi in cui descrivi i campi di un oggetto dizionario nidificato, ma l'API lo supporta. L'API è in grado di descrivere uno dei seguenti tipi:

AllowedType = (int | float | bool | str | list['AllowedType'] | dict[str, AllowedType])

Per vedere l'aspetto dello schema dedotto, puoi convertirlo utilizzando from_callable:

from pprint import pprint

def multiply(a: float, b: float):
    """Returns a * b."""
    return a * b

fn_decl = types.FunctionDeclaration.from_callable(callable=multiply, client=client)

# to_json_dict() provides a clean JSON representation.
pprint(fn_decl.to_json_dict())
{'description': 'Returns a * b.',
 'name': 'multiply',
 'parameters': {'properties': {'a': {'type': 'NUMBER'},
                               'b': {'type': 'NUMBER'}},
                'type': 'OBJECT'}}

Questi campi JSON mappano ai campi equivalenti nello schema Pydantic e possono essere racchiusi come Tool.

config = types.GenerateContentConfig(
    tools=[types.Tool(function_declarations=[fn_decl])]
)

Ecco una dichiarazione per la stessa funzione multiply scritta utilizzando le classi genai.types. Tieni presente che queste classi descrivono solo la funzione per l'API, non ne includono un'implementazione, pertanto questo approccio non funziona con la chiamata automatica delle funzioni. Tuttavia, ti consente di definire funzioni che non sono funzioni Python concrete (ad esempio per eseguire il wrapping di una chiamata HTTP remota) e ti offre un maggiore controllo tra le chiamate di funzione (ad esempio per modificare function_calling_config in modo che segua un grafico di stato).

tool = types.Tool(function_declarations=[
    types.FunctionDeclaration(
        name="multiply",
        description="Returns a * b.",
        parameters=types.Schema(
            properties={
                'a': types.Schema(type='NUMBER'),
                'b': types.Schema(type='NUMBER'),
            },
            type='OBJECT',
        ),
    )
])
assert tool.function_declarations[0] == fn_decl