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, l'appel de fonction vous aide à 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 aux modèles Gemini des descriptions de fonctions. Il s'agit de fonctions que vous écrivez dans le langage de votre application (il ne s'agit pas de fonctions Google Cloud Functions). 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 page Présentation de l'appel de fonction pour en savoir plus. Vous pouvez également essayer cette fonctionnalité dans Google Colab ou consulter l'exemple de code dans le dépôt Livret de recettes de l'API Gemini.

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

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

Paramètres Type Obligatoire Description
brightness Nombre oui Niveau de luminosité compris entre 0 et 100. Le zéro est désactivé et la valeur 100 correspond à la luminosité maximale.
colorTemperature chaîne oui Température des couleurs du luminaire, qui peut être daylight, cool ou warm.

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

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

Ce tutoriel 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 aux paramètres de l'API afin de contrôler la luminosité et les valeurs de température des couleurs d'une lumière.

Avant de commencer: configurer 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 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 l'application. L'API Gemini n'appelle pas cette fonction directement. Vous pouvez donc contrôler quand et comment 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 renvoie simplement 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 des fonctions et des paramètres. Le modèle génératif utilise ces informations pour déterminer la fonction à sélectionner et comment fournir des valeurs pour les paramètres de l'appel de fonction.

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

Si vous souhaitez utiliser l'appel de fonction avec un modèle, vous devez déclarer vos fonctions lorsque vous initialisez l'objet de modèle. Pour déclarer des fonctions, définissez 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 envoyer une requête au modèle avec la fonction définie. Vous devez utiliser l'appel de fonction à l'aide des invites de chat (sendMessage()), car il est généralement utile de disposer 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 de la conversation à votre place. Vous pouvez utiliser enable_automatic_function_calling pour que le SDK se charge automatiquement

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

Appel de fonction parallèle

Outre 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éfinir 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 qui pourrait 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 affichés reflète un appel de fonction unique demandé par le modèle. Pour renvoyer les résultats, incluez les réponses dans le même ordre que celui demandé.

# 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'un appel de fonction

L'extraction automatique du schéma des fonctions Python ne fonctionne pas dans tous les cas. Par exemple, elle ne gère pas les cas où vous décrivez les champs d'un objet de dictionnaire imbriqué, mais l'API le permet. 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 donne accès aux types de bas niveau, ce qui vous donne un contrôle total.

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

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

Cette commande renvoie la liste des objets genai.protos.Tool qui seront envoyés à l'API. Si le format imprimé ne vous est pas familier, cela signifie qu'il s'agit de classes de tampons de protocole Google. 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 pour la même fonction de multiplication écrite à l'aide des classes genai.protos. Notez que ces classes décrivent simplement la fonction de l'API et n'incluent pas d'implémentation de celle-ci. Son utilisation ne fonctionne donc pas avec l'appel de fonction automatique, 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']
        )
      )
    ])

De manière équivalente, vous pouvez décrire cela comme un objet compatible 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 tous les 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 appelant la fonction multiply du calculateur:

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