Gemini API: wywoływanie funkcji w Pythonie

Zobacz na ai.google.dev Uruchom w Google Colab Wyświetl źródło na GitHubie

Modelom Gemini możesz podawać opisy funkcji. Model może poprosić Cię o wywołanie funkcji i odesłanie wyniku, aby model mógł lepiej obsłużyć zapytanie.

Konfiguracja

Zainstaluj pakiet SDK Pythona

Pakiet SDK Pythona dla interfejsu Gemini API znajduje się w pakiecie google-generativeai. Zainstaluj zależność za pomocą narzędzia pip:

pip install -U -q google-generativeai

Importowanie pakietów

Zaimportuj niezbędne pakiety.

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

Konfigurowanie klucza interfejsu API

Aby korzystać z interfejsu Gemini API, musisz najpierw uzyskać klucz interfejsu API. Jeśli nie masz jeszcze klucza, utwórz go jednym kliknięciem w Google AI Studio.

Uzyskiwanie klucza interfejsu API

W Colab dodaj klucz do menedżera obiektów tajnych w sekcji „🔑” w panelu po lewej stronie. Nadaj mu nazwę API_KEY.

Przekaż klucz interfejsu API do pakietu SDK. Można to zrobić na dwa sposoby:

  • Umieść klucz w zmiennej środowiskowej GOOGLE_API_KEY (pakiet SDK automatycznie go stamtąd zabierze).
  • Przekaż klucz do: 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)

Podstawowe informacje o funkcjach

Listę funkcji możesz przekazać do argumentu tools podczas tworzenia 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>,
)

Zalecana metoda korzystania z wywołania funkcji to interfejs czatu. Głównym powodem jest to, że usługa FunctionCalls dobrze wpasowuje się w wieloetapową strukturę czatu.

chat = model.start_chat(enable_automatic_function_calling=True)

Przy włączonym automatycznym wywoływaniu funkcji chat.send_message automatycznie wywołuje Twoją funkcję, jeśli model o nie poprosi.

Wygląda na to, że zwracany jest komunikat zawierający poprawną odpowiedź:

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

ChatSession.history zawiera sekwencję zdarzeń:

  1. Wysłałeś pytanie.
  2. Model przesłał odpowiedź glm.FunctionCall.
  3. genai.ChatSession uruchomił funkcję lokalnie i odesłał model glm.FunctionResponse.
  4. Model użył w odpowiedzi danych wyjściowych funkcji.
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.'}
--------------------------------------------------------------------------------

Ogólnie diagram stanu wygląda tak:

Model zawsze może odpowiedzieć przy użyciu tekstu lub funkcji FunctionCall. Jeśli model wysyła wywołanie funkcji Function, użytkownik musi odpowiedzieć za pomocą obiektu FunctionResponse

Przed zwróceniem odpowiedzi tekstowej model może odpowiedzieć za pomocą wielu wywołań funkcji, a wywołania funkcji mają miejsce przed odpowiedzią tekstową.

Wszystko odbywało się automatycznie, ale jeśli chcesz mieć większą kontrolę, możesz:

  • Pozostaw domyślną wartość enable_automatic_function_calling=False i samodzielnie przetwarzaj odpowiedzi glm.FunctionCall.
  • Możesz też skorzystać z GenerativeModel.generate_content, gdzie musisz również zarządzać historią czatu.

[Opcjonalnie] Dostęp niskiego poziomu

Automatyczne wyodrębnianie schematu z funkcji Pythona nie we wszystkich przypadkach działa. Na przykład: nie obsługuje przypadków, gdy opisujesz pola zagnieżdżonego obiektu słownika, ale interfejs API to umożliwia. Interfejs API może opisywać każdy z następujących typów:

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

Biblioteka klienta google.ai.generativelanguage zapewnia dostęp do typów niskiego poziomu, co daje Ci pełną kontrolę.

import google.ai.generativelanguage as glm

Najpierw rzut oka na atrybut _tools modelu możesz zobaczyć, jak opisuje on funkcje przekazane do modelu:

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

Zwraca listę obiektów glm.Tool, które zostałyby wysłane do interfejsu API. Jeśli nie znasz formatu drukowanego, oznacza to, że są to klasy protokołu Google. Każdy element glm.Tool (w tym przypadku 1) zawiera listę obiektów glm.FunctionDeclarations, która opisuje funkcję i jej argumenty.

Oto deklaracja dla tej samej funkcji mnożenia zapisanej za pomocą klas glm.

Pamiętaj, że te klasy opisują tylko funkcję interfejsu API, a nie zawierają jego implementacji. Używanie tej metody nie działa w przypadku automatycznego wywoływania funkcji, ale funkcje nie zawsze wymagają implementacji.

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

Możesz go również opisać jako obiekt zgodny z formatem 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"
  }
}

W obu przypadkach przekazujesz reprezentację obiektu glm.Tool lub listy narzędzi do

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

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

Podobnie jak przed zwróceniem funkcji glm.FunctionCall, która wywołuje funkcję multiply kalkulatora:

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
]

Wykonaj funkcję samodzielnie:

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

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

Aby kontynuować rozmowę, wyślij wynik do modelu:

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

Podsumowanie

Pakiet SDK obsługuje podstawowe wywoływanie funkcji. Pamiętaj, że łatwiej jest nim zarządzać w trybie czatu dzięki naturalnej strukturze przechodzenia z powrotem i z powrotem. To Ty odpowiadasz za wywoływanie funkcji i wysyłanie wyników z powrotem do modelu, aby mógł wygenerować odpowiedź tekstową.