Gemini API: Funktionsaufruf mit Python

Auf ai.google.dev ansehen In Google Colab ausführen Quelle auf GitHub ansehen

Sie können Gemini-Modelle mit Funktionsbeschreibungen bereitstellen. Möglicherweise fordert das Modell Sie auf, eine Funktion aufzurufen und das Ergebnis zurückzusenden, um das Modell bei der Verarbeitung Ihrer Abfrage zu unterstützen.

Einrichtung

Python SDK installieren

Das Python SDK für die Gemini API ist im Paket google-generativeai enthalten. Installieren Sie die Abhängigkeit mit „Pip“:

pip install -U -q google-generativeai

Pakete importieren

Importieren Sie die erforderlichen Pakete.

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))

API-Schlüssel einrichten

Bevor Sie die Gemini API verwenden können, müssen Sie zuerst einen API-Schlüssel abrufen. Falls Sie noch keinen Schlüssel haben, können Sie mit einem Klick in Google AI Studio einen Schlüssel erstellen.

API-Schlüssel anfordern

Fügen Sie den Schlüssel in Colab im linken Bereich unter „🚀“ zum Secret-Manager hinzu. Geben Sie ihr den Namen API_KEY.

Sobald Sie den API-Schlüssel haben, übergeben Sie ihn an das SDK. Dafür haben Sie die beiden folgenden Möglichkeiten:

  • Fügen Sie den Schlüssel in die Umgebungsvariable GOOGLE_API_KEY ein. Das SDK übernimmt ihn dort automatisch.
  • Schlüssel an genai.configure(api_key=...) übergeben
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)

Grundlagen der Funktionen

Beim Erstellen eines genai.GenerativeModel können Sie eine Liste von Funktionen an das Argument tools übergeben.

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>,
)

Wir empfehlen den Funktionsaufruf über die Chat-Oberfläche. Der Hauptgrund ist, dass FunctionCalls so gut in die Multi-Turn-Struktur des Chats passen.

chat = model.start_chat(enable_automatic_function_calling=True)

Wenn automatische Funktionsaufrufe aktiviert sind, ruft chat.send_message die Funktion automatisch auf, wenn das Modell dies anfordert.

Es scheint einfach eine Textantwort zurückzugeben, die die richtige Antwort enthält:

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

Im ChatSession.history sehen Sie die Abfolge der Ereignisse:

  1. Sie haben die Frage gesendet.
  2. Das Modell hat mit glm.FunctionCall geantwortet.
  3. genai.ChatSession hat die Funktion lokal ausgeführt und ein glm.FunctionResponse-Element an das Modell zurückgesendet.
  4. Das Modell hat die Funktionsausgabe in der Antwort verwendet.
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.'}
--------------------------------------------------------------------------------

Im Allgemeinen sieht das Zustandsdiagramm so aus:

Das Modell kann immer mit Text oder einem Funktionsaufruf antworten. Wenn das Modell einen FunctionsCall sendet, muss der Nutzer mit einer FunctionResponse antworten

Das Modell kann mit mehreren Funktionsaufrufen antworten, bevor eine Textantwort zurückgegeben wird, und Funktionsaufrufe vor der Textantwort.

Dies wurde zwar automatisch abgewickelt, aber wenn Sie mehr Kontrolle benötigen, haben Sie folgende Möglichkeiten:

  • Behalten Sie den standardmäßigen enable_automatic_function_calling=False bei und verarbeiten Sie die glm.FunctionCall-Antworten selbst.
  • Alternativ können Sie GenerativeModel.generate_content verwenden. Dort müssen Sie auch das Chatprotokoll verwalten.

[Optional] Low-Level-Zugriff

Die automatische Extraktion des Schemas aus Python-Funktionen funktioniert nicht in allen Fällen. Beispiel: Sie ist nicht für Fälle geeignet, in denen Sie die Felder eines verschachtelten Wörterbuchobjekts beschreiben, aber die API unterstützt dies. Die API kann folgende Typen beschreiben:

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

Die google.ai.generativelanguage-Clientbibliothek bietet Zugriff auf die untergeordneten Typen, sodass Sie vollständige Kontrolle haben.

import google.ai.generativelanguage as glm

Werfen Sie zuerst einen Blick auf das Attribut _tools des Modells. Hier sehen Sie, wie es die Funktion(en) beschreibt, die Sie an das Modell übergeben haben:

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"
   }
 }]

Dadurch wird die Liste der glm.Tool-Objekte zurückgegeben, die an die API gesendet werden würden. Wenn das gedruckte Format nicht vertraut ist, liegt das daran, dass dies die protobuf-Klassen von Google sind. Jedes glm.Tool (in diesem Fall 1) enthält eine Liste von glm.FunctionDeclarations, die eine Funktion und ihre Argumente beschreiben.

Hier ist eine Deklaration für dieselbe Multiplikationsfunktion, die mithilfe der glm-Klassen geschrieben wurde.

Beachten Sie, dass diese Klassen nur die Funktion für das API beschreiben, sie keine Implementierung davon enthalten. Die Verwendung dieser Methode funktioniert also nicht mit automatischen Funktionsaufrufen, Funktionen erfordern jedoch nicht immer eine Implementierung.

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']
        )
      )
    ])

Entsprechend können Sie dies auch als JSON-kompatibles Objekt beschreiben:

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 beiden Fällen übergeben Sie eine Darstellung von glm.Tool oder eine Liste von Tools an

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

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

Wie zuvor, gibt das Modell einen glm.FunctionCall zurück, der die multiply-Funktion des Rechners aufruft:

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
]

Führen Sie die Funktion selbst aus:

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

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

Senden Sie das Ergebnis an das Modell, um die Unterhaltung fortzusetzen:

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

Zusammenfassung

Im SDK werden grundlegende Funktionsaufrufe unterstützt. Denken Sie daran, dass der Chat-Modus aufgrund der natürlichen Hin- und Her-Struktur einfacher zu verwalten ist. Sie sind dafür verantwortlich, die Funktionen aufzurufen und Ergebnisse zurück an das Modell zu senden, damit es eine Textantwort erzeugen kann.