在要求前後執行自訂伺服器端指令碼


您可以在應用程式透過 Firebase AI Logic傳送至 Gemini API 的每個要求前後,執行自訂伺服器端指令碼不必變更用戶端程式碼。您會將這些指令碼實作為部署至 Cloud Functions for Firebase 的回呼樣式函式。

這項功能可讓您執行多種操作,例如管理提示、限制詞元用量、記錄生成內容以供分析,或編輯回覆內容。

可用的事件類型有兩種:

  • beforeGenerateContent:在要求送達 Gemini API 之前執行。函式可以檢查或修改要求,也可以擲回錯誤,完全封鎖要求。

  • afterGenerateContent:在 Gemini API 傳回回應後,以及在回應傳回給用戶端應用程式前執行。這個函式可以檢查或修改回應、完全封鎖回應,或只是觀察回應 (例如用於記錄或稽核)。

將指令碼部署為 Cloud Functions for Firebase 的函式後,系統會將其註冊為 Firebase AI Logic 觸發條件,也就是說,專案中每個傳送至 Gemini APIgenerateContent 要求都會透過 Firebase AI Logic 執行指令碼 (包括使用伺服器提示範本提出的要求)。

這些函式不會由傳送至 Gemini API 的要求觸發 (並非透過 Firebase AI Logic)。

必要條件

  • 設定 Firebase AI Logic:如果尚未完成,請參閱Firebase AI Logic入門指南,瞭解如何設定 Firebase 專案、將應用程式連結至 Firebase、新增 SDK、為所選Gemini API供應商初始化後端服務,以及建立 GenerativeModel 執行個體。

  • 必要權限:請確認您具備部署至 Cloud Functions for Firebase 的必要 IAM 權限。

步驟 1:為 Cloud Functions for Firebase 設定專案

如果您從未在 Firebase 專案中使用 Cloud Functions for Firebase,請完成下列設定。

  1. 請確認 Firebase 專案採用即付即用 Blaze 定價方案 (使用 Cloud Functions for Firebase 的必要條件)。

  2. 安裝指令列介面 (CLI): gcloud CLIFirebase CLI

  3. Cloud Build 服務帳戶角色 (roles/cloudbuild.builds.builder) 授予預設的 Compute 服務帳戶,讓該帳戶具備建構函式所需的權限。執行下列 gcloud CLI 指令:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member="serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
      --role="roles/cloudbuild.builds.builder"
    
  4. 在 Firebase 專案中初始化 Cloud Functions for Firebase

    1. 執行下列 Firebase CLI 指令:

      firebase init functions
      
    2. 出現提示時,請選擇「TypeScript」

    3. 確認 functions/package.json 中的 firebase-functions 為 6.3.0 以上版本。如要查看版本,請按照下列步驟操作:

      npm --prefix functions list firebase-functions
      

步驟 2:編寫函式

撰寫前置要求函式 (beforeGenerateContent) 撰寫後置要求函式 (afterGenerateContent)

編寫前置要求函式 (beforeGenerateContent)

使用 beforeGenerateContent 事件類型時,函式會在 Firebase AI Logic Proxy 收到 generateContent 要求時觸發。函式 會在要求傳送至 Gemini API之前」,針對要求執行 這項函式可以修改要求,或完全封鎖要求。

撰寫函式前,請務必詳閱下列資訊:

範例

以下是前置要求函式範例,可執行下列操作:

  • 指定函式只應在要求適用於特定 Gemini API 提供者時執行。

  • 檢查提示中是否有遭封鎖的主題,並擲回錯誤來拒絕要求。

  • 限制文字生成模型的輸出詞元上限。

import { logger } from "firebase-functions";
import {
  beforeGenerateContent,
  HttpsError,
  vertexV1Beta1,
  type VertexV1Beta1GenerateContentRequest,
} from "firebase-functions/v2/ai";

const BLOCKED_TOPICS = ["weapon", "explosive", "self-harm"];
const MAX_OUTPUT_TOKENS = 4000;

export const guardPrompts = beforeGenerateContent((event) => {
  // 1. Optional: If you want the function to only run for a specific Gemini API provider, specify it here.
  if (event.data.api !== vertexV1Beta1) return;
  const request = event.data.request as VertexV1Beta1GenerateContentRequest;

  // 2. Read the prompt: contents[] -> parts[] -> text
  const prompt = (request.contents ?? [])
    .flatMap((c) => c.parts ?? [])
    .map((p) => ("text" in p ? p.text : "") ?? "")
    .join(" ")
    .toLowerCase();

  // 3. Throwing rejects the request. The request is never sent to the Gemini API.
  const blocked = BLOCKED_TOPICS.find((t) => prompt.includes(t));
  if (blocked) {
    logger.warn("Blocked a prompt", { topic: blocked });
    throw new HttpsError("invalid-argument", `We don't return content about ${blocked}.`);
  }

  logger.info("Allowing generation", {
    model: event.data.model,
    authType: event.authType,
    authId: event.authId,
    appId: event.appId,
  });

  // 4. The next step truncates the response, but that will break images.
  if (event.data.model.includes("image")) return;

  // 5. Return the WHOLE request, edited. Returning nothing leaves it untouched.
  return {
    ...request,
    generationConfig: {
      ...request.generationConfig,
      maxOutputTokens: Math.min(
        request.generationConfig?.maxOutputTokens ?? MAX_OUTPUT_TOKENS,
        MAX_OUTPUT_TOKENS,
      ),
    },
  };
});

預先要求函式的重要注意事項

  • 指定 Gemini API 提供者: event.data.request 可以是 Gemini Developer APIAgent Platform Gemini API (formerly Vertex AI)。這些不同 API 的要求物件形狀各異。如要安全地使用要求物件,請務必檢查 event.data.api (例如分別與 geminiV1BetavertexV1Beta1 比較)。

  • 擲回會封鎖要求:如果擲回 HttpsError,要求就會遭到拒絕。

  • 傳回整個要求:如果函式會修改要求,則必須傳回完整的修改後要求物件。如果未傳回任何內容 (或 undefined),要求就不會變更。

  • 測試延遲:視函式執行的動作而定,可能會增加延遲,進而影響使用者體驗。

撰寫要求後函式 (afterGenerateContent)

使用 afterGenerateContent 事件類型時,當 Firebase AI Logic Proxy 收到來自 generateContent 要求的 回應時,就會觸發函式。這個函式在回應傳回用戶端應用程式「之前」,針對回應執行。這個函式可以記錄用量、修改回應,或完全封鎖回應。

撰寫函式前,請務必詳閱下列資訊:

範例

以下是範例後續要求函式,可記錄權杖用量和完成原因:

import { logger } from "firebase-functions";
import {
  afterGenerateContent,
  vertexV1Beta1,
  type VertexV1Beta1GenerateContentResponse,
} from "firebase-functions/v2/ai";

export const recordGenerationUsage = afterGenerateContent((event) => {
  // Optional: If you want the function to only run for a specific Gemini API provider, specify it here.
  if (event.data.api !== vertexV1Beta1) return;
  const response = event.data.response as VertexV1Beta1GenerateContentResponse;

  logger.info("Generation finished", {
    model: event.data.model,
    promptTokens: response.usageMetadata?.promptTokenCount,
    totalTokens: response.usageMetadata?.totalTokenCount,
    finishReason: response.candidates?.[0]?.finishReason,
  });

  // To leave the response untouched, return nothing.
  // To modify the response, return a modified response object here.
});

要求後函式的重要注意事項

  • 指定 Gemini API 提供者: event.data.response 可以是 Gemini Developer APIAgent Platform Gemini API (formerly Vertex AI)。如要安全地轉換及處理要求物件,您必須檢查 event.data.api (例如分別與 geminiV1BetavertexV1Beta1 比較)。

  • 測試延遲:視函式執行的動作而定,可能會增加延遲,進而影響使用者體驗。

步驟 3:部署函式

將函式部署至 Firebase 時,系統會授予 Firebase AI Logic 服務代理程式叫用這些函式的權限,並將每個函式註冊為 Firebase AI Logic 觸發程序

  1. 使用 Firebase CLI 部署函式:

    firebase deploy --only functions
    
  2. 部署完成後,請確認函式已部署至 Firebase:

    firebase functions:list
    
  3. 如要疊代函式:

    更新專案目錄中的函式,然後再次執行 firebase deploy --only functions

停止執行函式

如要停止執行其中一項函式,必須從伺服器刪除函式,並取消註冊為 Firebase AI Logic 觸發程序。您可以使用 Firebase CLI,透過下列任一選項執行這項操作:

  • 選項 1:隱含刪除函式

    1. 從專案目錄程式碼集移除函式。

    2. 執行下列 Firebase CLI 指令:

      firebase deploy --only functions
      
  • 方法 2:明確刪除函式

    1. 從專案目錄程式碼集移除函式。

    2. 執行下列 Firebase CLI 指令:

      firebase functions:delete FUNCTION_NAME
      



事件資料參考資料

beforeGenerateContentafterGenerateContent 都會收到 AIBlockingEvent 物件,其中包含要求的背景資訊和中繼資料。

頂層要求中繼資料 (AIBlockingEvent)

頂層 AIBlockingEvent 物件提供有關呼叫端和觸發環境的資訊:

  • event.authType:呼叫端的驗證狀態:"app_user""unauthenticated""unknown"
  • event.authId:如果呼叫端已登入,則為呼叫端的 Firebase 驗證 UID。
  • event.authClaims:呼叫端的自訂授權聲明 (如有)。
  • event.appId:提出要求的 Firebase 應用程式 ID。
  • event.androidPackageName / event.iosBundleId:呼叫端應用程式的套件名稱或套件 ID (分別適用於 Android 或 Apple 平台)。
  • event.data:事件酬載,前置要求和後置要求函式之間有所不同:

要求前事件資料 (beforeGenerateContent)

beforeGenerateContent 函式中,event.data 會填入 BeforeGenerateContentData 物件:

  • event.data.apiGemini API 供應商:geminiV1Beta (Gemini Developer API) 或 vertexV1Beta1 (Agent Platform Gemini API (formerly Vertex AI))。
  • event.data.model:完整的模型資源路徑 (例如 projects/{PROJECT_ID}/locations/global/publishers/google/models/gemini-3.8-flash)。
  • event.data.template:所用伺服器提示詞範本的中繼資料 (PromptTemplateInfo),如適用。
  • event.data.request:外送要求酬載。物件類型和屬性取決於 Gemini API 提供者:

要求後事件資料 (afterGenerateContent)

afterGenerateContent 函式中,event.data 會填入 AfterGenerateContentData 物件。這個物件會擴充 BeforeGenerateContentData (提供 apimodeltemplaterequest),並新增模型的相關回應:



限制和行為

導入這些函式時,請注意下列行為和限制:

  • 僅限 generateContent 要求:這些函式只能透過 Firebase AI Logic,由對 Gemini APIgenerateContent 要求觸發。

    下列情況不會觸發這些函式,且系統會自動略過該要求:

    • generateContentStream 的要求不會觸發這些函式。

    • Gemini Live API 的要求不會觸發這些函式。

  • 不必變更用戶端程式碼:除了確保在執行這些函式時使用 generateContent 要求之外,您不必變更用戶端程式碼集。

    這些函式會部署到我們的伺服器,並註冊為 Firebase AI Logic 觸發程序,以便 Firebase AI Logic Proxy 攔截伺服器端的要求和回應。

  • 專案層級範圍:每個 Firebase 專案最多可部署一個 beforeGenerateContent 函式和一個 afterGenerateContent 函式。

  • 預設位置:這些函式預設會部署至 us-central1 (請參閱函式位置)。不過,無論您將函式部署到哪個區域,系統都會在 global 區域中將函式註冊為 Firebase AI Logic 觸發程序