Implementa flujos con Cloud Functions para Firebase

Genkit incluye un complemento que te ayuda a implementar tus flujos en Cloud Functions para Firebase. Una vez que se implementan, los flujos están disponibles como extremos HTTPS y se puede acceder a ellos como funciones que se pueden llamar con las bibliotecas cliente de Cloud Functions.

Antes de comenzar

  • Instala Firebase CLI.
  • Debes conocer el concepto de flujos de Genkit y cómo escribirlos. En las instrucciones de esta página, se da por sentado que ya tienes algunos flujos definidos que deseas implementar.
  • Sería útil, pero no obligatorio, que ya hayas usado Cloud Functions para Firebase.

1. Configura un proyecto de Firebase:

Si aún no tienes un proyecto de Firebase con Cloud Functions de TypeScript configurado, sigue estos pasos:

  1. Crea un proyecto de Firebase nuevo con la consola de Firebase o elige uno existente.

  2. Actualiza el proyecto al plan Blaze, que es obligatorio para implementar Cloud Functions.

  3. Accede con Firebase CLI:

    firebase login
    firebase login --reauth # alternative, if necessary
    firebase login --no-localhost # if running in a remote shell
  4. Crea un directorio de proyecto nuevo:

    export PROJECT_ROOT=~/tmp/genkit-firebase-project1
    mkdir -p $PROJECT_ROOT
  5. Inicializa un proyecto de Firebase en el directorio:

    cd $PROJECT_ROOT
    firebase init genkit

    En el resto de esta página, se supone que seleccionaste escribir tus funciones en TypeScript, pero también puedes implementar tus flujos de Genkit si usas JavaScript.

2. Actualiza las definiciones de flujo

Después de configurar un proyecto de Firebase con Cloud Functions, puedes copiar o escribir definiciones de flujo en el directorio functions/src del proyecto y exportarlas en index.ts.

Para que tus flujos se puedan implementar, deberás hacer algunos pequeños cambios en la forma en que los defines. La lógica principal seguirá siendo la misma, pero agregarás información adicional para que se puedan implementar sin problemas y sean más seguras una vez que se implementen.

Supongamos que tienes el siguiente flujo:

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

En las siguientes secciones, se describen los cambios que debes realizar antes de poder implementarlo.

Define flujos con onFlow

En lugar de definir tu flujo con Genkit.defineFlow(), usa la función onFlow() del plugin de Firebase. El uso de esta función une la lógica de tu flujo en un controlador de solicitudes de Cloud Functions, similar a onCall.

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

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

Ten en cuenta que onFlow no es un método de Genkit, sino una función que toma una instancia de Genkit como primer parámetro. De lo contrario, la sintaxis es similar a defineFlow.

Define una política de autorización

Todos los flujos implementados, ya sea que se implementen en Firebase o no, deben tener una política de autorización. Sin una, cualquier persona podría invocar tus flujos de IA generativa potencialmente costosos. Para definir una política de autorización, usa el parámetro authPolicy en la definición del flujo:

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) => {
    // ...
  }
);

Esta política usa el auxiliar firebaseAuth() para permitir el acceso solo a los usuarios registrados de tu app con direcciones de correo electrónico verificadas. En el lado del cliente, debes configurar el encabezado Authorization: Bearer en un token de ID de Firebase que satisfaga tu política. Los SDK de cliente de Cloud Functions proporcionan métodos de función que admite llamadas que automatizan este proceso. Consulta la sección Cómo probar el flujo implementado para ver un ejemplo.

Haz que las credenciales de la API estén disponibles para los flujos implementados

Una vez que se implementan, tus flujos necesitan una forma de autenticarse con los servicios remotos en los que se basan. La mayoría de los flujos necesitarán, como mínimo, credenciales para acceder al servicio de la API del modelo que usan.

En este ejemplo, realiza una de las siguientes acciones según el proveedor de modelos que hayas elegido:

Gemini (IA de Google)

  1. Asegúrate de que la IA de Google esté disponible en tu región.

  2. Genera una clave de API para la API de Gemini con Google AI Studio.

  3. Almacena tu clave de API en Cloud Secret Manager:

    firebase functions:secrets:set GOOGLE_GENAI_API_KEY

    Este paso es importante para evitar que se filtre accidentalmente tu clave de API, que otorga acceso a un servicio potencialmente medido.

    Consulta Almacena información de configuración sensible y accede a ella para obtener más información sobre cómo administrar secretos.

  4. Edita src/index.ts y agrega lo siguiente después de las importaciones existentes:

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

    Luego, en la definición del flujo, declara que la función de Cloud Functions necesita acceso a este valor secreto:

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

Ahora, cuando implementes esta función, tu clave de API se almacenará en Cloud Secret Manager y estará disponible desde el entorno de Cloud Functions.

Gemini (Vertex AI)

  1. En la consola de Cloud, Habilita la API de Vertex AI para tu proyecto de Firebase.

  2. En la página IAM, asegúrate de que la cuenta de servicio de procesamiento predeterminada tenga otorgado el rol de usuario de Vertex AI.

El único secreto que debes configurar para este instructivo es para el proveedor del modelo, pero, en general, debes hacer algo similar para cada servicio que tu flujo use.

Cómo establecer una política de CORS

Si accederás a tu flujo desde una app web (lo que harás en la sección Probar el flujo desplegado), en el parámetro httpsOptions, establece una política de CORS:

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

Es probable que desees una política más restrictiva para las apps de producción, pero esta será suficiente para este instructivo.

Ejemplo completo

Después de realizar todos los cambios descritos anteriormente, tu flujo implementable se verá como el siguiente ejemplo:

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. Implementa flujos en Firebase

Después de definir los flujos con onFlow, puedes implementarlos como implementarías otras funciones de Cloud Functions:

cd $PROJECT_ROOT
firebase deploy --only functions

Ya implementaste el flujo como una función de Cloud Functions. Sin embargo, no podrás acceder a tu extremo implementado con curl o un servicio similar debido a la política de autorización del flujo. Continúa con la siguiente sección para obtener información sobre cómo acceder de forma segura al flujo.

Opcional: Prueba el flujo implementado

Para probar el extremo de tu flujo, puedes implementar la siguiente app web mínima de ejemplo:

  1. En la sección Configuración del proyecto de Firebase console, agrega una app web nueva y selecciona la opción para configurar también Hosting.

  2. En la sección Authentication de Firebase console, habilita el proveedor Google, que usarás en este ejemplo.

  3. En el directorio de tu proyecto, configura Firebase Hosting, donde implementarás la app de ejemplo:

    cd $PROJECT_ROOT
    firebase init hosting

    Acepta los valores predeterminados para todas las indicaciones.

  4. Reemplaza public/index.html por lo siguiente:

    <!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. Implementa la app web y la Cloud Function:

    cd $PROJECT_ROOT
    firebase deploy

Para abrir la app web, visita la URL que imprime el comando deploy. La app requiere que accedas con una Cuenta de Google. Luego, puedes iniciar solicitudes de extremos.

Opcional: Ejecuta flujos en la IU para desarrolladores

Puedes ejecutar flujos definidos con onFlow en la IU para desarrolladores de la misma manera que ejecutas flujos definidos con defineFlow, por lo que no es necesario alternar entre los dos entre la implementación y el desarrollo.

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

o

cd $PROJECT_ROOT/functions
npm run genkit:start

Ahora puedes navegar a la URL que imprimió el comando genkit start para acceder a ella.

Opcional: Desarrolla con Firebase Local Emulator Suite

Firebase ofrece un conjunto de emuladores para el desarrollo local, que puedes usar con Genkit.

Para usar la IU de Genkit Dev con Firebase Emulator Suite, inicia los emuladores de Firebase de la siguiente manera:

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

Esto ejecutará tu código en el emulador y ejecutará el framework de Genkit en modo de desarrollo, que inicia y expone la API de reflexión de Genkit (pero no la IU para desarrolladores).

Para ver los seguimientos de Firestore en la IU de Dev, puedes navegar a la pestaña Inspeccionar y activar o desactivar el interruptor “Dev/Prod”. Cuando se cambie a "prod", se cargarán los registros de Firestore.