Benutzerdefinierte serverseitige Skripts vor und nach Anfragen ausführen


Sie können eigene benutzerdefinierte serverseitige Skripts vor und nach jeder Anfrage ausführen, die Ihre App über Firebase AI Logic an Gemini API sendet – ohne Ihren Clientcode zu ändern. Sie implementieren diese Skripts als Callback-Funktionen, die in Cloud Functions for Firebase bereitgestellt werden.

Damit können Sie beispielsweise Prompts moderieren, die Tokennutzung begrenzen, Generierungen für Analysen protokollieren oder Antwortinhalte unkenntlich machen.

Es gibt zwei Ereignistypen:

  • beforeGenerateContent: Wird ausgeführt, bevor eine Anfrage den Gemini API erreicht. Die Funktion kann die Anfrage prüfen oder ändern oder die Anfrage vollständig blockieren, indem sie einen Fehler ausgibt.

  • afterGenerateContent: Wird ausgeführt, nachdem die Antwort von Gemini API zurückgesendet wurde und bevor sie an die Client-App zurückgegeben wird. Die Funktion kann die Antwort prüfen oder ändern, sie vollständig blockieren oder nur beobachten (z. B. für Logging oder Auditing).

Sobald Ihre Skripts als Funktionen in Cloud Functions for Firebase bereitgestellt werden, werden sie als Firebase AI Logic-Trigger registriert. Das bedeutet, dass sie für jede generateContent-Anfrage in Ihrem Projekt an Gemini API über Firebase AI Logic ausgeführt werden (einschließlich Anfragen, die mit Server-Promptvorlagen gestellt werden).

Diese Funktionen werden nicht durch Anfragen an die Gemini API ausgelöst, die nicht über Firebase AI Logic erfolgen.

Vorbereitung

Schritt 1: Projekt für Cloud Functions for Firebase einrichten

Wenn Sie Cloud Functions for Firebase noch nie in Ihrem Firebase-Projekt verwendet haben, führen Sie die folgenden Schritte aus.

  1. Ihr Firebase-Projekt muss den Blaze-Preismodell (Pay as you go) verwenden, damit Sie Cloud Functions for Firebase nutzen können.

  2. Installieren Sie die Befehlszeilen (Command Line Interfaces, CLIs): gcloud CLI und Firebase CLI

  3. Weisen Sie dem Compute Engine-Standarddienstkonto die Rolle Cloud Build-Dienstkonto (roles/cloudbuild.builds.builder) zu, die zum Erstellen Ihrer Funktion erforderlich ist. Führen Sie dazu diesen Befehl gcloud CLI aus:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member="serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
      --role="roles/cloudbuild.builds.builder"
    
  4. Initialisieren Sie Cloud Functions for Firebase in Ihrem Firebase-Projekt:

    1. Führen Sie den folgenden Firebase-Befehlszeilenbefehl aus:

      firebase init functions
      
    2. Wählen Sie bei Aufforderung TypeScript aus.

    3. Achten Sie darauf, dass firebase-functions in Ihrem functions/package.json Version 6.3.0 oder höher ist. So prüfen Sie Ihre Version:

      npm --prefix functions list firebase-functions
      

Schritt 2: Funktionen schreiben

 Funktion für Vorab-Anfrage schreiben (beforeGenerateContent)  Funktion für Nachab-Anfrage schreiben (afterGenerateContent)

Funktion für die Vorab-Anfrage schreiben (beforeGenerateContent)

Beim Ereignistyp beforeGenerateContent wird die Funktion ausgelöst, wenn der Firebase AI Logic-Proxy eine generateContent-Anfrage empfängt. Die Funktion wird vor dem Senden der Anfrage an Gemini API für die Anfrage ausgeführt. Die Funktion kann die Anfrage ändern oder vollständig blockieren.

Beachten Sie die folgenden Informationen, bevor Sie Ihre Funktion schreiben:

Beispiel

Hier ist ein Beispiel für eine Pre-Request-Funktion, die Folgendes ausführt:

  • Gibt an, dass die Funktion nur ausgeführt werden soll, wenn die Anfrage für einen bestimmten Gemini API-Anbieter erfolgt.

  • Überprüft den Prompt auf blockierte Themen und lehnt die Anfrage ab, indem ein Fehler ausgegeben wird.

  • Begrenzt die maximale Anzahl von Ausgabetokens für Modelle zur Textgenerierung.

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

Wichtige Hinweise zu Funktionen vor der Anfrage

  • Gemini API-Anbieter angeben:event.data.request kann entweder für Gemini Developer API oder Agent Platform Gemini API (formerly Vertex AI) sein. Die Anfrageobjekte für diese verschiedenen APIs haben unterschiedliche Formen. Um sicher mit dem Anfrageobjekt zu arbeiten, müssen Sie event.data.api prüfen (z. B. mit geminiV1Beta oder vertexV1Beta1 vergleichen).

  • Durch das Werfen wird die Anfrage blockiert:Wenn Sie ein HttpsError werfen, wird die Anfrage abgelehnt.

  • Ganze Anfrage zurückgeben:Wenn Ihre Funktion die Anfrage ändert, müssen Sie das vollständige, geänderte Anfrageobjekt zurückgeben. Wenn nichts zurückgegeben wird (oder undefined), bleibt die Anfrage unverändert.

  • Latenz testen:Je nachdem, was Ihre Funktion tut, kann es zu Latenz kommen, die sich auf die Nutzerfreundlichkeit auswirkt.

Funktion für die Verarbeitung nach der Anfrage schreiben (afterGenerateContent)

Beim Ereignistyp afterGenerateContent wird die Funktion ausgelöst, wenn der Firebase AI Logic-Proxy eine Antwort auf eine generateContent-Anfrage erhält. Die Funktion wird für die Antwort ausgeführt, bevor die Antwort an die Client-App zurückgegeben wird. Mit der Funktion kann die Nutzung protokolliert, die Antwort geändert oder die Antwort vollständig blockiert werden.

Beachten Sie die folgenden Informationen, bevor Sie Ihre Funktion schreiben:

Beispiel

Hier ist ein Beispiel für eine Funktion für Anfragen nach dem Posten, die die Tokennutzung und den Grund für den Abschluss protokolliert:

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

Wichtige Überlegungen zu Funktionen nach der Anfrage

  • Gemini API-Anbieter angeben:event.data.response kann entweder für Gemini Developer API oder Agent Platform Gemini API (formerly Vertex AI) sein. Um das Anfrageobjekt sicher zu casten und damit zu arbeiten, müssen Sie event.data.api prüfen (z. B. mit geminiV1Beta oder vertexV1Beta1 vergleichen).

  • Latenz testen:Je nachdem, was Ihre Funktion tut, kann es zu Latenz kommen, die sich auf die Nutzerfreundlichkeit auswirkt.

Schritt 3: Funktionen bereitstellen

Wenn Sie Ihre Funktionen in Firebase bereitstellen, erhält der Dienst-Agent Firebase AI Logic die Berechtigung, diese Funktionen aufzurufen, und jede Funktion wird als Firebase AI Logic-Trigger registriert.

  1. Stellen Sie Ihre Funktionen mit der Firebase-CLI bereit:

    firebase deploy --only functions
    
  2. Prüfen Sie nach der Bereitstellung, ob Ihre Funktionen in Firebase bereitgestellt wurden:

    firebase functions:list
    
  3. Wenn Sie Ihre Funktion iterieren müssen:

    Aktualisieren Sie die Funktion in Ihrem Projektverzeichnis und führen Sie dann firebase deploy --only functions noch einmal aus.

Ausführung einer Funktion beenden

Damit eine dieser Funktionen nicht mehr ausgeführt wird, muss sie von unseren Servern gelöscht und als Firebase AI Logic-Trigger abgemeldet werden. Dazu haben Sie mit der Firebase-Befehlszeile folgende Möglichkeiten:

  • Option 1: Funktion implizit löschen

    1. Entfernen Sie die Funktion aus der Codebasis Ihres Projektverzeichnisses.

    2. Führen Sie den folgenden Firebase-Befehlszeilenbefehl aus:

      firebase deploy --only functions
      
  • Option 2: Funktion explizit löschen

    1. Entfernen Sie die Funktion aus der Codebasis Ihres Projektverzeichnisses.

    2. Führen Sie den folgenden Firebase-Befehlszeilenbefehl aus:

      firebase functions:delete FUNCTION_NAME
      



Referenz zu Ereignisdaten

Sowohl beforeGenerateContent als auch afterGenerateContent erhalten ein AIBlockingEvent-Objekt mit Kontext und Metadaten zur Anfrage.

Metadaten der obersten Ebene für Anfragen (AIBlockingEvent)

Das AIBlockingEvent-Objekt auf oberster Ebene enthält Informationen zum Anrufer und zur Umgebung, in der der Aufruf ausgelöst wurde:

  • event.authType: Authentifizierungsstatus für den Aufrufer: "app_user", "unauthenticated" oder "unknown".
  • event.authId: Die Firebase Authentication-UID des Aufrufers, falls er angemeldet ist.
  • event.authClaims: Die benutzerdefinierten Authentifizierungsansprüche des Aufrufers, falls vorhanden.
  • event.appId: Die Firebase-App-ID, mit der die Anfrage gestellt wurde.
  • event.androidPackageName / event.iosBundleId: Der Paketname oder die Bundle-ID der aufrufenden App (gilt für Android- bzw. Apple-Plattformen).
  • event.data: Die Ereignisnutzlast, die sich zwischen Funktionen vor und nach der Anfrage unterscheidet:

Ereignisdaten vorab anfordern (beforeGenerateContent)

In einer beforeGenerateContent-Funktion wird event.data mit einem BeforeGenerateContentData-Objekt gefüllt:

  • event.data.api: Der Gemini API-Bereitsteller: geminiV1Beta (Gemini Developer API) oder vertexV1Beta1 (Agent Platform Gemini API (formerly Vertex AI)).
  • event.data.model: Der vollständige Modellressourcenpfad, z. B. projects/{PROJECT_ID}/locations/global/publishers/google/models/gemini-3.8-flash.
  • event.data.template: Metadaten zur verwendeten Server-Promptvorlage (PromptTemplateInfo), falls zutreffend.
  • event.data.request: Die Nutzlast der ausgehenden Anfrage. Der Objekttyp und die Eigenschaften hängen vom Gemini API-Anbieter ab:

Ereignisdaten nach der Anfrage (afterGenerateContent)

In einer afterGenerateContent-Funktion wird event.data mit einem AfterGenerateContentData-Objekt gefüllt. Dieses Objekt erweitert BeforeGenerateContentData (mit api, model, template und request) und fügt die Antwort des Modells hinzu:



Einschränkungen und Verhalten

Beachten Sie bei der Implementierung dieser Funktionen die folgenden Verhaltensweisen und Einschränkungen:

  • Nur generateContent-Anfragen: Diese Funktionen können nur durch generateContent-Anfragen an die Gemini API über Firebase AI Logic ausgelöst werden.

    Die folgenden Ereignisse lösen diese Funktionen nicht aus und die Funktionen werden für diese Anfrage unbemerkt umgangen:

    • Anfragen an generateContentStream lösen diese Funktionen nicht aus.

    • Anfragen an Gemini Live API lösen diese Funktionen nicht aus.

  • Keine clientseitigen Codeänderungen: Sie müssen lediglich dafür sorgen, dass Sie generateContent-Anfragen verwenden, wenn Sie diese Funktionen ausführen möchten. An Ihrer clientseitigen Codebasis sind keine Änderungen erforderlich.

    Diese Funktionen werden auf unseren Servern bereitgestellt und als Firebase AI Logic-Trigger registriert, damit der Firebase AI Logic-Proxy Anfragen und Antworten serverseitig abfangen kann.

  • Bereich auf Projektebene: Sie können maximal eine beforeGenerateContent-Funktion und eine afterGenerateContent-Funktion pro Firebase-Projekt bereitstellen.

  • Standardspeicherorte: Diese Funktionen werden standardmäßig in us-central1 bereitgestellt. Weitere Informationen zu Speicherorten für Funktionen Die Funktion wird jedoch unabhängig davon, wo Sie sie bereitstellen, als Firebase AI Logic-Trigger in der Region global registriert.