Come interagire con le API utilizzando la chiamata di funzione in Gemini

1. Panoramica

Che cos'è la chiamata di funzione in Gemini?

L'API Vertex AI Gemini è una famiglia di modelli di AI generativa sviluppati da Google DeepMind progettati per casi d'uso multimodali. La chiamata di funzione è una funzionalità dei modelli Gemini che consente agli sviluppatori di ottenere più facilmente output di dati strutturati dai modelli generativi.

Gli sviluppatori possono quindi utilizzare questi output per chiamare altre API e restituire i dati di risposta pertinenti al modello. In altre parole, la chiamata di funzione ti aiuta a connettere i tuoi modelli generativi a sistemi esterni in modo che i contenuti generati includano le informazioni più aggiornate e accurate.

Come funziona la chiamata di funzioni

Le funzioni vengono descritte utilizzando le dichiarazioni di funzione, che aiutano il modello generativo a comprendere lo scopo e i parametri all'interno di una funzione. Dopo aver passato le dichiarazioni di funzione in una query a un modello generativo, il modello restituisce un oggetto strutturato che include i nomi delle funzioni pertinenti e i relativi argomenti in base alla query dell'utente. Tieni presente che con la chiamata di funzione, il modello non chiama effettivamente la funzione. Puoi invece utilizzare la funzione e i parametri restituiti per chiamare la funzione in qualsiasi linguaggio, libreria o framework che preferisci.

Interfaccia API

Cosa creerai

In questo codelab, creerai una pipeline di AI generativa con l'API Vertex AI Gemini e Python. Utilizzando la tua app, gli utenti possono chiedere informazioni sui tassi di cambio e il sistema recupererà i dati più recenti da un'API esterna e risponderà all'utente con la risposta.

Obiettivi didattici

  • Come interagire con il modello Gemini utilizzando la libreria client Python
  • Come definire una dichiarazione di funzione e registrarla come strumento
  • Come chiamare Gemini e ottenere una risposta alla chiamata di funzione
  • Come restituire la risposta della funzione a Gemini e rispondere all'utente

Che cosa ti serve

2. Configurazione e requisiti

Prima di poter iniziare a utilizzare la chiamata di funzione in Gemini, devi abilitare l'API Vertex AI e installare l'ultima versione della libreria client Python di Vertex AI.

Abilita API Vertex AI

Per abilitare l'API Vertex AI:

  1. Nel browser, vai alla pagina dei dettagli del servizio API Vertex AI.
  2. Fai clic sul pulsante Abilita per abilitare l'API Vertex AI nel tuo progetto Google Cloud.

Installa la libreria client Python per Vertex AI

Per installare le librerie client Python per Vertex AI, segui questi passaggi:

  1. Apri un terminale nell'ambiente di sviluppo.
  2. Verifica di disporre di un ambiente di sviluppo Python valido e consulta queste linee guida, se necessario.
  3. Esegui questo comando per installare la libreria client Python per Vertex AI:
    pip install --upgrade google-cloud-aiplatform
    
  4. Se esegui l'operazione in un ambiente notebook, potrebbe essere necessario riavviare il runtime/kernel per utilizzare i pacchetti appena installati.

Ora puoi utilizzare l'API Vertex AI.

3. Comprendere il problema

Ti è mai capitato di interagire con un modello linguistico di grandi dimensioni o di AI generativa e di chiedere informazioni in tempo reale o attuali, per poi ricevere una risposta con informazioni obsolete o imprecise?

Proviamo subito. Innanzitutto, importeremo i pacchetti Python pertinenti e inizializzeremo il modello Gemini. Puoi eseguire il seguente codice in un ambiente di sviluppo Python come Colab o Colab Enterprise e installando l'ultima versione dell'SDK Vertex AI per Python:

import vertexai
from vertexai.generative_models import GenerativeModel
model = GenerativeModel("gemini-1.5-pro-001")

Ora, poniamo una domanda sul tasso di cambio per le diverse valute oggi:

response = model.generate_content(
    "What's the exchange rate for euros to dollars today?"
)
print(response.text)

Il modello dovrebbe generare una risposta limitata o obsoleta simile a:

As an AI language model, I don't have access to real-time currency exchange
rates. However, as of my last update in September 2021, the approximate exchange
rate between euros (EUR) and US dollars (USD) was:

1 EUR ≈ 1.18 USD

Please note that currency exchange rates constantly fluctuate and can vary
depending on various factors such as economic conditions, supply and demand,
political events, and more. To obtain the most up-to-date and accurate exchange
rate, I recommend using a reliable currency converter or financial website that
provides live rates.

[...]

Se un utente finale riceve questo tipo di risposta, deve cambiare contesto per cercare le valute che gli interessano, recuperare l'ultimo tasso di cambio ed eseguire autonomamente le conversioni.

Idealmente, una pipeline di modelli generativi potrebbe gestire alcune o tutte queste attività per l'utente. Nella sezione successiva, proverai alcune soluzioni alternative comuni per ottenere risposte strutturate dai modelli generativi in modo da poter chiamare sistemi esterni.

4. Provare soluzioni alternative comuni

Quando lavori con modelli generativi in scenari in cui hai bisogno di informazioni o dati aggiornati da fonti esterne, puoi chiamare un'API esterna e poi fornire i risultati al modello generativo in modo che li utilizzi nella sua risposta.

Prima di chiamare un sistema esterno, devi determinare la funzione giusta da utilizzare, estrarre i parametri pertinenti dall'utente e inserirli in un oggetto di dati strutturati. In genere, ciò comporta un'ingegneria dei prompt esaustiva per forzare il modello generativo a restituire dati strutturati validi.

Torniamo alla domanda che abbiamo posto nella sezione precedente e aggiungiamo alcune istruzioni aggiuntive per il modello. Prova a inviare la seguente richiesta al modello Gemini:

user_prompt = "What's the exchange rate from euros to US dollars today?"

response = model.generate_content("""
Your task is to extract parameters from the user's input and return it as a
structured JSON payload. The user will ask about the exchange rate and which
currency they are converting from and converting to.

User input: {user_prompt}

Please extract the currencies as parameters and put them in a JSON object.
""".format(user_prompt=user_prompt))
print(response.text)

Il risultato è la seguente risposta di testo, che non è un JSON valido e sarà difficile da utilizzare:

```json
{
  "currency_from": "euros",
  "currency_to": "US dollars"
}
```

In particolare, la prima e l'ultima riga della risposta di testo includono il carattere backtick per delimitare il blocco di codice, la prima riga include uno specificatore di lingua e i valori nell'oggetto JSON non sono le abbreviazioni standard di tre lettere per le valute che un'API di cambio valuta si aspetterebbe come parametri di input.

Potremmo provare a utilizzare Python per post-elaborare questo testo in JSON valido e in un dizionario, aggiungere altre istruzioni al prompt, fornire uno o più esempi dell'output desiderato, perfezionare il modello o effettuare un'altra chiamata al modello generativo chiedendogli di ripulire il JSON.

Esiste però un modo più deterministico. Scopriamo come utilizzare la chiamata di funzione in Gemini per eseguire query per informazioni in servizi esterni e restituire risposte pertinenti agli utenti finali.

5. Come funziona la chiamata di funzioni

Prima di iniziare con l'estrazione dei parametri e la chiamata di funzione, esaminiamo i passaggi della chiamata di funzione e i componenti utilizzati in fase di runtime.

Panoramica delle chiamate di funzione in Gemini

Input dell'utente all'API Gemini

Il prompt dell'utente viene inviato all'API Gemini e, in questa chiamata API al modello Gemini, lo sviluppatore ha definito una o più dichiarazioni di funzione all'interno di uno strumento in modo che il modello Gemini sappia quali funzioni può chiamare e come chiamarle.

L'API Gemini restituisce una chiamata di funzione

In base ai contenuti dell'input e del prompt dell'utente, Gemini restituirà una risposta di chiamata di funzione con dati strutturati che includono il nome della funzione da chiamare e i parametri corrispondenti da utilizzare.

Esegui una richiesta API

Poi, utilizzerai il nome e i parametri della funzione per effettuare una richiesta API per recuperare informazioni da un sistema o un'API esterni. Questa richiesta e risposta API viene implementata dallo sviluppatore nel codice dell'applicazione e si verifica al di fuori dell'ambito dell'API e dell'SDK Gemini. Ad esempio, puoi utilizzare la libreria requests in Python per chiamare un'API REST e ricevere una risposta JSON. In alternativa, puoi chiamare la funzione utilizzando l'approccio e la libreria client che preferisci.

Restituisci la risposta API a Gemini

Infine, passerai la risposta dell'API al modello Gemini in modo che possa generare una risposta al prompt iniziale dell'utente finale o richiamare un'altra risposta di chiamata di funzione se il modello Gemini determina che ha bisogno di ulteriori informazioni.

6. Scegliere l'API

Ora che hai compreso il flusso generale e i passaggi specifici nella chiamata di funzione, creerai una pipeline di AI generativa per recuperare gli ultimi tassi di cambio. Innanzitutto, dobbiamo selezionare l'API che vogliamo utilizzare come origine delle informazioni.

Per la nostra app di cambio valuta, utilizzeremo l'API REST all'indirizzo https://www.frankfurter.app/ per recuperare le informazioni più recenti sui tassi di cambio globali.

Per interagire con questa API REST, potremmo effettuare una chiamata API REST con requests in Python come segue:

import requests
url = "https://api.frankfurter.app/latest"
response = requests.get(url)
response.text

o una richiesta cURL come:

curl https://api.frankfurter.app/latest

che restituisce una risposta simile alla seguente:

{
  "amount": 1,
  "base": "EUR",
  "date": "2023-12-20",
  "rates": {
    "AUD": 1.6186, "BGN": 1.9558, "BRL": 5.3287,
    "CAD": 1.4609, "CHF": 0.946, "CNY": 7.8121,
    "CZK": 24.538, "DKK": 7.4565, "GBP": 0.86555,
    "HKD": 8.5439, "HUF": 385.23, "IDR": 16994,
    "ILS": 3.9983, "INR": 91.06, "ISK": 150.3,
    "JPY": 157.12, "KRW": 1425.62, "MXN": 18.6867,
    "MYR": 5.0977, "NOK": 11.2895, "NZD": 1.7421,
    "PHP": 60.991, "PLN": 4.3413, "RON": 4.9699,
    "SEK": 11.129, "SGD": 1.4562, "THB": 38.252,
    "TRY": 31.883, "USD": 1.0944, "ZAR": 20.111
  }
}

Poiché la chiamata di funzione in Gemini non effettua effettivamente la chiamata API esterna per te, non esistono restrizioni sul tipo di API che utilizzi. Puoi utilizzare un servizio Cloud Run, una funzione Cloud, una richiesta API a un servizio Google Cloud o qualsiasi API REST esterna.

7. Definisci una funzione e uno strumento

Ora che hai selezionato un'API REST da utilizzare, possiamo definire una specifica API e registrare la funzione in uno strumento.

Assicurati di aver installato l'ultima versione dell'SDK Vertex AI per Python.

Quindi, importa i moduli necessari dall'SDK Python e inizializza il modello Gemini:

from vertexai.generative_models import (
    Content,
    FunctionDeclaration,
    GenerativeModel,
    Part,
    Tool,
)

model = GenerativeModel("gemini-1.5-pro-001")

Tornando all'API REST all'indirizzo https://api.frankfurter.app/, possiamo vedere che accetta i seguenti parametri di input:

Parametro

Tipo

Descrizione

from

Stringa

Valuta da cui convertire

to

Stringa

Valuta in cui convertire

date

Stringa

Data per recuperare il tasso di cambio

Utilizzando questi parametri, una specifica OpenAPI parziale per questa API REST in formato YAML ha il seguente aspetto:

openapi: 3.0.0
info:
  title: Frankfurter Exchange Rate API
  description: This API provides current and historical exchange rates
  version: 1.0.0
servers:
  - url: https://api.frankfurter.app
paths:
  /{date}:
    get:
      summary: Get the latest currency exchange rates.
      parameters:
        - name: date
          in: path
          description: Get currency rates for a specific date or 'latest' if a date is not specified
          required: true
          schema:
            type: string
        - name: from
          in: query
          description: The currency to convert from.
          required: true
          schema:
            type: string
        - name: to
          in: query
          description: The currency to convert to.
          schema:
            type: string

Ora registriamolo come FunctionDeclaration utilizzando l'SDK Python per Gemini:

get_exchange_rate_func = FunctionDeclaration(
    name="get_exchange_rate",
    description="Get the exchange rate for currencies between countries",
    parameters={
    "type": "object",
    "properties": {
        "currency_date": {
            "type": "string",
            "description": "A date that must always be in YYYY-MM-DD format or the value 'latest' if a time period is not specified"
        },
        "currency_from": {
            "type": "string",
            "description": "The currency to convert from in ISO 4217 format"
        },
        "currency_to": {
            "type": "string",
            "description": "The currency to convert to in ISO 4217 format"
        }
    },
         "required": [
            "currency_from",
            "currency_date",
      ]
  },
)

Assicurati di utilizzare il maggior numero possibile di dettagli nelle descrizioni di funzioni e parametri, poiché il modello generativo utilizzerà queste informazioni per determinare quale funzione selezionare e come compilare i parametri nella chiamata di funzione.

Infine, definirai un Tool che include la dichiarazione di funzione:

exchange_rate_tool = Tool(
    function_declarations=[get_exchange_rate_func],
)

Qui utilizzi una dichiarazione di funzione all'interno di uno strumento, ma tieni presente che puoi registrare una o più dichiarazioni di funzione in uno strumento e il modello selezionerà la funzione appropriata da utilizzare in fase di runtime. Per ulteriori dettagli su FunctionDeclaration, Tool e sulle classi correlate nell'SDK Gemini per Python, consulta la documentazione su Chiamata di funzioni nell'API Gemini.

Hai completato la configurazione delle definizioni di funzioni e strumenti. Nella sezione successiva, chiameremo il modello generativo con questo strumento e riceveremo una chiamata di funzione che possiamo utilizzare per chiamare l'API REST.

8. Generare una chiamata di funzione

Ora puoi richiedere al modello generativo di includere il tool che hai definito:

prompt = """What is the exchange rate from Australian dollars to Swedish krona?
How much is 500 Australian dollars worth in Swedish krona?"""

response = model.generate_content(
    prompt,
    tools=[exchange_rate_tool],
)

Diamo un'occhiata all'oggetto di risposta:

print(response.candidates[0].content)

role: "model"
parts {
  function_call {
    name: "get_exchange_rate"
    args {
      fields {
        key: "currency_to"
        value {
          string_value: "SEK"
        }
      }
      fields {
        key: "currency_from"
        value {
          string_value: "AUD"
        }
      }
      fields {
        key: "currency_date"
        value {
          string_value: "latest"
        }
      }
    }
  }
}

Sembra che il modello abbia selezionato l'unica funzione disponibile e abbia restituito una chiamata di funzione per la funzione get_exchange_rate insieme ai parametri. e i parametri sono nel formato corretto che volevamo. Evviva per le risposte strutturate dei modelli generativi!

Nella sezione successiva, utilizzerai le informazioni nella risposta per effettuare una richiesta API.

9. Esegui una richiesta API

Ricorda che la chiamata di funzione in Gemini non effettua effettivamente la chiamata API esterna per te. Puoi utilizzare qualsiasi linguaggio, libreria o framework che preferisci.

Qui utilizzerai la libreria requests in Python per chiamare l'API REST per i tassi di cambio.

Analizziamo la risposta in un dizionario Python:

params = {}
for key, value in response.candidates[0].content.parts[0].function_call.args.items():
    params[key[9:]] = value
params

Ora possiamo chiamare requests o qualsiasi altro metodo:

import requests
url = f"https://api.frankfurter.app/{params['date']}"
api_response = requests.get(url, params=params)
api_response.text

che genera una risposta simile alla seguente:

'{"amount":1.0,"base":"AUD","date":"2024-01-16","rates":{"SEK":6.8682}}'

Abbiamo ricevuto la risposta dall'API REST, con le informazioni sul tasso di cambio più recente di oggi. Nella sezione successiva, trasmetteremo queste informazioni al modello in modo che possa generare una risposta pertinente per l'utente.

10. Generare una risposta

Infine, generiamo una risposta per l'utente restituendo la risposta della funzione al modello nel turno di conversazione successivo:

response = model.generate_content(
    [
    Content(role="user", parts=[
        Part.from_text(prompt + """Give your answer in steps with lots of detail
            and context, including the exchange rate and date."""),
    ]),
    Content(role="function", parts=[
        Part.from_dict({
            "function_call": {
                "name": "get_exchange_rate",
            }
        })
    ]),
    Content(role="function", parts=[
        Part.from_function_response(
            name="get_exchange_rate",
            response={
                "content": api_response.text,
            }
        )
    ]),
    ],
    tools=[exchange_rate_tool],
)


response.candidates[0].content.parts[0].text

Una volta restituita la risposta della funzione al modello, quest'ultimo risponderà al prompt dell'utente insieme alle informazioni pertinenti della risposta dell'API.

The exchange rate from Australian dollars to Swedish krona on January 16, 2024,
is 1 Australian dollar is equal to 6.8663 Swedish krona.

So, 500 Australian dollars would be worth 500 * 6.8663 = 3,433.15 Swedish krona.

11. Visualizza l'esempio di codice completo

A questo punto, puoi inserire il codice Python in un'API di backend utilizzando un servizio Cloud Run, una Cloud Function o un altro servizio cloud ed eseguire il deployment di un'app frontend che utilizza questa API di backend per eseguire query sui modelli e chiamate API.

Ecco l'esempio di codice completo per la nostra soluzione finale:

import requests
from vertexai.generative_models import (
    Content,
    FunctionDeclaration,
    GenerativeModel,
    Part,
    Tool,
)

model = GenerativeModel("gemini-1.5-pro-001")

get_exchange_rate_func = FunctionDeclaration(
    name="get_exchange_rate",
    description="Get the exchange rate for currencies between countries",
    parameters={
    "type": "object",
    "properties": {
        "currency_date": {
            "type": "string",
            "description": "A date that must always be in YYYY-MM-DD format or the value 'latest' if a time period is not specified"
        },
        "currency_from": {
            "type": "string",
            "description": "The currency to convert from in ISO 4217 format"
        },
        "currency_to": {
            "type": "string",
            "description": "The currency to convert to in ISO 4217 format"
        }
    },
         "required": [
            "currency_from",
            "currency_date",
      ]
  },
)

exchange_rate_tool = Tool(
    function_declarations=[get_exchange_rate_func],
)

prompt = """What is the exchange rate from Australian dollars to Swedish krona?
How much is 500 Australian dollars worth in Swedish krona?"""

response = model.generate_content(
    prompt,
    tools=[exchange_rate_tool],
)

response.candidates[0].content

params = {}
for key, value in response.candidates[0].content.parts[0].function_call.args.items():
    params[key[9:]] = value
params

import requests
url = f"https://api.frankfurter.app/{params['date']}"
api_response = requests.get(url, params=params)
api_response.text

response = model.generate_content(
    [
    Content(role="user", parts=[
        Part.from_text(prompt + """Give your answer in steps with lots of detail
            and context, including the exchange rate and date."""),
    ]),
    Content(role="function", parts=[
        Part.from_dict({
            "function_call": {
                "name": "get_exchange_rate",
            }
        })
    ]),
    Content(role="function", parts=[
        Part.from_function_response(
            name="get_exchange_rate",
            response={
                "content": api_response.text,
            }
        )
    ]),
    ],
    tools=[exchange_rate_tool],
)


response.candidates[0].content.parts[0].text

In questa implementazione, abbiamo utilizzato due richieste al modello generativo: una richiesta per generare una chiamata di funzione e un'altra richiesta per restituire la risposta della funzione. Tieni presente che questo è solo uno dei metodi per gestire le chiamate di funzioni e le risposte delle funzioni con Gemini. Puoi anche effettuare chiamate di funzioni aggiuntive per ottenere maggiori informazioni per la tua query o utilizzare la chiamata di funzioni con metodi di chat e asincroni.

Per altri esempi di codice, consulta il notebook di esempio per la chiamata di funzioni in Gemini.

12. Complimenti

Utilizzando la chiamata di funzione in Gemini, hai creato correttamente una pipeline di AI generativa che utilizza l'API Vertex AI Gemini e Python. Gli utenti possono chiedere informazioni sui tassi di cambio e il sistema recupererà i dati più recenti da un'API esterna e risponderà con una risposta.

Dato un prompt di un utente finale, la chiamata di funzione in Gemini si occupa di selezionare la funzione appropriata, estrarre i parametri dal prompt e restituire un oggetto dati strutturato per effettuare una chiamata API esterna.

La progettazione della chiamata di funzione in Gemini ha lo scopo di offrirti il meglio di entrambi i mondi per l'estrazione deterministica dei parametri, lasciando al modello generativo il riepilogo e la creazione di contenuti. Puoi provare altre API e prompt nella pipeline ed esplorare le altre funzionalità disponibili relative all'API Vertex AI Gemini.

Interfaccia API

Esegui la pulizia

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo codelab, puoi eseguire la seguente pulizia:

Scopri di più

Continua a scoprire l'AI conversazionale e l'AI generativa con queste guide e risorse:

Licenza

Questo lavoro è concesso in licenza ai sensi di una licenza Creative Commons Attribution 2.0 Generic.