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


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

這項功能可讓您控管提示、限制詞元用量、記錄生成內容以進行分析,或遮蓋回覆內容。

可用的事件類型有兩種:

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

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

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

如果對 Gemini API 提出的要求並非透過 Firebase AI Logic,則不會觸發這些函式。

必要條件

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

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

  1. 確認 Firebase 專案採用即付即用 Blaze 定價方案 (必須採用此方案才能使用 Cloud Functions for Firebase)。

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

  3. 將建構函式所需的 Cloud Build 服務帳戶角色 (roles/cloudbuild.builds.builder) 授予預設運算服務帳戶。執行下列 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 API 或 Agent Platform Gemini API (formerly Vertex AI)。這些不同 API 的要求物件有不同的形狀。如要安全地使用要求物件,您必須檢查 event.data.api (例如分別與 geminiV1Beta 或 vertexV1Beta1 比較)。

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

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

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

編寫 POST 要求函式 (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 API 或 Agent Platform Gemini API (formerly Vertex AI)。如要安全地轉換及處理要求物件,您必須檢查 event.data.api (例如分別與 geminiV1Beta 或 vertexV1Beta1 比較)。

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

步驟 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
      



事件資料參照網址

beforeGenerateContent 和 afterGenerateContent 都會收到 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.api:Gemini 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 (提供 api、model、template 和 request),並新增模型的回覆:



限制和行為

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

  • 僅限 generateContent 要求:這些函式只能透過 Firebase AI Logic 向 Gemini API 發出 generateContent 要求來觸發。

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

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

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

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

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

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

  • 預設位置:這些函式預設會部署至 us-central1 (瞭解函式位置)。不過,無論您在何處部署函式,函式都會在 global 區域中註冊為 Firebase AI Logic 觸發條件。