Tutorial sulla chiamata di funzione

La chiamata di funzione semplifica l'ottenimento di output di dati strutturati da modelli generativi. Puoi quindi utilizzare questi output per chiamare altre API e restituire i dati di risposta pertinenti al modello. In altre parole, le chiamate di funzione consentono di collegare 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 delle funzioni che scrivi nella lingua della tua app (ovvero non sono Google Cloud Functions). Il modello potrebbe chiederti di richiamare una funzione e restituire il risultato per aiutare il modello a gestire la query.

Se non lo hai già fatto, consulta 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 del libro di ricette dell'API Gemini.

API di esempio per il controllo dell'illuminazione

Immagina di avere un sistema di base per il controllo dell'illuminazione con un'interfaccia di programmazione di un'applicazione (API) 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 dell'illuminazione. Questo ipotetico sistema di controllo dell'illuminazione consente di controllare la luminosità della luce e la sua temperatura di colore, definita come due parametri separati:

Parametro Tipo Obbligatorie Descrizione
brightness numero Livello di luce da 0 a 100. Lo zero è disattivato e 100 è piena luminosità.
colorTemperature stringa Temperatura di colore del dispositivo di illuminazione che può essere daylight, cool o warm.

Per semplicità, questo sistema di illuminazione immaginario ha una sola illuminazione, quindi l'utente non deve specificare una stanza o un luogo. Ecco un esempio di richiesta JSON che potresti inviare all'API di controllo della luce per modificare il livello della luce 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 impostare il progetto e configurare la chiave API.

Definisci una funzione API

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

def set_light_values(brightness, color_temp):
    """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 delle funzioni e dei parametri. Il modello generativo utilizza queste informazioni per determinare quale funzione selezionare e come fornire valori per i parametri nella chiamata di funzione.

Dichiara le funzioni durante l'inizializzazione del modello

Per utilizzare le chiamate di funzione con un modello, devi dichiarare le funzioni al momento dell'inizializzazione dell'oggetto di modello. Dichiari le funzioni impostando il parametro tools del modello:

model = genai.GenerativeModel(model_name='gemini-1.5-flash',
                              tools=[set_light_values])

Genera una chiamata di funzione

Dopo aver inizializzato il modello con le dichiarazioni di funzione, puoi inviare un prompt al modello con la funzione definita. Dovresti usare le chiamate di funzione tramite i prompt di chat (sendMessage()), poiché in genere le chiamate di funzione traggono vantaggio dal contesto dei prompt e delle risposte precedenti.

chat = model.start_chat()
response = chat.send_message('Dim the lights so the room feels cozy and warm.')
response.text

L'oggetto ChatSession dell'SDK Python semplifica la gestione delle sessioni di chat mediante la gestione della cronologia delle conversazioni per te. Puoi utilizzare enable_automatic_function_calling per fare in modo che l'SDK venga automaticamente

# Create a chat session that automatically makes suggested function calls
chat = model.start_chat(enable_automatic_function_calling=True)

Chiamate di funzione parallele

Oltre alle chiamate di funzione di base descritte sopra, puoi anche richiamare più funzioni in un singolo turno. Questa sezione mostra un esempio di come utilizzare le chiamate di funzione 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, bpm: int) -> 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.
      bpm: The beats per minute of the music.

    Returns: The name of the song being played.
    """
    print(f"Starting music! {energetic=} {loud=}, {bpm=}")
    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 usare tutti gli strumenti specificati.

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

model = genai.GenerativeModel(model_name="gemini-1.5-flash", tools=house_fns)

# Call the API.
chat = model.start_chat()
response = chat.send_message("Turn this place into a party!")

# Print out each of the function calls requested from this single call.
for part in response.parts:
    if fn := part.function_call:
        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, bpm=120.0)
dim_lights(brightness=0.3)

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

# Simulate the responses from the specified tools.
responses = {
    "power_disco_ball": True,
    "start_music": "Never gonna give you up.",
    "dim_lights": True,
}

# Build the response parts.
response_parts = [
    genai.protos.Part(function_response=genai.protos.FunctionResponse(name=fn, response={"result": val}))
    for fn, val in responses.items()
]

response = chat.send_message(response_parts)
print(response.text)
Let's get this party started! I've turned on the disco ball, started playing some upbeat music, and dimmed the lights. 🎶✨  Get ready to dance! 🕺💃

Mappatura del tipo di dati della chiamata 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 supporta questa funzionalità. L'API è in grado di descrivere uno qualsiasi dei seguenti tipi:

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

La libreria client google.ai.generativelanguage fornisce l'accesso ai tipi di basso livello, offrendoti il controllo completo.

Prima di dare un'occhiata all'attributo _tools del modello, puoi vedere come descrive le funzioni che hai passato al modello:

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

model = genai.GenerativeModel(model_name='gemini-1.5-flash',
                             tools=[multiply])

model._tools.to_proto()
[function_declarations {
   name: "multiply"
   description: "returns a * b."
   parameters {
     type_: OBJECT
     properties {
       key: "b"
       value {
         type_: NUMBER
       }
     }
     properties {
       key: "a"
       value {
         type_: NUMBER
       }
     }
     required: "a"
     required: "b"
   }
 }]

Questo restituisce l'elenco degli oggetti genai.protos.Tool che verranno inviati all'API. Se il formato cartaceo non è familiare, è perché si tratta di classi protobuf Google. Ciascun genai.protos.Tool (in questo caso 1) contiene un elenco di genai.protos.FunctionDeclarations, che descrive una funzione e i suoi argomenti.

Ecco una dichiarazione per la stessa funzione di moltiplicazione scritta utilizzando le classi genai.protos. Queste classi descrivono solo la funzione per l'API e non includono un'implementazione. Pertanto, questa soluzione non funziona con le chiamate di funzione automatiche, ma le funzioni non richiedono sempre un'implementazione.

calculator = genai.protos.Tool(
    function_declarations=[
      genai.protos.FunctionDeclaration(
        name='multiply',
        description="Returns the product of two numbers.",
        parameters=genai.protos.Schema(
            type=genai.protos.Type.OBJECT,
            properties={
                'a':genai.protos.Schema(type=genai.protos.Type.NUMBER),
                'b':genai.protos.Schema(type=genai.protos.Type.NUMBER)
            },
            required=['a','b']
        )
      )
    ])

In modo equivalente, puoi descrivere questo oggetto come un oggetto compatibile con JSON:

calculator = {'function_declarations': [
      {'name': 'multiply',
       'description': 'Returns the product of two numbers.',
       'parameters': {'type_': 'OBJECT',
       'properties': {
         'a': {'type_': 'NUMBER'},
         'b': {'type_': 'NUMBER'} },
       'required': ['a', 'b']} }]}
genai.protos.Tool(calculator)
function_declarations {
  name: "multiply"
  description: "Returns the product of two numbers."
  parameters {
    type_: OBJECT
    properties {
      key: "b"
      value {
        type_: NUMBER
      }
    }
    properties {
      key: "a"
      value {
        type_: NUMBER
      }
    }
    required: "a"
    required: "b"
  }
}

In ogni caso, passi una rappresentazione di un genai.protos.Tool o un elenco di strumenti

model = genai.GenerativeModel('gemini-1.5-flash', tools=calculator)
chat = model.start_chat()

response = chat.send_message(
    f"What's 234551 X 325552 ?",
)

Come prima, il modello restituisce un genai.protos.FunctionCall richiamando la funzione multiply della calcolatrice:

response.candidates
[index: 0
content {
  parts {
    function_call {
      name: "multiply"
      args {
        fields {
          key: "b"
          value {
            number_value: 325552
          }
        }
        fields {
          key: "a"
          value {
            number_value: 234551
          }
        }
      }
    }
  }
  role: "model"
}
finish_reason: STOP
]

Esegui la funzione autonomamente:

fc = response.candidates[0].content.parts[0].function_call
assert fc.name == 'multiply'

result = fc.args['a'] * fc.args['b']
result
76358547152.0

Invia il risultato al modello per continuare la conversazione:

response = chat.send_message(
    genai.protos.Content(
    parts=[genai.protos.Part(
        function_response = genai.protos.FunctionResponse(
          name='multiply',
          response={'result': result}))]))