Men-deploy alur menggunakan Cloud Functions for Firebase

Cloud Functions for Firebase memiliki metode onCallGenkit yang memungkinkan Anda membuat fungsi callable dengan cepat menggunakan tindakan Genkit (misalnya, Flow). Fungsi ini dapat dipanggil menggunakan genkit/beta/client atau SDK klien Functions, yang secara otomatis menambahkan info autentikasi.

Sebelum memulai

  • Anda harus memahami konsep alur Genkit, dan cara menulisnya. Petunjuk di halaman ini mengasumsikan bahwa Anda sudah menentukan beberapa alur yang ingin di-deploy.
  • Akan lebih baik, tetapi tidak wajib, jika Anda sudah pernah menggunakan Cloud Functions untuk Firebase sebelumnya.

1. Menyiapkan project Firebase

Jika Anda belum memiliki project Firebase dengan Cloud Functions TypeScript yang disiapkan, ikuti langkah-langkah berikut:

  1. Buat project Firebase baru menggunakan Firebase console atau pilih project yang sudah ada.

  2. Upgrade project ke paket Blaze, yang diperlukan untuk men-deploy Cloud Functions.

  3. Instal Firebase CLI.

  4. Login dengan Firebase CLI:

    firebase login
    firebase login --reauth # alternative, if necessary
    firebase login --no-localhost # if running in a remote shell
  5. Buat direktori project baru:

    export PROJECT_ROOT=~/tmp/genkit-firebase-project1
    mkdir -p $PROJECT_ROOT
  6. Lakukan inisialisasi project Firebase di direktori:

    cd $PROJECT_ROOT
    firebase init genkit

    Bagian selanjutnya dari halaman ini mengasumsikan bahwa Anda telah memutuskan untuk menulis fungsi di TypeScript, tetapi Anda juga dapat men-deploy alur Genkit jika menggunakan JavaScript.

2. Menggabungkan Flow di onCallGenkit

Setelah menyiapkan project Firebase dengan Cloud Functions, Anda dapat menyalin atau menulis definisi alur di direktori functions/src project, dan mengekspornya di index.ts.

Agar alur dapat di-deploy, Anda harus menggabungkannya dalam onCallGenkit. Metode ini memiliki semua fitur onCall normal. Fungsi ini otomatis mendukung respons streaming dan JSON.

Misalkan Anda memiliki alur berikut:

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

Anda dapat mengekspos alur ini sebagai fungsi yang dapat dipanggil menggunakan onCallGenkit:

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

export generatePoem = onCallGenkit(generatePoemFlow);

Menentukan kebijakan otorisasi

Semua alur yang di-deploy, baik di-deploy ke Firebase maupun tidak, harus memiliki kebijakan otorisasi. Tanpa kebijakan ini, siapa pun dapat memanggil alur AI generatif Anda yang berpotensi mahal. Untuk menentukan kebijakan otorisasi, gunakan parameter authPolicy dari onCallGenkit:

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

Contoh ini menggunakan fungsi manual sebagai kebijakan autentikasi. Selain itu, library https mengekspor helper signedIn() dan hasClaim(). Berikut adalah kode yang sama menggunakan salah satu helper tersebut:

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

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

Menyediakan kredensial API untuk alur yang di-deploy

Setelah di-deploy, alur Anda memerlukan beberapa cara untuk mengautentikasi dengan layanan jarak jauh yang menjadi andalannya. Sebagian besar alur memerlukan, minimal, kredensial untuk mengakses layanan API model yang mereka gunakan.

Untuk contoh ini, lakukan salah satu hal berikut, bergantung pada penyedia model yang Anda pilih:

Gemini (AI Google)

  1. Pastikan AI Google tersedia di wilayah Anda.

  2. Buat kunci API untuk Gemini API menggunakan Google AI Studio.

  3. Simpan kunci API Anda di Cloud Secret Manager:

    firebase functions:secrets:set GOOGLE_GENAI_API_KEY

    Langkah ini penting untuk mencegah kebocoran kunci API secara tidak sengaja, yang memberikan akses ke layanan yang berpotensi berbayar.

    Lihat Menyimpan dan mengakses informasi konfigurasi yang sensitif untuk mengetahui informasi selengkapnya tentang cara mengelola secret.

  4. Edit src/index.ts dan tambahkan kode berikut setelah impor yang ada:

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

    Kemudian, dalam definisi alur, deklarasikan bahwa fungsi cloud memerlukan akses ke nilai rahasia ini:

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

Sekarang, saat Anda men-deploy fungsi ini, kunci API Anda akan disimpan di Cloud Secret Manager, dan tersedia dari lingkungan Cloud Functions.

Gemini (Vertex AI)

  1. Di konsol Cloud, Aktifkan API Vertex AI untuk project Firebase Anda.

  2. Di halaman IAM, pastikan bahwa Akun layanan komputasi default diberikan peran Vertex AI User.

Satu-satunya secret yang perlu Anda siapkan untuk tutorial ini adalah untuk penyedia model, tetapi secara umum, Anda harus melakukan hal serupa untuk setiap layanan yang digunakan oleh flow Anda.

Menambahkan penerapan App Check

Firebase App Check menggunakan mekanisme pengesahan bawaan untuk memverifikasi bahwa API Anda hanya dipanggil oleh aplikasi Anda. onCallGenkit mendukung penerapan App Check secara deklaratif.

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

Menetapkan kebijakan CORS

Fungsi callable secara default mengizinkan domain mana pun untuk memanggil fungsi Anda. Jika Anda ingin menyesuaikan domain yang dapat melakukannya, gunakan opsi cors. Dengan autentikasi yang tepat (terutama App Check), CORS sering kali tidak diperlukan.

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

Contoh lengkap

Setelah Anda membuat semua perubahan yang dijelaskan sebelumnya, alur yang dapat di-deploy akan terlihat seperti contoh berikut:

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. Men-deploy alur ke Firebase

Setelah menentukan alur menggunakan onCallGenkit, Anda dapat men-deploy-nya dengan cara yang sama seperti men-deploy Cloud Functions lainnya:

cd $PROJECT_ROOT
firebase deploy --only functions

Sekarang Anda telah men-deploy alur sebagai Cloud Function. Namun, Anda tidak dapat mengakses endpoint yang di-deploy dengan curl atau yang serupa, karena kebijakan otorisasi alur. Bagian berikutnya menjelaskan cara mengakses alur dengan aman.

Opsional: Mencoba alur yang di-deploy

Untuk mencoba endpoint alur, Anda dapat men-deploy contoh aplikasi web minimal berikut:

  1. Di bagian Project settings di Firebase console, tambahkan aplikasi web baru, dengan memilih opsi untuk menyiapkan Hosting juga.

  2. Di bagian Authentication di Firebase console, aktifkan penyedia Google, yang digunakan dalam contoh ini.

  3. Di direktori project, siapkan Firebase Hosting, tempat Anda akan men-deploy aplikasi contoh:

    cd $PROJECT_ROOT
    firebase init hosting

    Terima setelan default untuk semua perintah.

  4. Ganti public/index.html dengan yang berikut:

    <!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. Men-deploy aplikasi web dan Cloud Function:

    cd $PROJECT_ROOT
    firebase deploy

Buka aplikasi web dengan membuka URL yang dicetak oleh perintah deploy. Aplikasi ini memerlukan Anda untuk login dengan Akun Google, setelah itu Anda dapat memulai permintaan endpoint.

Opsional: Menjalankan flow di UI developer

Anda dapat menjalankan alur yang ditentukan menggunakan onCallGenkit di UI developer, persis seperti saat menjalankan alur yang ditentukan menggunakan defineFlow, sehingga tidak perlu beralih di antara keduanya antara deployment dan pengembangan.

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

atau

cd $PROJECT_ROOT/functions
npm run genkit:start

Sekarang Anda dapat membuka URL yang dicetak oleh perintah genkit start untuk diakses.

Opsional: Mengembangkan menggunakan Firebase Local Emulator Suite

Firebase menawarkan rangkaian emulator untuk pengembangan lokal, yang dapat Anda gunakan dengan Genkit.

Untuk menggunakan UI Developer Genkit dengan Firebase Emulator Suite, mulai emulator Firebase sebagai berikut:

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

Perintah ini menjalankan kode Anda di emulator, dan menjalankan framework Genkit dalam mode pengembangan. Tindakan ini akan meluncurkan dan mengekspos API refleksi Genkit (tetapi tidak UI Dev).

Untuk melihat rekaman aktivitas dari Firestore di UI Developer, Anda dapat membuka tab Periksa dan mengalihkan tombol Dev/Prod. Jika diaktifkan ke prod, tindakan ini akan memuat trace dari firestore.