Exécuter des scripts côté serveur personnalisés avant et après les requêtes


Vous pouvez exécuter vos propres scripts côté serveur personnalisés avant et après chaque requête envoyée par votre application à Gemini API via Firebase AI Logic, sans modifier votre code client. Vous implémentez ces scripts en tant que fonctions de style rappel déployées sur Cloud Functions for Firebase.

Cette fonctionnalité vous permet par exemple de modérer les requêtes, de limiter l'utilisation des jetons, de consigner les générations à des fins d'analyse ou de masquer le contenu des réponses.

Deux types d'événements sont disponibles :

  • beforeGenerateContent : s'exécute avant qu'une requête n'atteigne Gemini API. La fonction peut inspecter ou modifier la requête, ou la bloquer entièrement en générant une erreur.

  • afterGenerateContent : s'exécute après que la réponse a été renvoyée par Gemini API et avant qu'elle ne soit renvoyée à l'application cliente. La fonction peut inspecter ou modifier la réponse, la bloquer entièrement ou simplement l'observer (par exemple, pour la journalisation ou l'audit).

Une fois vos scripts déployés en tant que fonctions dans Cloud Functions for Firebase, ils sont enregistrés en tant que déclencheurs Firebase AI Logic, ce qui signifie qu'ils s'exécuteront pour chaque requête generateContent de votre projet vers Gemini API via Firebase AI Logic (y compris les requêtes effectuées avec des modèles de prompt de serveur).

Ces fonctions ne sont pas déclenchées par les requêtes envoyées à Gemini API qui ne passent pas par Firebase AI Logic.

Prérequis

Étape 1 : Configurez votre projet pour Cloud Functions for Firebase

Si vous n'avez jamais utilisé Cloud Functions for Firebase dans votre projet Firebase, effectuez la configuration suivante.

  1. Assurez-vous que votre projet Firebase est associé au forfait Blaze avec paiement à l'usage (obligatoire pour utiliser Cloud Functions for Firebase).

  2. Installez les interfaces de ligne de commande (CLI) : gcloud CLI et Firebase CLI.

  3. Attribuez au compte de service Compute par défaut le rôle Compte de service Cloud Build (roles/cloudbuild.builds.builder) dont il a besoin pour créer votre fonction. Exécutez la commande gcloud CLI suivante :

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member="serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
      --role="roles/cloudbuild.builds.builder"
    
  4. Initialisez Cloud Functions for Firebase dans votre projet Firebase :

    1. Exécutez la commande Firebase CLI suivante :

      firebase init functions
      
    2. Lorsque vous y êtes invité, choisissez TypeScript.

    3. Assurez-vous que firebase-functions dans votre functions/package.json est la version 6.3.0 ou ultérieure. Pour vérifier la version de votre appareil :

      npm --prefix functions list firebase-functions
      

Étape 2 : Écrivez vos fonctions

Écrire une fonction de pré-requête (beforeGenerateContent) Écrire une fonction de post-requête (afterGenerateContent)

Écrire une fonction de pré-requête (beforeGenerateContent)

Avec le type d'événement beforeGenerateContent, la fonction est déclenchée lorsque le proxy Firebase AI Logic reçoit une requête generateContent. La fonction s'exécute sur la requête avant que celle-ci ne soit envoyée à Gemini API. La fonction peut modifier la requête ou la bloquer complètement.

Veillez à lire les informations suivantes avant d'écrire votre fonction :

Exemple

Voici un exemple de fonction de pré-requête qui effectue les opérations suivantes :

  • Spécifie que la fonction ne doit s'exécuter que lorsque la requête concerne un fournisseur Gemini API spécifique.

  • Inspecte la requête pour détecter les sujets bloqués et la rejette en générant une erreur.

  • Limite le nombre maximal de jetons de sortie pour les modèles génératifs de texte.

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

Points clés à prendre en compte pour les fonctions de pré-requête

  • Spécifiez le fournisseur Gemini API : event.data.request peut être destiné à Gemini Developer API ou à Agent Platform Gemini API (formerly Vertex AI). Les objets de requête de ces différentes API ont des formes différentes. Pour travailler en toute sécurité avec l'objet de requête, vous devez vérifier event.data.api (par exemple, comparer respectivement à geminiV1Beta ou vertexV1Beta1).

  • Le lancement bloque la requête : si vous lancez une HttpsError, la requête sera rejetée.

  • Renvoyer l'intégralité de la requête : si votre fonction modifie la requête, vous devez renvoyer l'objet de requête complet et modifié. Si vous ne renvoyez rien (ou undefined), la requête reste inchangée.

  • Tester la latence : selon ce que fait votre fonction, elle peut ajouter de la latence et avoir un impact sur l'expérience utilisateur.

Écrire une fonction post-requête (afterGenerateContent)

Avec le type d'événement afterGenerateContent, la fonction est déclenchée lorsque le proxy Firebase AI Logic reçoit une réponse d'une requête generateContent. La fonction s'exécute sur la réponse avant que celle-ci ne soit renvoyée à l'application cliente. Elle peut consigner l'utilisation, modifier la réponse ou la bloquer complètement.

Veillez à lire les informations suivantes avant d'écrire votre fonction :

Exemple

Voici un exemple de fonction post-requête qui consigne l'utilisation des jetons et le motif de fin :

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

Points clés à prendre en compte pour les fonctions post-requête

  • Spécifiez le fournisseur Gemini API : event.data.response peut être destiné à Gemini Developer API ou à Agent Platform Gemini API (formerly Vertex AI). Pour caster et utiliser l'objet de requête en toute sécurité, vous devez vérifier event.data.api (par exemple, comparer respectivement à geminiV1Beta ou vertexV1Beta1).

  • Tester la latence : selon ce que fait votre fonction, elle peut ajouter de la latence et avoir un impact sur l'expérience utilisateur.

Étape 3 : Déployez vos fonctions

Le déploiement de vos fonctions sur Firebase accorde à l'agent de service Firebase AI Logic l'autorisation d'appeler ces fonctions et enregistre chaque fonction en tant que déclencheur Firebase AI Logic.

  1. Déployez vos fonctions à l'aide de la CLI Firebase :

    firebase deploy --only functions
    
  2. Après le déploiement, vérifiez que vos fonctions ont été déployées sur Firebase :

    firebase functions:list
    
  3. Si vous devez itérer sur votre fonction :

    Mettez à jour la fonction dans le répertoire de votre projet, puis exécutez à nouveau firebase deploy --only functions.

Arrêter l'exécution d'une fonction

Pour arrêter l'exécution de l'une de ces fonctions, vous devez la supprimer de nos serveurs et annuler son enregistrement en tant que déclencheur Firebase AI Logic. Pour ce faire, utilisez la CLI Firebase avec l'une des options suivantes :

  • Option 1 : Supprimer la fonction de manière implicite

    1. Supprimez la fonction de la codebase du répertoire de votre projet.

    2. Exécutez la commande Firebase CLI suivante :

      firebase deploy --only functions
      
  • Option 2 : Supprimer explicitement la fonction

    1. Supprimez la fonction de la codebase du répertoire de votre projet.

    2. Exécutez la commande Firebase CLI suivante :

      firebase functions:delete FUNCTION_NAME
      



Référence des données d'événement

beforeGenerateContent et afterGenerateContent reçoivent tous deux un objet AIBlockingEvent contenant le contexte et les métadonnées de la requête.

Métadonnées de requête de premier niveau (AIBlockingEvent)

L'objet AIBlockingEvent de premier niveau fournit des informations sur l'appelant et l'environnement de déclenchement :

  • event.authType : état d'authentification de l'appelant : "app_user", "unauthenticated" ou "unknown".
  • event.authId : UID Firebase Authentication de l'appelant, s'il est connecté.
  • event.authClaims : revendications d'authentification personnalisées de l'appelant, le cas échéant.
  • event.appId : ID de l'application Firebase qui a effectué la requête.
  • event.androidPackageName / event.iosBundleId : nom du package ou ID du bundle de l'application appelante (applicable respectivement aux plates-formes Android ou Apple).
  • event.data : charge utile de l'événement, qui diffère entre les fonctions de pré-requête et de post-requête :

Données d'événement de pré-requête (beforeGenerateContent)

Dans une fonction beforeGenerateContent, event.data est renseigné avec un objet BeforeGenerateContentData :

  • event.data.api : fournisseur Gemini API : geminiV1Beta (Gemini Developer API) ou vertexV1Beta1 (Agent Platform Gemini API (formerly Vertex AI)).
  • event.data.model : chemin d'accès complet à la ressource de modèle (par exemple, projects/{PROJECT_ID}/locations/global/publishers/google/models/gemini-3.8-flash).
  • event.data.template : métadonnées sur le modèle de prompt du serveur utilisé (PromptTemplateInfo), le cas échéant.
  • event.data.request : charge utile de la requête sortante. Le type d'objet et les propriétés dépendent du fournisseur Gemini API :

Données d'événement post-requête (afterGenerateContent)

Dans une fonction afterGenerateContent, event.data est renseigné avec un objet AfterGenerateContentData. Cet objet étend BeforeGenerateContentData (en fournissant api, model, template et request) et ajoute la réponse du modèle :



Limites et comportements

Lorsque vous implémentez ces fonctions, tenez compte des comportements et des limites suivants :

  • Requêtes generateContent uniquement : ces fonctions ne peuvent être déclenchées que par des requêtes generateContent envoyées à Gemini API via Firebase AI Logic.

    Les éléments suivants ne déclencheront pas ces fonctions, et les fonctions seront ignorées silencieusement pour cette requête :

    • Les requêtes envoyées à generateContentStream ne déclencheront pas ces fonctions.

    • Les requêtes adressées à Gemini Live API ne déclencheront pas ces fonctions.

  • Aucune modification du code côté client : à part vous assurer que vous utilisez des requêtes generateContent lorsque vous souhaitez exécuter ces fonctions, aucune modification n'est requise dans votre codebase côté client.

    Ces fonctions sont déployées sur nos serveurs et enregistrées en tant que déclencheurs Firebase AI Logic afin que le proxy Firebase AI Logic puisse intercepter les requêtes et les réponses côté serveur.

  • Champ d'application au niveau du projet : vous pouvez déployer au maximum une fonction beforeGenerateContent et une fonction afterGenerateContent par projet Firebase.

  • Emplacements par défaut : ces fonctions seront déployées par défaut dans us-central1 (en savoir plus sur les emplacements des fonctions). Toutefois, la fonction sera enregistrée en tant que déclencheur Firebase AI Logic dans la région global, quel que soit l'emplacement où vous déployez votre fonction.