Tutoriel sur l'appel de fonction

L'appel de fonction vous permet d'obtenir plus facilement des sorties de données structurées à partir de modèles génératifs. Vous pouvez ensuite utiliser ces sorties pour appeler d'autres API et renvoyer les données de réponse pertinentes au modèle. En d'autres termes, les appels de fonction vous aident à connecter des modèles génératifs à des systèmes externes afin que le contenu généré inclue les informations les plus récentes et les plus précises.

Vous pouvez fournir des descriptions de fonctions aux modèles Gemini. Il s'agit de fonctions que vous écrivez dans la langue de votre application (c'est-à-dire qu'elles ne sont pas des fonctions Google Cloud). Le modèle peut vous demander d'appeler une fonction et de renvoyer le résultat pour l'aider à gérer votre requête.

Si vous ne l'avez pas déjà fait, consultez la section Présentation de l'appel de fonction pour en savoir plus. Vous pouvez également tester cette fonctionnalité dans Google Colab ou consulter l'exemple de code dans le dépôt Cookbook de l'API Gemini.

Exemple d'API pour le contrôle de l'éclairage

Imaginons que vous disposiez d'un système de contrôle d'éclairage de base avec une interface de programmation d'application (API) et que vous souhaitiez permettre aux utilisateurs de contrôler les lumières à l'aide de requêtes textuelles simples. Vous pouvez utiliser la fonctionnalité d'appel de fonction pour interpréter les demandes de modification de l'éclairage des utilisateurs et les traduire en appels d'API pour définir les valeurs d'éclairage. Ce système de contrôle d'éclairage hypothétique vous permet de contrôler la luminosité de la lumière et sa température de couleur, définies comme deux paramètres distincts:

Paramètre Type Obligatoire Description
brightness Nombre oui Niveau d'éclairage compris entre 0 et 100. La valeur 0 correspond à l'arrêt et la valeur 100 à la luminosité maximale.
colorTemperature chaîne oui Température de couleur de l'appareil d'éclairage, qui peut être daylight, cool ou warm.

Par souci de simplicité, ce système d'éclairage imaginaire ne comporte qu'une seule ampoule. L'utilisateur n'a donc pas besoin de spécifier de pièce ni d'emplacement. Voici un exemple de requête JSON que vous pouvez envoyer à l'API de contrôle de l'éclairage pour définir le niveau d'éclairage sur 50 % à l'aide de la température de couleur de la lumière du jour:

{
  "brightness": "50",
  "colorTemperature": "daylight"
}

Ce tutoriel vous explique comment configurer un appel de fonction pour l'API Gemini afin d'interpréter les requêtes d'éclairage des utilisateurs et de les mapper sur les paramètres de l'API pour contrôler les valeurs de luminosité et de température de couleur d'une lumière.

Avant de commencer: configurez votre projet et votre clé API

Avant d'appeler l'API Gemini, vous devez configurer votre projet et votre clé API.

Définir une fonction d'API

Créez une fonction qui envoie une requête API. Cette fonction doit être définie dans le code de votre application, mais elle peut appeler des services ou des API en dehors de votre application. L'API Gemini n'appelle pas directement cette fonction. Vous pouvez donc contrôler comment et quand cette fonction est exécutée via le code de votre application. À des fins de démonstration, ce tutoriel définit une fonction d'API fictive qui ne renvoie que les valeurs d'éclairage demandées:

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
    }

Lorsque vous créez une fonction à utiliser dans un appel de fonction par le modèle, vous devez inclure autant de détails que possible dans les descriptions de la fonction et des paramètres. Le modèle génératif utilise ces informations pour déterminer quelle fonction sélectionner et comment fournir des valeurs pour les paramètres dans l'appel de fonction.

Déclarer des fonctions lors de l'initialisation du modèle

Lorsque vous souhaitez utiliser l'appel de fonction avec un modèle, vous devez déclarer vos fonctions lorsque vous initialisez l'objet modèle. Vous déclarez des fonctions en définissant le paramètre tools du modèle:

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

Générer un appel de fonction

Une fois que vous avez initialisé le modèle avec vos déclarations de fonction, vous pouvez l'inviter avec la fonction définie. Vous devez utiliser l'appel de fonction à l'aide d'une requête de chat (sendMessage()), car l'appel de fonction bénéficie généralement du contexte des requêtes et réponses précédentes.

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

L'objet ChatSession du SDK Python simplifie la gestion des sessions de chat en gérant l'historique des conversations à votre place. Vous pouvez utiliser enable_automatic_function_calling pour que le SDK appelle automatiquement la fonction.

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

Appels de fonction en parallèle

En plus de l'appel de fonction de base décrit ci-dessus, vous pouvez également appeler plusieurs fonctions en un seul tour. Cette section présente un exemple d'utilisation de l'appel de fonction parallèle.

Définissez les outils.

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

Appelez maintenant le modèle avec une instruction pouvant utiliser tous les outils spécifiés.

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

Chacun des résultats imprimés reflète un seul appel de fonction que le modèle a demandé. Pour renvoyer les résultats, incluez les réponses dans l'ordre dans lequel elles ont été demandées.

# 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! 🕺💃

Mappage des types de données d'appel de fonction

L'extraction automatique de schémas à partir de fonctions Python ne fonctionne pas dans tous les cas. Par exemple, il ne gère pas les cas où vous décrivez les champs d'un objet de dictionnaire imbriqué, mais l'API le fait. L'API peut décrire l'un des types suivants:

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

La bibliothèque cliente google.ai.generativelanguage vous permet d'accéder aux types de bas niveau et de contrôler entièrement votre application.

Examinez d'abord l'attribut _tools du modèle. Vous pouvez voir comment il décrit la ou les fonctions que vous lui avez transmises:

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

Cela renvoie la liste des objets genai.protos.Tool qui seraient envoyés à l'API. Si le format imprimé n'est pas familier, il s'agit de classes Google Protobuf. Chaque genai.protos.Tool (1 dans ce cas) contient une liste de genai.protos.FunctionDeclarations, qui décrivent une fonction et ses arguments.

Voici une déclaration de la même fonction de multiplication écrite à l'aide des classes genai.protos. Notez que ces classes ne décrivent que la fonction de l'API. Elles n'incluent pas d'implémentation. Par conséquent, cette méthode ne fonctionne pas avec l'appel automatique des fonctions, mais les fonctions n'ont pas toujours besoin d'une implémentation.

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

Vous pouvez également décrire cela comme un objet compatible avec le format 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"
  }
}

Dans les deux cas, vous transmettez une représentation d'un genai.protos.Tool ou d'une liste d'outils à

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

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

Comme précédemment, le modèle renvoie un genai.protos.FunctionCall qui appelle la fonction multiply de la calculatrice:

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
]

Exécutez la fonction vous-même:

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

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

Envoyez le résultat au modèle pour poursuivre la conversation:

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