API Gemini: chiamate di funzioni con Python

Visualizza su ai.google.dev Esegui in Google Colab Visualizza il codice sorgente su GitHub

Puoi fornire ai modelli Gemini le descrizioni delle funzioni. Il modello potrebbe chiederti di chiamare una funzione e inviare il risultato per aiutarlo a gestire la query.

Configurazione

Installa l'SDK Python

L'SDK Python per l'API Gemini è contenuto nel pacchetto google-generativeai. Installa la dipendenza utilizzando pip:

pip install -U -q google-generativeai

Importa pacchetti

Importa i pacchetti necessari.

import pathlib
import textwrap
import time

import google.generativeai as genai


from IPython import display
from IPython.display import Markdown

def to_markdown(text):
  text = text.replace('•', '  *')
  return Markdown(textwrap.indent(text, '> ', predicate=lambda _: True))

Configura la chiave API

Prima di poter utilizzare l'API Gemini, devi ottenere una chiave API. Se non ne hai già una, crea una chiave con un clic in Google AI Studio.

Ottenere una chiave API

In Colab, aggiungi la chiave al gestore dei secret nella sezione "☁" del riquadro a sinistra. Assegna il nome API_KEY.

Una volta ottenuta la chiave API, passala all'SDK. A tale scopo, puoi procedere in uno dei due seguenti modi:

  • Inserisci la chiave nella variabile di ambiente GOOGLE_API_KEY (l'SDK la acquisirà automaticamente da lì).
  • Passa la chiave a genai.configure(api_key=...)
try:
    # Used to securely store your API key
    from google.colab import userdata

    # Or use `os.getenv('API_KEY')` to fetch an environment variable.
    GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')
except ImportError:
    import os
    GOOGLE_API_KEY = os.environ['GOOGLE_API_KEY']

genai.configure(api_key=GOOGLE_API_KEY)

Nozioni di base sulle funzioni

Puoi passare un elenco di funzioni all'argomento tools durante la creazione di un genai.GenerativeModel.

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

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

model
genai.GenerativeModel(
    model_name='models/gemini-1.0-pro',
    generation_config={},
    safety_settings={},
    tools=<google.generativeai.types.content_types.FunctionLibrary object at 0x10e73fe90>,
)

Il modo consigliato per utilizzare le chiamate di funzione è tramite l'interfaccia di chat. Il motivo principale è che FunctionCalls si adatta perfettamente alla struttura multi-turno della chat.

chat = model.start_chat(enable_automatic_function_calling=True)

Quando le chiamate di funzione automatiche sono attivate, chat.send_message chiama automaticamente la tua funzione se il modello lo richiede.

Sembra che restituisca semplicemente un messaggio di risposta contenente la risposta corretta:

response = chat.send_message('I have 57 cats, each owns 44 mittens, how many mittens is that in total?')
response.text
'The total number of mittens is 2508.'
57*44
2508

Se guardi nella ChatSession.history puoi vedere la sequenza di eventi:

  1. Hai inviato la domanda.
  2. Il modello ha risposto con glm.FunctionCall.
  3. genai.ChatSession ha eseguito la funzione localmente e ha inviato al modello un glm.FunctionResponse.
  4. Il modello ha utilizzato l'output della funzione nella risposta.
for content in chat.history:
    part = content.parts[0]
    print(content.role, "->", type(part).to_dict(part))
    print('-'*80)
user -> {'text': 'I have 57 cats, each owns 44 mittens, how many mittens is that in total?'}
--------------------------------------------------------------------------------
model -> {'function_call': {'name': 'multiply', 'args': {'a': 57.0, 'b': 44.0} } }
--------------------------------------------------------------------------------
user -> {'function_response': {'name': 'multiply', 'response': {'result': 2508.0} } }
--------------------------------------------------------------------------------
model -> {'text': 'The total number of mittens is 2508.'}
--------------------------------------------------------------------------------

In generale, il diagramma di stato è:

Il modello può sempre rispondere con un testo o una funzione FunctionCall. Se il modello invia una funzione FunctionCall, l&#39;utente deve rispondere con una FunctionResponse

Il modello può rispondere con più chiamate di funzione prima di restituire una risposta testuale, e le chiamate di funzione precedeno la risposta testuale.

Sebbene il tutto sia stato gestito automaticamente, se hai bisogno di un maggiore controllo puoi:

  • Lascia il valore predefinito enable_automatic_function_calling=False ed elabora autonomamente le risposte glm.FunctionCall.
  • In alternativa, utilizza GenerativeModel.generate_content, dove devi gestire anche la cronologia chat.

[Facoltativo] Accesso di basso livello

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 operazione. L'API è in grado di descrivere tutti i seguenti tipi:

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

La libreria client di google.ai.generativelanguage consente di accedere ai tipi di basso livello, dandoti il pieno controllo.

import google.ai.generativelanguage as glm

Prima di tutto all'interno dell'attributo _tools del modello, puoi vedere come descrive la funzione o le funzioni che hai trasmesso al modello:

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

model = genai.GenerativeModel(model_name='gemini-1.0-pro',
                             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 di glm.Tool oggetti che verranno inviati all'API. Se il formato stampato non conosce il formato, si tratta di classi protobuf di Google. Ogni glm.Tool (1 in questo caso) contiene un elenco di glm.FunctionDeclarations, che descrivono una funzione e i relativi argomenti.

Ecco una dichiarazione per la stessa funzione di moltiplicazione scritta utilizzando le classi glm.

Tieni presente che queste classi descrivono solo la funzione per l'API e non ne includono un'implementazione. Quindi, l'utilizzo di questa funzione non funziona con le chiamate di funzione automatiche, ma non sempre le funzioni richiedono un'implementazione.

calculator = glm.Tool(
    function_declarations=[
      glm.FunctionDeclaration(
        name='multiply',
        description="Returns the product of two numbers.",
        parameters=glm.Schema(
            type=glm.Type.OBJECT,
            properties={
                'a':glm.Schema(type=glm.Type.NUMBER),
                'b':glm.Schema(type=glm.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']} }]}
glm.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 glm.Tool o di un elenco di strumenti a

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

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

Come prima che il modello restituisca un glm.FunctionCall che richiama 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(
    glm.Content(
    parts=[glm.Part(
        function_response = glm.FunctionResponse(
          name='multiply',
          response={'result': result}))]))

Riepilogo

Le chiamate di funzione di base sono supportate nell'SDK. Ricorda che è più facile da gestire con la modalità chat, a causa della naturale struttura degli scambi. Sta a te chiamare le funzioni e inviare i risultati al modello in modo che possa produrre una risposta testuale.