Interagir avec les API à l'aide de l'appel de fonction dans Gemini

1. Présentation

Qu'est-ce que l'appel de fonction dans Gemini ?

L'API Gemini Vertex AI est une famille de modèles d'IA générative développés par Google DeepMind, et conçus pour les cas d'utilisation multimodaux. L'appel de fonction est une fonctionnalité des modèles Gemini qui permet aux développeurs d'obtenir plus facilement des sorties de données structurées à partir de modèles génératifs.

Les développeurs peuvent 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 vos modèles génératifs à des systèmes externes afin que le contenu généré comprenne les informations les plus récentes et les plus précises.

Fonctionnement des appels de fonction

Les fonctions sont décrites à l'aide de déclarations de fonction, ce qui aide le modèle génératif à comprendre l'objectif et les paramètres d'une fonction. Une fois que vous avez transmis des déclarations de fonction dans une requête à un modèle génératif, celui-ci renvoie un objet structuré qui inclut les noms des fonctions pertinentes et leurs arguments en fonction de la requête de l'utilisateur. Notez qu'avec l'appel de fonction, le modèle n'appelle pas réellement la fonction. À la place, vous pouvez utiliser la fonction et les paramètres renvoyés pour appeler la fonction dans le langage, la bibliothèque ou le framework de votre choix.

Interface API

Ce que vous allez faire

Dans cet atelier de programmation, vous allez créer un pipeline d'IA générative à l'aide de l'API Gemini Vertex AI et de Python. À l'aide de votre application, les utilisateurs peuvent poser des questions sur les taux de change. Le système extrait les dernières données d'une API externe et fournit la réponse à l'utilisateur.

Points abordés

  • Interagir avec le modèle Gemini à l'aide de la bibliothèque cliente Python
  • Définir une déclaration de fonction et l'enregistrer en tant qu'outil
  • Appeler Gemini et obtenir une réponse à un appel de fonction
  • Renvoyer la réponse de la fonction à Gemini et répondre à l'utilisateur

Prérequis

2. Préparation

Avant de pouvoir utiliser l'appel de fonction dans Gemini, vous devez activer l'API Vertex AI et installer la dernière version de la bibliothèque cliente Python Vertex AI.

Activer l'API Vertex AI

Pour activer l'API Vertex AI, procédez comme suit:

  1. Dans votre navigateur, accédez à la page Informations sur le service de l'API Vertex AI.
  2. Cliquez sur le bouton Activer pour activer l'API Vertex AI dans votre projet Google Cloud.

Installer la bibliothèque cliente Python pour Vertex AI

Pour installer les bibliothèques clientes Python pour Vertex AI, procédez comme suit:

  1. Ouvrez un terminal dans votre environnement de développement.
  2. Vérifiez que vous disposez d'un environnement de développement Python valide et consultez ces consignes si nécessaire.
  3. Exécutez la commande suivante pour installer la bibliothèque cliente Python pour Vertex AI:
    pip install --upgrade google-cloud-aiplatform
    
  4. Si vous utilisez un environnement de notebook, vous devrez peut-être redémarrer votre environnement d'exécution/noyau pour utiliser les packages que vous venez d'installer.

Vous êtes maintenant prêt à utiliser l'API Vertex AI.

3. Comprendre le problème

Avez-vous déjà interagi avec un grand modèle de langage ou un modèle d'IA générative, et leur poser des questions sur des informations en temps réel ou actuelles, pour obtenir une réponse contenant des informations obsolètes ou inexactes ?

Essayons maintenant ! Tout d'abord, nous allons importer les packages Python pertinents et initialiser le modèle Gemini. Vous pouvez exécuter le code suivant dans un environnement de développement Python tel que Colab ou Colab Enterprise et en installant la dernière version du SDK Vertex AI pour Python:

import vertexai
from vertexai.generative_models import GenerativeModel
model = GenerativeModel("gemini-1.5-pro-001")

Maintenant, posons une question sur le taux de change pour différentes devises aujourd'hui:

response = model.generate_content(
    "What's the exchange rate for euros to dollars today?"
)
print(response.text)

Le modèle devrait générer une réponse limitée ou obsolète semblable à celle-ci:

As an AI language model, I don't have access to real-time currency exchange
rates. However, as of my last update in September 2021, the approximate exchange
rate between euros (EUR) and US dollars (USD) was:

1 EUR ≈ 1.18 USD

Please note that currency exchange rates constantly fluctuate and can vary
depending on various factors such as economic conditions, supply and demand,
political events, and more. To obtain the most up-to-date and accurate exchange
rate, I recommend using a reliable currency converter or financial website that
provides live rates.

[...]

Si un utilisateur final reçoit ce type de réponse, il doit changer de contexte afin de rechercher les devises qui l'intéressent, d'extraire le dernier taux de change et d'effectuer lui-même toute conversion.

Idéalement, un pipeline de modèle génératif pourrait gérer l'ensemble ou une partie de ces tâches pour l'utilisateur. Dans la section suivante, vous allez essayer des solutions courantes pour obtenir des réponses structurées à partir de modèles génératifs afin d'appeler des systèmes externes.

4. Essayer des solutions de contournement courantes

Lorsque vous travaillez avec des modèles génératifs dans des cas où vous avez besoin d'informations à jour ou de données provenant de sources externes, vous pouvez appeler une API externe, puis transmettre les résultats au modèle génératif pour qu'il les utilise dans sa réponse.

Avant d'appeler un système externe, vous devez déterminer la fonction à utiliser, extraire les paramètres pertinents de l'utilisateur et les placer dans un objet de données structurées. Cela implique généralement une ingénierie des requêtes exhaustive pour forcer le modèle génératif à générer des données structurées valides.

Reprenons la question posée dans la section précédente et ajoutons des instructions pour le modèle. Essayez d'envoyer la requête suivante au modèle Gemini:

user_prompt = "What's the exchange rate from euros to US dollars today?"

response = model.generate_content("""
Your task is to extract parameters from the user's input and return it as a
structured JSON payload. The user will ask about the exchange rate and which
currency they are converting from and converting to.

User input: {user_prompt}

Please extract the currencies as parameters and put them in a JSON object.
""".format(user_prompt=user_prompt))
print(response.text)

Ces résultats sont la réponse textuelle suivante, qui n'est pas un fichier JSON valide et il nous sera difficile de la traiter:

```json
{
  "currency_from": "euros",
  "currency_to": "US dollars"
}
```

Plus précisément, la première et la dernière ligne de la réponse textuelle comprennent des accents graves pour délimiter le bloc de code, la première ligne inclut un spécificateur de langue et les valeurs de l'objet JSON ne correspondent pas aux abréviations de devises standards à trois lettres qu'une API de change de devises attendrait comme paramètres d'entrée.

Nous pourrions essayer d'utiliser Python pour post-traiter ce texte en JSON valide et un dictionnaire, ajouter des instructions à la requête, fournir un ou plusieurs exemples de sortie souhaitée, affiner le modèle ou effectuer un autre appel au modèle génératif en lui demandant de nettoyer le JSON.

Mais il existe une méthode plus déterministe ! Découvrons comment utiliser l'appel de fonction dans Gemini pour rechercher des informations dans des services externes et renvoyer des réponses pertinentes aux utilisateurs finaux.

5. Fonctionnement des appels de fonction

Avant de commencer à extraire des paramètres et à appeler des fonctions, examinons les étapes de l'appel de fonction et les composants utilisés lors de l'exécution.

Présentation de l'appel de fonction dans Gemini

Entrée utilisateur dans l'API Gemini

La requête de l'utilisateur est envoyée à l'API Gemini. Dans cet appel d'API au modèle Gemini, le développeur a défini une ou plusieurs déclarations de fonction dans un outil pour que le modèle Gemini sache quelles fonctions il peut appeler et comment les appeler.

L'API Gemini renvoie un appel de fonction

En fonction du contenu de l'entrée utilisateur et de la requête, Gemini renvoie une réponse à un appel de fonction avec des données structurées incluant le nom de la fonction à appeler et les paramètres correspondants à utiliser.

Envoyer une requête API

Ensuite, vous utiliserez le nom et les paramètres de la fonction pour envoyer une requête API afin de récupérer des informations à partir d'un système externe ou d'une API. Cette requête API et cette réponse sont implémentées par le développeur dans le code de l'application, et sont en dehors du champ d'application de l'API et du SDK Gemini. Par exemple, vous pouvez utiliser la bibliothèque requests en Python pour appeler une API REST et recevoir une réponse JSON. Vous pouvez également appeler la fonction en utilisant l'approche et la bibliothèque cliente de votre choix.

Renvoyer la réponse de l'API à Gemini

Enfin, vous transmettrez la réponse de l'API au modèle Gemini afin qu'il puisse générer une réponse à la requête initiale de l'utilisateur final ou appeler une autre réponse d'appel de fonction si le modèle Gemini détermine qu'il a besoin d'informations supplémentaires.

6. Choisissez votre API

Maintenant que vous connaissez le flux général et les étapes spécifiques de l'appel de fonction, vous allez créer un pipeline d'IA générative pour récupérer les derniers taux de change. Tout d'abord, nous devons sélectionner l'API à utiliser comme source d'informations.

Pour notre application de change, nous utiliserons l'API REST disponible à l'adresse https://www.frankfurter.app/ afin d'extraire les dernières informations sur les taux de change internationaux.

Pour interagir avec cette API REST, nous pouvons effectuer un appel d'API REST avec requests dans Python comme suit:

import requests
url = "https://api.frankfurter.app/latest"
response = requests.get(url)
response.text

ou une requête cURL telle que:

curl https://api.frankfurter.app/latest

qui renvoie une réponse semblable à celle-ci:

{
  "amount": 1,
  "base": "EUR",
  "date": "2023-12-20",
  "rates": {
    "AUD": 1.6186, "BGN": 1.9558, "BRL": 5.3287,
    "CAD": 1.4609, "CHF": 0.946, "CNY": 7.8121,
    "CZK": 24.538, "DKK": 7.4565, "GBP": 0.86555,
    "HKD": 8.5439, "HUF": 385.23, "IDR": 16994,
    "ILS": 3.9983, "INR": 91.06, "ISK": 150.3,
    "JPY": 157.12, "KRW": 1425.62, "MXN": 18.6867,
    "MYR": 5.0977, "NOK": 11.2895, "NZD": 1.7421,
    "PHP": 60.991, "PLN": 4.3413, "RON": 4.9699,
    "SEK": 11.129, "SGD": 1.4562, "THB": 38.252,
    "TRY": 31.883, "USD": 1.0944, "ZAR": 20.111
  }
}

Étant donné que l'appel de fonction dans Gemini n'effectue pas l'appel d'API externe à votre place, il n'existe pas de telles restrictions concernant le type d'API que vous utilisez. Vous pouvez utiliser un service Cloud Run, une fonction Cloud, une requête API adressée à un service Google Cloud ou n'importe quelle API REST externe.

7. Définir une fonction et un outil

Maintenant que vous avez sélectionné l'API REST à utiliser, nous pouvons définir une spécification d'API et enregistrer la fonction dans un outil.

Assurez-vous d'avoir installé la dernière version du SDK Vertex AI pour Python.

Ensuite, importez les modules nécessaires à partir du SDK Python et initialisez le modèle Gemini:

from vertexai.generative_models import (
    Content,
    FunctionDeclaration,
    GenerativeModel,
    Part,
    Tool,
)

model = GenerativeModel("gemini-1.5-pro-001")

Si nous revenons à l'API REST à l'adresse https://api.frankfurter.app/, nous constatons qu'elle accepte les paramètres d'entrée suivants:

Paramètre

Type

Description

from

Chaîne

Devise utilisée pour la conversion

to

Chaîne

Devise utilisée pour la conversion

date

Chaîne

Date pour laquelle récupérer le taux de change

Avec ces paramètres, une spécification OpenAPI partielle pour cette API REST au format YAML se présente comme suit:

openapi: 3.0.0
info:
  title: Frankfurter Exchange Rate API
  description: This API provides current and historical exchange rates
  version: 1.0.0
servers:
  - url: https://api.frankfurter.app
paths:
  /{date}:
    get:
      summary: Get the latest currency exchange rates.
      parameters:
        - name: date
          in: path
          description: Get currency rates for a specific date or 'latest' if a date is not specified
          required: true
          schema:
            type: string
        - name: from
          in: query
          description: The currency to convert from.
          required: true
          schema:
            type: string
        - name: to
          in: query
          description: The currency to convert to.
          schema:
            type: string

Enregistrons maintenant cela en tant que FunctionDeclaration à l'aide du SDK Python pour Gemini:

get_exchange_rate_func = FunctionDeclaration(
    name="get_exchange_rate",
    description="Get the exchange rate for currencies between countries",
    parameters={
    "type": "object",
    "properties": {
        "currency_date": {
            "type": "string",
            "description": "A date that must always be in YYYY-MM-DD format or the value 'latest' if a time period is not specified"
        },
        "currency_from": {
            "type": "string",
            "description": "The currency to convert from in ISO 4217 format"
        },
        "currency_to": {
            "type": "string",
            "description": "The currency to convert to in ISO 4217 format"
        }
    },
         "required": [
            "currency_from",
            "currency_date",
      ]
  },
)

Soyez aussi précis que possible dans les descriptions des fonctions et des paramètres, car le modèle génératif s'appuiera sur ces informations pour déterminer la fonction à sélectionner et comment renseigner les paramètres dans l'appel de fonction.

Enfin, vous allez définir un Tool qui inclut la déclaration de la fonction:

exchange_rate_tool = Tool(
    function_declarations=[get_exchange_rate_func],
)

Ici, vous utilisez une déclaration de fonction dans un outil, mais notez que vous pouvez enregistrer une ou plusieurs déclarations de fonction dans un outil, et le modèle sélectionnera la fonction appropriée à utiliser au moment de l'exécution. Consultez la documentation sur l'appel de fonction dans l'API Gemini pour en savoir plus sur FunctionDeclaration, Tool et les classes associées dans le SDK Gemini pour Python.

Vous avez terminé la configuration des définitions de votre fonction et de votre outil. Dans la section suivante, nous appellerons le modèle génératif avec cet outil et reviendrons à un appel de fonction que nous pourrons utiliser pour appeler l'API REST.

8. Générer un appel de fonction

Vous pouvez maintenant envoyer une requête au modèle génératif et inclure le tool que vous avez défini:

prompt = """What is the exchange rate from Australian dollars to Swedish krona?
How much is 500 Australian dollars worth in Swedish krona?"""

response = model.generate_content(
    prompt,
    tools=[exchange_rate_tool],
)

Examinons l'objet de réponse:

print(response.candidates[0].content)

role: "model"
parts {
  function_call {
    name: "get_exchange_rate"
    args {
      fields {
        key: "currency_to"
        value {
          string_value: "SEK"
        }
      }
      fields {
        key: "currency_from"
        value {
          string_value: "AUD"
        }
      }
      fields {
        key: "currency_date"
        value {
          string_value: "latest"
        }
      }
    }
  }
}

Il semble que le modèle a sélectionné la fonction disponible et renvoyé un appel de fonction pour la fonction get_exchange_rate avec les paramètres. Les paramètres sont au bon format. Félicitations, vous avez obtenu des réponses structurées à partir de modèles génératifs !

Dans la section suivante, vous allez utiliser les informations de la réponse pour effectuer une requête API.

9. Envoyer une requête API

Rappelez-vous que l'appel de fonction dans Gemini n'effectue pas réellement l'appel d'API externe pour vous. Vous êtes libre d'utiliser le langage, la bibliothèque ou le framework de votre choix !

Ici, vous utiliserez la bibliothèque requests en Python pour appeler l'API REST de taux de change.

Décompressons la réponse dans un dictionnaire Python:

params = {}
for key, value in response.candidates[0].content.parts[0].function_call.args.items():
    params[key[9:]] = value
params

Nous pouvons maintenant appeler requests ou toute autre méthode:

import requests
url = f"https://api.frankfurter.app/{params['date']}"
api_response = requests.get(url, params=params)
api_response.text

Vous obtenez alors une réponse semblable à celle-ci:

'{"amount":1.0,"base":"AUD","date":"2024-01-16","rates":{"SEK":6.8682}}'

Nous recevons la réponse de l'API REST, avec les dernières informations sur le taux de change à ce jour. Dans la section suivante, nous allons transmettre ces informations au modèle afin qu'il puisse générer une réponse pertinente pour l'utilisateur.

10. Générer une réponse

Enfin, générons une réponse pour l'utilisateur en transmettant la réponse de la fonction au modèle lors du prochain tour de conversation:

response = model.generate_content(
    [
    Content(role="user", parts=[
        Part.from_text(prompt + """Give your answer in steps with lots of detail
            and context, including the exchange rate and date."""),
    ]),
    Content(role="function", parts=[
        Part.from_dict({
            "function_call": {
                "name": "get_exchange_rate",
            }
        })
    ]),
    Content(role="function", parts=[
        Part.from_function_response(
            name="get_exchange_rate",
            response={
                "content": api_response.text,
            }
        )
    ]),
    ],
    tools=[exchange_rate_tool],
)


response.candidates[0].content.parts[0].text

Une fois que nous avons transmis la réponse de la fonction au modèle, celui-ci répond à l'invite de l'utilisateur avec les informations pertinentes issues de la réponse de l'API.

The exchange rate from Australian dollars to Swedish krona on January 16, 2024,
is 1 Australian dollar is equal to 6.8663 Swedish krona.

So, 500 Australian dollars would be worth 500 * 6.8663 = 3,433.15 Swedish krona.

11. Afficher l'exemple de code complet

À ce stade, vous pouvez placer votre code Python dans une API backend à l'aide d'un service Cloud Run, d'une fonction Cloud ou d'un autre service Cloud, et déployer une application d'interface qui utilise cette API backend pour effectuer des requêtes de modèle et des appels d'API.

Voici l'exemple de code complet pour notre solution finale:

import requests
from vertexai.generative_models import (
    Content,
    FunctionDeclaration,
    GenerativeModel,
    Part,
    Tool,
)

model = GenerativeModel("gemini-1.5-pro-001")

get_exchange_rate_func = FunctionDeclaration(
    name="get_exchange_rate",
    description="Get the exchange rate for currencies between countries",
    parameters={
    "type": "object",
    "properties": {
        "currency_date": {
            "type": "string",
            "description": "A date that must always be in YYYY-MM-DD format or the value 'latest' if a time period is not specified"
        },
        "currency_from": {
            "type": "string",
            "description": "The currency to convert from in ISO 4217 format"
        },
        "currency_to": {
            "type": "string",
            "description": "The currency to convert to in ISO 4217 format"
        }
    },
         "required": [
            "currency_from",
            "currency_date",
      ]
  },
)

exchange_rate_tool = Tool(
    function_declarations=[get_exchange_rate_func],
)

prompt = """What is the exchange rate from Australian dollars to Swedish krona?
How much is 500 Australian dollars worth in Swedish krona?"""

response = model.generate_content(
    prompt,
    tools=[exchange_rate_tool],
)

response.candidates[0].content

params = {}
for key, value in response.candidates[0].content.parts[0].function_call.args.items():
    params[key[9:]] = value
params

import requests
url = f"https://api.frankfurter.app/{params['date']}"
api_response = requests.get(url, params=params)
api_response.text

response = model.generate_content(
    [
    Content(role="user", parts=[
        Part.from_text(prompt + """Give your answer in steps with lots of detail
            and context, including the exchange rate and date."""),
    ]),
    Content(role="function", parts=[
        Part.from_dict({
            "function_call": {
                "name": "get_exchange_rate",
            }
        })
    ]),
    Content(role="function", parts=[
        Part.from_function_response(
            name="get_exchange_rate",
            response={
                "content": api_response.text,
            }
        )
    ]),
    ],
    tools=[exchange_rate_tool],
)


response.candidates[0].content.parts[0].text

Dans cette implémentation, nous avons envoyé deux requêtes au modèle génératif: l'une pour générer un appel de fonction et l'autre pour renvoyer la réponse de la fonction. Notez qu'il ne s'agit que d'une méthode parmi d'autres pour gérer les appels de fonction et les réponses de fonction avec Gemini. Vous pouvez également effectuer des appels de fonction supplémentaires pour obtenir plus d'informations sur votre requête, ou utiliser l'appel de fonction avec le chat et les méthodes asynchrones.

Pour obtenir d'autres exemples de code, consultez l'exemple de notebook pour l'appel de fonction dans Gemini.

12. Félicitations

Grâce à l'appel de fonction dans Gemini, vous avez réussi à créer un pipeline d'IA générative qui fonctionne avec l'API Gemini Vertex AI et Python. Les utilisateurs peuvent poser des questions sur les taux de change. Le système extrait les dernières données d'une API externe et répond en renvoyant une réponse.

À partir d'une requête d'un utilisateur final, l'appel de fonction dans Gemini se charge de sélectionner la fonction appropriée, d'extraire les paramètres de la requête et de renvoyer un objet de données structurées pour que vous puissiez effectuer un appel d'API externe.

La conception de l'appel de fonction dans Gemini vise à vous offrir le meilleur des deux mondes pour extraire des paramètres de manière déterministe, tout en laissant la synthèse et la création de contenu au modèle génératif. N'hésitez pas à essayer d'autres API et requêtes dans votre pipeline, et à explorer les autres fonctionnalités disponibles liées à l'API Gemini de Vertex AI.

Interface API

Effectuer un nettoyage

Vous pouvez effectuer le nettoyage suivant pour éviter que les ressources utilisées dans cet atelier de programmation soient facturées sur votre compte Google Cloud:

En savoir plus

Poursuivez votre apprentissage sur l'IA conversationnelle et l'IA générative grâce à ces guides et ressources:

Licence

Ce document est publié sous une licence Creative Commons Attribution 2.0 Generic.