使用 Cloud Functions for Firebase 部署流程

Cloud Functions for Firebase 提供 onCallGenkit 方法,可讓您使用 Genkit 動作 (例如流程) 快速建立可呼叫的函式。您可以使用 genkit/beta/clientFunctions 用戶端 SDK 呼叫這些函式,這些函式會自動新增驗證資訊。

事前準備

  • 您應該熟悉 Genkit 的流程概念,以及如何編寫流程。本頁面說明假設您已定義要部署的部分流程。
  • 您可以先前曾使用 Firebase 的 Cloud Functions 為基礎,但這並非必要條件。

1. 設定 Firebase 專案

如果您還沒有 Firebase 專案,且未設定 TypeScript Cloud 函式,請按照下列步驟操作:

  1. 使用 Firebase 主控台建立新的 Firebase 專案,或選擇現有專案。

  2. 將專案升級至 Blaze 方案,這是部署 Cloud Functions 的必要條件。

  3. 安裝 Firebase CLI

  4. 使用 Firebase CLI 登入:

    firebase login
    firebase login --reauth # alternative, if necessary
    firebase login --no-localhost # if running in a remote shell
  5. 建立新的專案目錄:

    export PROJECT_ROOT=~/tmp/genkit-firebase-project1
    mkdir -p $PROJECT_ROOT
  6. 在目錄中初始化 Firebase 專案:

    cd $PROJECT_ROOT
    firebase init genkit

    本頁其餘部分假設您已決定使用 TypeScript 編寫函式,但如果您使用的是 JavaScript,也可以部署 Genkit 流程。

2. 在 onCallGenkit 中包裝 Flow

設定含有 Cloud Functions 的 Firebase 專案後,您可以在專案的 functions/src 目錄中複製或撰寫流程定義,並在 index.ts 中匯出。

如要部署流程,您必須將其納入 onCallGenkit。這個方法具有一般 onCall 的所有功能。這項功能會自動支援串流和 JSON 回應。

假設您有以下流程:

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

您可以使用 onCallGenkit 將此流程公開為可呼叫的函式:

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

export generatePoem = onCallGenkit(generatePoemFlow);

定義授權政策

所有已部署的流程 (無論是否已部署至 Firebase) 都應設有授權政策;否則,任何人都能叫用可能耗費不斐的生成式 AI 流程。如要定義授權政策,請使用 onCallGenkitauthPolicy 參數:

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

這個範例使用手動函式做為其授權政策。此外,https 程式庫會匯出 signedIn()hasClaim() 輔助程式。以下是使用其中一個輔助程式的相同程式碼:

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

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

讓 API 憑證可供部署的資料流使用

部署後,流程需要透過某種方式,驗證所依賴的任何遠端服務。大多數流程至少需要憑證,才能存取所使用的模型 API 服務。

在本例中,請根據所選模型供應器執行下列任一操作:

Gemini (Google AI)

  1. 確認 Google AI 是否支援您的地區

  2. 使用 Google AI Studio 為 Gemini API 產生 API 金鑰

  3. 將 API 金鑰儲存在 Cloud Secret Manager 中:

    firebase functions:secrets:set GOOGLE_GENAI_API_KEY

    這項步驟非常重要,可避免 API 金鑰意外外洩,導致您付費使用可能計費的服務。

    如要進一步瞭解如何管理機密資料,請參閱「儲存及存取機密設定資訊」。

  4. 編輯 src/index.ts,並在現有匯入內容後方新增以下內容:

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

    接著,請在流程定義中宣告 Cloud Functions 需要存取此機密值:

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

如今,當您部署這個函式時,API 金鑰會儲存在 Cloud Secret Manager 中,並可從 Cloud Functions 環境取得。

Gemini (Vertex AI)

  1. 在 Cloud 控制台中,為 Firebase 專案啟用 Vertex AI API

  2. 在「IAM」頁面上,確認「預設運算服務帳戶」已獲授「Vertex AI 使用者」角色。

您只需要為本教學課程的模型供應商設定一個機密,但一般來說,您必須為流程使用的每項服務執行類似的操作。

新增 App Check 強制執行

Firebase App Check 會使用內建的認證機制,確認 API 只會由應用程式呼叫。onCallGenkit 可透過宣告方式支援 App Check 強制執行。

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

設定 CORS 政策

可呼叫的函式預設為允許任何網域呼叫您的函式。如要自訂可執行這項操作的網域,請使用 cors 選項。只要有適當的驗證 (尤其是 App Check),通常就不需要使用 CORS。

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

完整範例

完成上述所有變更後,可部署的流程會如下所示:

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. 將流程部署至 Firebase

使用 onCallGenkit 定義流程後,您可以按照部署其他 Cloud Functions 的方式部署流程:

cd $PROJECT_ROOT
firebase deploy --only functions

您現在已將流程部署為 Cloud 函式!但由於流程的授權政策,您無法使用 curl 或類似方式存取已部署的端點。下一節將說明如何安全地存取流程。

選用步驟:試用已部署的流程

如要試用流程端點,您可以部署以下簡易的網頁應用程式範例:

  1. 在 Firebase 主控台的「專案設定」部分新增網頁應用程式,並選取相關選項來設定代管服務。

  2. 在 Firebase 主控台的「Authentication」部分中,啟用本例中使用的 Google 供應器。

  3. 在專案目錄中設定 Firebase 託管服務,以便部署範例應用程式:

    cd $PROJECT_ROOT
    firebase init hosting

    接受所有提示訊息的預設值。

  4. public/index.html 替換為下列內容:

    <!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. 部署網頁應用程式和 Cloud 函式:

    cd $PROJECT_ROOT
    firebase deploy

開啟網頁應用程式,方法是造訪 deploy 指令列印的網址。應用程式會要求您使用 Google 帳戶登入,之後您才能發出端點要求。

選用:在開發人員 UI 中執行流程

您可以在開發人員 UI 中執行使用 onCallGenkit 定義的流程,這與使用 defineFlow 定義的流程完全相同,因此在部署和開發期間,您不需要在兩者之間切換。

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

cd $PROJECT_ROOT/functions
npm run genkit:start

您現在可以前往 genkit start 指令顯示的網址存取內容。

選用:使用 Firebase 本機模擬器套件進行開發

Firebase 提供一系列本機開發模擬器,可搭配 Genkit 使用。

如要搭配 Firebase Emulator Suite 使用 Genkit 開發人員 UI,請按照下列步驟啟動 Firebase 模擬器:

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

這個指令會在模擬器中執行程式碼,並在開發模式中執行 Genkit 架構。這會啟動並公開 Genkit 反射 API (但不會公開開發人員 UI)。

如要在開發人員 UI 中查看 Firestore 的追蹤記錄,請前往「檢查」分頁,然後切換「開發人員/產品」切換鈕。切換為「prod」時,會從 Firestore 載入追蹤記錄。