Déployer des flux à l'aide de Cloud Functions for Firebase

Cloud Functions for Firebase dispose d'une méthode onCallGenkit qui vous permet de créer rapidement une fonction appelable avec une action Genkit (par exemple, un flux). Ces fonctions peuvent être appelées à l'aide de genkit/beta/client ou du SDK client Functions, qui ajoute automatiquement des informations d'authentification.

Avant de commencer

  • Vous devez connaître le concept de flux de Genkit et savoir comment les écrire. Les instructions de cette page supposent que vous avez déjà défini des flux que vous souhaitez déployer.
  • Il est utile, mais pas obligatoire, d'avoir déjà utilisé Cloud Functions for Firebase.

1. Configurer un projet Firebase

Si vous ne disposez pas encore d'un projet Firebase avec des fonctions Cloud TypeScript configurées, procédez comme suit:

  1. Créez un projet Firebase à l'aide de la console Firebase ou choisissez-en un existant.

  2. Passez le projet à la formule Blaze, qui est requise pour déployer Cloud Functions.

  3. Installez la CLI Firebase.

  4. Connectez-vous avec la CLI Firebase:

    firebase login
    firebase login --reauth # alternative, if necessary
    firebase login --no-localhost # if running in a remote shell
  5. Créez un répertoire de projet:

    export PROJECT_ROOT=~/tmp/genkit-firebase-project1
    mkdir -p $PROJECT_ROOT
  6. Initialisez un projet Firebase dans le répertoire:

    cd $PROJECT_ROOT
    firebase init genkit

    Le reste de cette page part du principe que vous avez décidé d'écrire vos fonctions en TypeScript, mais vous pouvez également déployer vos flux Genkit si vous utilisez JavaScript.

2. Encapsuler le flux dans onCallGenkit

Une fois que vous avez configuré un projet Firebase avec Cloud Functions, vous pouvez copier ou écrire des définitions de flux dans le répertoire functions/src du projet, puis les exporter dans index.ts.

Pour que vos flux puissent être déployés, vous devez les encapsuler dans onCallGenkit. Cette méthode possède toutes les fonctionnalités de l'onCall standard. Il est compatible automatiquement avec le streaming et les réponses JSON.

Supposons que vous disposiez du flux suivant:

const generatePoemFlow = ai.defineFlow(
  {
    name: "generatePoem",
    inputSchema: z.string(),
    outputSchema: z.string(),
  },
  async (subject: string) => {
    const { text } = await ai.generate(`Compose a poem about ${subject}.`);
    return text;
  }
);

Vous pouvez exposer ce flux en tant que fonction appelable à l'aide de onCallGenkit:

import { onCallGenkit } from 'firebase-functions/https';

export generatePoem = onCallGenkit(generatePoemFlow);

Définir une règle d'autorisation

Tous les flux déployés, qu'ils soient déployés sur Firebase ou non, doivent disposer d'une stratégie d'autorisation. Sans cela, n'importe qui peut appeler vos flux d'IA générative potentiellement coûteux. Pour définir une stratégie d'autorisation, utilisez le paramètre authPolicy de onCallGenkit:

export const generatePoem = onCallGenkit({
  authPolicy: (auth) => auth?.token?.email_verified,
}, generatePoemFlow);

Cet exemple utilise une fonction manuelle comme règle d'authentification. De plus, la bibliothèque https exporte les outils d'aide signedIn() et hasClaim(). Voici le même code utilisant l'une de ces aides:

import { hasClaim } from 'firebase-functions/https';

export const generatePoem = onCallGenkit({
  authPolicy: hasClaim('email_verified'),
}, generatePoemFlow);

Rendre les identifiants de l'API disponibles pour les flux déployés

Une fois déployés, vos flux doivent disposer d'un moyen de s'authentifier auprès des services distants sur lesquels ils s'appuient. La plupart des flux nécessitent au minimum des identifiants pour accéder au service d'API de modèle qu'ils utilisent.

Pour cet exemple, effectuez l'une des opérations suivantes, en fonction du fournisseur de modèle que vous avez choisi:

Gemini (IA de Google)

  1. Assurez-vous que l'IA de Google est disponible dans votre région.

  2. Générez une clé API pour l'API Gemini à l'aide de Google AI Studio.

  3. Stockez votre clé API dans Cloud Secret Manager:

    firebase functions:secrets:set GOOGLE_GENAI_API_KEY

    Cette étape est importante pour éviter de divulguer accidentellement votre clé API, qui permet d'accéder à un service potentiellement limité.

    Pour en savoir plus sur la gestion des secrets, consultez la section Stocker et accéder à des informations de configuration sensibles.

  4. Modifiez src/index.ts et ajoutez les éléments suivants après les importations existantes:

    import {defineSecret} from "firebase-functions/params";
    const googleAIapiKey = defineSecret("GOOGLE_GENAI_API_KEY");
    

    Ensuite, dans la définition du flux, déclarez que la fonction cloud doit avoir accès à cette valeur secrète:

    export const generatePoem = onCallGenkit({
      secrets: [googleAIapiKey]
    }, generatePoemFlow);
    

Désormais, lorsque vous déployez cette fonction, votre clé API est stockée dans Cloud Secret Manager et disponible depuis l'environnement Cloud Functions.

Gemini (Vertex AI)

  1. Dans la console Cloud, activez l'API Vertex AI pour votre projet Firebase.

  2. Sur la page IAM, assurez-vous que le compte de service Compute par défaut se voit attribuer le rôle Utilisateur Vertex AI.

Le seul secret que vous devez configurer pour ce tutoriel concerne le fournisseur de modèle, mais en général, vous devez effectuer une opération similaire pour chaque service utilisé par votre flux.

Ajouter l'application App Check

Firebase App Check utilise un mécanisme d'attestation intégré pour vérifier que votre API n'est appelée que par votre application. onCallGenkit prend en charge l'application de la vérification des applications de manière déclarative.

export const generatePoem = onCallGenkit({
  enforceAppCheck: true,
  // Optional. Makes App Check tokens only usable once. This adds extra security
  // at the expense of slowing down your app to generate a token for every API
  // call
  consumeAppCheckToken: true,
}, generatePoemFlow);

Définir une règle CORS

Par défaut, les fonctions appelables autorisent n'importe quel domaine à appeler votre fonction. Si vous souhaitez personnaliser les domaines pouvant effectuer cette opération, utilisez l'option cors. Avec une authentification appropriée (en particulier avec App Check), le CORS est souvent inutile.

export const generatePoem = onCallGenkit({
  cors: 'mydomain.com',
}, generatePoemFlow);

Exemple complet

Une fois toutes les modifications décrites précédemment effectuées, votre flux déployable se présente comme suit:

import { genkit } from 'genkit';
import { onCallGenkit, hasClaim } from 'firebase-functions/https';
import { defineSecret } from 'firebase-functions/params';

const apiKey = defineSecret("GOOGLE_GENAI_API_KEY");

const generatePoemFlow = ai.defineFlow({
  name: "generatePoem",
  inputSchema: z.string(),
  outputSchema: z.string(),
}, async (subject: string) => {
  const { text } = await ai.generate(`Compose a poem about ${subject}.`);
  return text;
});

export const generateFlow = onCallGenkit({
  secrets: [apiKey],
  authPolicy: hasClaim("email_verified"),
  enforceAppCheck: true,
}, generatePoemFlow);

3. Déployer des flux sur Firebase

Une fois que vous avez défini des flux à l'aide de onCallGenkit, vous pouvez les déployer de la même manière que les autres fonctions Cloud:

cd $PROJECT_ROOT
firebase deploy --only functions

Vous avez maintenant déployé le flux en tant que fonction Cloud. Toutefois, vous ne pouvez pas accéder à votre point de terminaison déployé avec curl ou un outil similaire, en raison de la stratégie d'autorisation du flux. La section suivante explique comment accéder de manière sécurisée au flux.

Facultatif: Essayer le flux déployé

Pour tester votre point de terminaison de flux, vous pouvez déployer l'exemple d'application Web minimal suivant:

  1. Dans la section Project settings (Paramètres du projet) de la console Firebase, ajoutez une application Web, en sélectionnant l'option permettant également de configurer l'hébergement.

  2. Dans la section Authentication (Authentification) de la console Firebase, activez le fournisseur Google, utilisé dans cet exemple.

  3. Dans le répertoire de votre projet, configurez Firebase Hosting, où vous allez déployer l'application exemple:

    cd $PROJECT_ROOT
    firebase init hosting

    Acceptez les valeurs par défaut pour toutes les requêtes.

  4. Remplacez public/index.html par ce qui suit:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Genkit demo</title>
      </head>
      <body>
        <div id="signin" hidden>
          <button id="signinBtn">Sign in with Google</button>
        </div>
        <div id="callGenkit" hidden>
          Subject: <input type="text" id="subject" />
          <button id="generatePoem">Compose a poem on this subject</button>
          <p id="generatedPoem"></p>
        </div>
        <script type="module">
          import { initializeApp } from "https://www.gstatic.com/firebasejs/11.0.1/firebase-app.js";
          import {
            getAuth,
            onAuthStateChanged,
            GoogleAuthProvider,
            signInWithPopup,
          } from "https://www.gstatic.com/firebasejs/11.0.1/firebase-auth.js";
          import {
            getFunctions,
            httpsCallable,
          } from "https://www.gstatic.com/firebasejs/11.0.1/firebase-functions.js";
    
          const firebaseConfig = await fetch("/__/firebase/init.json");
          initializeApp(await firebaseConfig.json());
    
          async function generatePoem() {
            const poemFlow = httpsCallable(getFunctions(), "generatePoem");
            const subject = document.querySelector("#subject").value;
            const response = await poemFlow(subject);
            document.querySelector("#generatedPoem").innerText = response.data;
          }
    
          function signIn() {
            signInWithPopup(getAuth(), new GoogleAuthProvider());
          }
    
          document.querySelector("#signinBtn").addEventListener("click", signIn);
          document
            .querySelector("#generatePoem")
            .addEventListener("click", generatePoem);
    
          const signinEl = document.querySelector("#signin");
          const genkitEl = document.querySelector("#callGenkit");
    
          onAuthStateChanged(getAuth(), (user) => {
            if (!user) {
              signinEl.hidden = false;
              genkitEl.hidden = true;
            } else {
              signinEl.hidden = true;
              genkitEl.hidden = false;
            }
          });
        </script>
      </body>
    </html>
    
  5. Déployez l'application Web et la fonction Cloud:

    cd $PROJECT_ROOT
    firebase deploy

Ouvrez l'application Web en accédant à l'URL imprimée par la commande deploy. L'application vous demande de vous connecter avec un compte Google, après quoi vous pouvez lancer des requêtes de point de terminaison.

Facultatif: Exécuter des flux dans l'UI du développeur

Vous pouvez exécuter des flux définis à l'aide de onCallGenkit dans l'interface utilisateur du développeur, exactement de la même manière que vous exécutez des flux définis à l'aide de defineFlow. Vous n'avez donc pas besoin de basculer entre les deux entre le déploiement et le développement.

cd $PROJECT_ROOT/functions
npx genkit start -- npx tsx --watch src/index.ts

ou

cd $PROJECT_ROOT/functions
npm run genkit:start

Vous pouvez maintenant accéder à l'URL imprimée par la commande genkit start.

Facultatif: Développement à l'aide de la suite d'émulateurs locaux Firebase

Firebase propose une suite d'émulateurs pour le développement local, que vous pouvez utiliser avec Genkit.

Pour utiliser l'UI de développement Genkit avec la suite d'émulateurs Firebase, démarrez les émulateurs Firebase comme suit:

npx genkit start -- firebase emulators:start --inspect-functions

Cette commande exécute votre code dans l'émulateur et exécute le framework Genkit en mode développement. Cette opération lance et expose l'API de réflexion Genkit (mais pas l'UI de développement).

Pour afficher les traces de Firestore dans l'UI de développement, accédez à l'onglet Inspect (Inspecter) et activez/désactivez l'option Dev/Prod (Dev/Prod). Lorsque l'option prod est activée, elle charge les traces de Firestore.