Esegui il deployment dei flussi utilizzando Cloud Functions for Firebase

Genkit include un plug-in che ti aiuta a eseguire il deployment dei flussi in Cloud Functions for Firebase. Una volta di cui sono stati eseguiti il deployment, i flussi sono disponibili come endpoint HTTPS e accessibili come funzioni richiamabili utilizzando le librerie client di Cloud Functions.

Prima di iniziare

  • Installa l'interfaccia a riga di comando di Firebase.
  • Dovresti conoscere il concetto di flussi di Genkit e come scriverli. Le istruzioni riportate in questa pagina presuppongono che tu abbia già definito alcuniflussi da eseguire.
  • Sarebbe utile, ma non obbligatorio, se avessi già utilizzato Cloud Functions per Firebase.

1. Configurare un progetto Firebase

Se non hai già un progetto Firebase con Cloud Functions per TypeScript configurato, segui questi passaggi:

  1. Crea un nuovo progetto Firebase utilizzando la console Firebase o scegline uno esistente.

  2. Esegui l'upgrade del progetto al piano Blaze, necessario per eseguire il deployment di Cloud Functions.

  3. Accedi con l'interfaccia a riga di comando di Firebase:

    firebase login
    firebase login --reauth # alternative, if necessary
    firebase login --no-localhost # if running in a remote shell
  4. Crea una nuova directory del progetto:

    export PROJECT_ROOT=~/tmp/genkit-firebase-project1
    mkdir -p $PROJECT_ROOT
  5. Inizializza un progetto Firebase nella directory:

    cd $PROJECT_ROOT
    firebase init genkit

    Il resto di questa pagina presuppone che tu abbia selezionato di scrivere le funzioni in TypeScript, ma puoi anche eseguire il deployment dei flussi Genkit se utilizzi JavaScript.

2. Aggiorna le definizioni dei flussi

Dopo aver configurato un progetto Firebase con Cloud Functions, puoi copiare o scrivere le definizioni dei flussi nella directory functions/src del progetto ed esportarle in index.ts.

Affinché i flussi siano implementabili, dovrai apportare alcune piccole modifiche alla loro definizione. La logica di base rimarrà invariata, ma aggiungerai alcune informazioni aggiuntive per semplificarne il deployment e renderlo più sicuro.

Supponiamo che tu abbia il seguente flusso:

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

Le sezioni seguenti descrivono le modifiche che devi apportare prima di poter eseguire il deployment.

Definire i flussi con onFlow

Anziché definire il flusso con Genkit.defineFlow(), utilizza la funzione onFlow() del plug-in Firebase. Questa funzione inserisce la logica del flusso in un gestore delle richieste Cloud Functions, in modo simile a onCall.

import { onFlow } from "@genkit-ai/firebase/functions";

export const generatePoem = onFlow(
  ai,
  {
    // ...
  },
  async (subject: string) => {
    // ...
  }
);

Tieni presente che onFlow non è un metodo di Genkit, ma una funzione che accetta come primo parametro un'istanza di Genkit. In caso contrario, la sintassi è simile a quella di defineFlow.

Definire un criterio di autorizzazione

Tutti i flussi di lavoro di cui è stato eseguito il deployment, indipendentemente dal fatto che siano stati eseguiti in Firebase o meno, devono avere un criterio di autorizzazione. In caso contrario, i flussi di lavoro di AI generativa potenzialmente costosi potrebbero essere richiamati da chiunque. Per definire un criterio di autorizzazione, utilizza il parametro authPolicy nella definizione del flusso:

import { firebaseAuth } from "@genkit-ai/firebase/auth";

export const generatePoem = onFlow(
  ai,
  {
    name: "generatePoem",
    // ...
    authPolicy: firebaseAuth((user, input) => {
      if (!user.email_verified) {
        throw new Error("Verified email required to run flow");
      }
    }),
  },
  async (subject: string) => {
    // ...
  }
);

Questo criterio utilizza l'helper firebaseAuth() per consentire l'accesso solo agli utenti registrati della tua app con indirizzi email verificati. Sul lato client, devi impostare l'intestazione Authorization: Bearer su un token ID Firebase che soddisfi i tuoi criteri. Gli SDK client di Cloud Functions forniscono metodi di funzione richiamabili che automatizzano questa operazione. Per un esempio, consulta la sezione Provare il flusso di cui è stato eseguito il deployment.

Rendi disponibili le credenziali API per i flussi di cui è stato eseguito il deployment

Una volta implementati, i flussi devono avere un modo per autenticarsi con i servizi remoti su cui si basano. La maggior parte dei flussi richiederà almeno le credenziali per accedere al servizio API model che utilizzano.

Per questo esempio, esegui una delle seguenti operazioni, a seconda del fornitore di modelli scelto:

Gemini (IA di Google)

  1. Assicurati che l'AI di Google sia disponibile nella tua regione.

  2. Genera una chiave API per l'API Gemini utilizzando Google AI Studio.

  3. Memorizza la chiave API in Cloud Secret Manager:

    firebase functions:secrets:set GOOGLE_GENAI_API_KEY

    Questo passaggio è importante per evitare la fuga accidentale della chiave API, che consente di accedere a un servizio potenzialmente soggetto a misurazione.

    Per ulteriori informazioni sulla gestione dei secret, consulta Archiviare e accedere a informazioni di configurazione sensibili.

  4. Modifica src/index.ts e aggiungi quanto segue dopo le importazioni esistenti:

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

    Poi, nella definizione del flusso, dichiara che la funzione cloud deve accedere a questo valore segreto:

    export const generatePoem = onFlow(
      {
        name: "generatePoem",
        // ...
        httpsOptions: {
          secrets: [googleAIapiKey],  // Add this line.
        },
      },
      async (subject) => {
        // ...
      }
    );
    

Ora, quando esegui il deployment di questa funzione, la chiave API verrà archiviata in Cloud Secret Manager e sarà disponibile nell'ambiente Cloud Functions.

Gemini (Vertex AI)

  1. Nella console Cloud, abilita l'API Vertex AI per il tuo progetto Firebase.

  2. Nella pagina IAM, assicurati che all'account di servizio Compute predefinito sia stato concesso il ruolo Utente Vertex AI.

L'unico segreto che devi configurare per questo tutorial è per il provider del modello, ma in generale devi eseguire un'operazione simile per ogni servizio utilizzato dal flusso.

Impostare un criterio CORS

Se accedi al flusso da un'app web (come farai nella sezione Prova il flusso di cui è stato eseguito il deployment), imposta un criterio CORS nel parametro httpsOptions:

export const generatePoem = onFlow(
  ai,
  {
    name: "generatePoem",
    // ...
    httpsOptions: {
      cors: '*',
    },
  },
  async (subject: string) => {
    // ...
  }
);

Probabilmente vorrai un criterio più restrittivo per le app di produzione, ma questo è sufficiente per questo tutorial.

Esempio completo

Dopo aver apportato tutte le modifiche descritte sopra, il flusso di deployment sarà simile all'esempio seguente:

const googleAIapiKey = defineSecret("GOOGLE_GENAI_API_KEY");

export const generatePoem = onFlow(
  ai,
  {
    name: "generatePoem",
    inputSchema: z.string(),
    outputSchema: z.string(),
    authPolicy: firebaseAuth((user, input) => {
      if (!user.email_verified) {
        throw new Error("Verified email required to run flow");
      }
    }),
    httpsOptions: {
      secrets: [googleAIapiKey],
      cors: '*',
    },
  },
  async (subject: string) => {
    const { text } = await ai.generate(`Compose a poem about ${subject}.`);
    return text;
  }
);

3. Esegui il deployment dei flussi in Firebase

Dopo aver definito i flussi utilizzando onFlow, puoi eseguirne il deployment come faresti con altre funzioni Cloud:

cd $PROJECT_ROOT
firebase deploy --only functions

Hai eseguito il deployment del flusso come funzione Cloud. Tuttavia, non potrai accedere all'endpoint di cui è stato eseguito il deployment con curl o un servizio simile a causa del criterio di autorizzazione del flusso. Vai alla sezione successiva per scoprire come accedere in sicurezza al flusso.

(Facoltativo) Prova il flusso di cui è stato eseguito il deployment

Per provare l'endpoint del flusso, puoi eseguire il deployment della seguente app web di esempio minima:

  1. Nella sezione Impostazioni progetto della Console Firebase, aggiungi una nuova app web selezionando l'opzione per configurare anche l'hosting.

  2. Nella sezione Autenticazione della Console Firebase, abilita il provider Google, che utilizzerai in questo esempio.

  3. Nella directory del progetto, configura Firebase Hosting, dove verrà eseguita l'implementazione dell'app di esempio:

    cd $PROJECT_ROOT
    firebase init hosting

    Accetta i valori predefiniti per tutti i prompt.

  4. Sostituisci public/index.html con quanto segue:

    <!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. Esegui il deployment dell'app web e della funzione Cloud:

    cd $PROJECT_ROOT
    firebase deploy

Apri l'app web visitando l'URL stampato dal comando deploy. L'app richiede di accedere con un Account Google, dopodiché puoi avviare richieste di endpoint.

(Facoltativo) Esegui i flussi nell'interfaccia utente per gli sviluppatori

Puoi eseguire i flussi definiti utilizzando onFlow nell'interfaccia utente per gli sviluppatori esattamente come esegui i flussi definiti utilizzando defineFlow, quindi non è necessario passare da uno all'altro tra il deployment e lo sviluppo.

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

o

cd $PROJECT_ROOT/functions
npm run genkit:start

Ora puoi accedere all'URL stampato dal comando genkit start.

(Facoltativo) Sviluppo con Firebase Local Emulator Suite

Firebase offre una suite di emulatori per lo sviluppo locale, che puoi utilizzare con Genkit.

Per utilizzare l'interfaccia utente di Genkit Dev con Firebase Emulator Suite, avvia gli emulatori Firebase come segue:

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

In questo modo, il codice verrà eseguito nell'emulatore e il framework Genkit in modalità di sviluppo, che avvia ed espone l'API di riflessione Genkit (ma non l'interfaccia utente per sviluppatori).

Per visualizzare le tracce di Firestore nell'interfaccia utente di sviluppo, puoi andare alla scheda Ispeziona e attivare/disattivare l'opzione "Sviluppatore/Produzione". Se impostato su "prod", verranno caricate le tracce da Firestore.