Esegui il deployment dei flussi utilizzando Cloud Functions for Firebase

Cloud Functions for Firebase dispone di un metodo onCallGenkit che ti consente di creare rapidamente una funzione richiamabile con un'azione Genkit (ad es. un flusso). Queste funzioni possono essere chiamate utilizzando genkit/beta/cliento l'SDK client Functions, che aggiunge automaticamente le informazioni di autenticazione.

Prima di iniziare

  • Dovresti conoscere il concetto di flussi di Genkit e come scriverli. Le istruzioni in questa pagina presuppongono che tu abbia già definito alcuniflussi da eseguire.
  • Sarebbe utile, ma non obbligatorio, se hai 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. Installa l'interfaccia a riga di comando di Firebase.

  4. 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
  5. Crea una nuova directory del progetto:

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

    cd $PROJECT_ROOT
    firebase init genkit

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

2. Inserisci il flusso in onCallGenkit

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, devi racchiuderli in onCallGenkit. Questo metodo ha tutte le funzionalità del normale onCall. Supporta automaticamente sia le risposte JSON che quelle in streaming.

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

Puoi esporre questo flusso come funzione richiamabile utilizzando onCallGenkit:

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

export generatePoem = onCallGenkit(generatePoemFlow);

Definire un criterio di autorizzazione

Tutti i flussi 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, chiunque può richiamare i flussi di IA generativa potenzialmente costosi. Per definire un criterio di autorizzazione, utilizza il parametro authPolicy di onCallGenkit:

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

Questo esempio utilizza una funzione manuale come criterio di autenticazione. Inoltre, la libreria https esporta gli aiuti signedIn() e hasClaim(). Ecco lo stesso codice che utilizza uno di questi helper:

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

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

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 richiede almeno le credenziali per accedere al servizio API di modelli 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 l'accesso a un servizio potenzialmente con tariffa.

    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 avere accesso a questo valore segreto:

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

Ora, quando esegui il deployment di questa funzione, la chiave API viene archiviata in Cloud Secret Manager ed è 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.

Aggiungere l'applicazione forzata di App Check

Firebase App Check utilizza un meccanismo di attestazione integrato per verificare che la tua API venga chiamata solo dalla tua applicazione. onCallGenkit supporta l'applicazione di App Check in modo dichiarativo.

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

Impostare un criterio CORS

Per impostazione predefinita, le funzioni richiamabili consentono a qualsiasi dominio di chiamare la funzione. Se vuoi personalizzare i domini che possono eseguire questa operazione, utilizza l'opzione cors. Con l'autenticazione corretta (in particolare App Check), CORS spesso non è necessario.

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

Esempio completo

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

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. Esegui il deployment dei flussi in Firebase

Dopo aver definito i flussi utilizzando onCallGenkit, 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 puoi accedere all'endpoint di cui è stato eseguito il deployment con curl o un servizio simile a causa del criterio di autorizzazione del flusso. La sezione successiva spiega come accedere in modo sicuro al flusso.

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

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

  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, utilizzato in questo esempio.

  3. Nella directory del progetto, configura Firebase Hosting, dove verrà eseguita il deployment 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 onCallGenkit 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

Questo comando esegue il codice nell'emulatore e il framework Genkit in modalità di sviluppo. Viene lanciata ed esposta 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, carica le tracce da Firestore.