Esegui script lato server personalizzati prima e dopo le richieste


Puoi eseguire i tuoi script lato server personalizzati prima e dopo ogni richiesta che la tua app invia a Gemini API tramite Firebase AI Logic, senza modificare il codice client. Puoi implementare questi script come funzioni di tipo callback di cui è stato eseguito il deployment in Cloud Functions for Firebase.

Con questa funzionalità, puoi moderare i prompt, limitare l'utilizzo dei token, registrare le generazioni per l'analisi o oscurare i contenuti delle risposte.

Sono disponibili due tipi di eventi:

  • beforeGenerateContent: viene eseguito prima che una richiesta raggiunga Gemini API. La funzione può ispezionare o modificare la richiesta oppure bloccarla completamente generando un errore.

  • afterGenerateContent: viene eseguito dopo che la risposta viene inviata dal Gemini API e prima che venga restituita all'app client. La funzione può ispezionare o modificare la risposta, bloccarla completamente o semplicemente osservarla (ad esempio per il logging o l'audit).

Una volta eseguito il deployment degli script come funzioni in Cloud Functions for Firebase, vengono registrati come trigger Firebase AI Logic, il che significa che verranno eseguiti per ogni richiesta generateContent nel tuo progetto a Gemini API tramite Firebase AI Logic (incluse le richieste effettuate con template di prompt del server).

Queste funzioni non vengono attivate dalle richieste effettuate a Gemini API che non passano tramite Firebase AI Logic.

Prerequisiti

Passaggio 1: configura il progetto per Cloud Functions for Firebase

Se non hai mai utilizzato Cloud Functions for Firebase nel tuo progetto Firebase, completa la seguente configurazione.

  1. Assicurati che il tuo progetto Firebase sia nel piano tariffario Blaze con pagamento a consumo (obbligatorio per utilizzare Cloud Functions for Firebase).

  2. Installa le interfacce a riga di comando (CLI): gcloud CLI e CLI Firebase

  3. Concedi al service account Compute predefinito il ruolo Cloud Build Service Account (roles/cloudbuild.builds.builder) di cui ha bisogno per creare la tua funzione. Esegui questo comando gcloud CLI:

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

    1. Esegui il seguente comando dell'interfaccia a riga di comando Firebase:

      firebase init functions
      
    2. Quando richiesto, scegli TypeScript.

    3. Assicurati che firebase-functions nel tuo functions/package.json sia la versione 6.3.0 o successive. Per controllare la versione:

      npm --prefix functions list firebase-functions
      

Passaggio 2: scrivi le funzioni

Scrivi una funzione di pre-richiesta (beforeGenerateContent) Scrivi una funzione di post-richiesta (afterGenerateContent)

Scrivi una funzione di pre-richiesta (beforeGenerateContent)

Con il tipo di evento beforeGenerateContent, la funzione viene attivata quando il proxy Firebase AI Logic riceve una richiesta generateContent. La funzione viene eseguita sulla richiesta prima che questa venga inviata a Gemini API. La funzione può modificare la richiesta o bloccarla completamente.

Prima di scrivere la funzione, assicurati di esaminare le seguenti informazioni:

Esempio

Ecco un esempio di funzione di pre-richiesta che esegue le seguenti operazioni:

  • Specifica che la funzione deve essere eseguita solo quando la richiesta riguarda un provider Gemini API specifico.

  • Esamina il prompt per individuare argomenti bloccati e rifiuta la richiesta generando un errore.

  • Limita il numero massimo di token di output per i modelli di generazione di testo.

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

Considerazioni principali per le funzioni di pre-richiesta

  • Specifica il provider Gemini API: event.data.request può essere per Gemini Developer API o Agent Platform Gemini API (formerly Vertex AI). Gli oggetti di richiesta per queste diverse API hanno forme diverse. Per lavorare in sicurezza con l'oggetto della richiesta, devi controllare event.data.api (ad esempio, confrontarlo rispettivamente con geminiV1Beta o vertexV1Beta1).

  • La generazione di un errore blocca la richiesta: se generi un errore HttpsError, la richiesta verrà rifiutata.

  • Restituisci l'intera richiesta: se la funzione modifica la richiesta, devi restituire l'oggetto della richiesta completo e modificato. Se non restituisci nulla (o restituisci undefined), la richiesta rimane invariata.

  • Esegui test per la latenza: a seconda di ciò che fa la funzione, potrebbe aggiungere latenza e influire sull'esperienza utente.

Scrivi una funzione post-richiesta (afterGenerateContent)

Con il tipo di evento afterGenerateContent, la funzione viene attivata quando il proxy Firebase AI Logic riceve una risposta da una richiesta generateContent. La funzione viene eseguita sulla risposta prima che questa venga restituita all'app client. La funzione può registrare l'utilizzo, modificare la risposta o bloccarla completamente.

Assicurati di esaminare le seguenti informazioni prima di scrivere la funzione:

Esempio

Ecco un esempio di funzione post-request che registra l'utilizzo dei token e il motivo della fine:

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

Considerazioni principali per le funzioni post-richiesta

  • Specifica il provider Gemini API: event.data.response può essere per Gemini Developer API o Agent Platform Gemini API (formerly Vertex AI). Per eseguire il cast e lavorare in sicurezza con l'oggetto della richiesta, devi controllare event.data.api (ad esempio, confrontalo rispettivamente con geminiV1Beta o vertexV1Beta1).

  • Esegui test per la latenza: a seconda di ciò che fa la funzione, potrebbe aggiungere latenza e influire sull'esperienza utente.

Passaggio 3: esegui il deployment delle funzioni

Il deployment delle funzioni in Firebase concede all'agente di servizio Firebase AI Logic l'autorizzazione per richiamare queste funzioni e registra ogni funzione come trigger Firebase AI Logic.

  1. Esegui il deployment delle funzioni utilizzando l'interfaccia a riga di comando Firebase:

    firebase deploy --only functions
    
  2. Dopo il deployment, verifica che sia stato eseguito il deployment delle funzioni in Firebase:

    firebase functions:list
    
  3. Se devi eseguire l'iterazione della funzione:

    Aggiorna la funzione nella directory del progetto, quindi esegui di nuovo firebase deploy --only functions.

Interrompi l'esecuzione di una funzione

Per interrompere l'esecuzione di una di queste funzioni, è necessario eliminarla dai nostri server e annullarne la registrazione come trigger Firebase AI Logic. Puoi farlo utilizzando l'interfaccia a riga di comando Firebase con una delle seguenti opzioni:

  • Opzione 1: elimina la funzione in modo implicito

    1. Rimuovi la funzione dal codebase della directory del progetto.

    2. Esegui il seguente comando dell'interfaccia a riga di comando Firebase:

      firebase deploy --only functions
      
  • Opzione 2: elimina la funzione in modo esplicito

    1. Rimuovi la funzione dal codebase della directory del progetto.

    2. Esegui il seguente comando dell'interfaccia a riga di comando Firebase:

      firebase functions:delete FUNCTION_NAME
      



Riferimento ai dati sugli eventi

Sia beforeGenerateContent che afterGenerateContent ricevono un oggetto AIBlockingEvent contenente il contesto e i metadati della richiesta.

Metadati della richiesta di primo livello (AIBlockingEvent)

L'oggetto di primo livello AIBlockingEvent fornisce informazioni sul chiamante e sull'ambiente di attivazione:

  • event.authType: stato di autenticazione del chiamante: "app_user", "unauthenticated" o "unknown".
  • event.authId: l'UID di Firebase Authentication del chiamante, se ha eseguito l'accesso.
  • event.authClaims: le attestazioni di autenticazione personalizzate del chiamante, se presenti.
  • event.appId: l'ID app Firebase che ha effettuato la richiesta.
  • event.androidPackageName/event.iosBundleId: il nome del pacchetto o l'ID pacchetto dell'app di chiamate (applicabile rispettivamente alle piattaforme Android o Apple).
  • event.data: il payload dell'evento, che varia tra le funzioni pre-richiesta e post-richiesta:

Dati sugli eventi di pre-richiesta (beforeGenerateContent)

In una funzione beforeGenerateContent, event.data viene compilato con un oggetto BeforeGenerateContentData:

  • event.data.api: il provider Gemini API: geminiV1Beta (Gemini Developer API) o vertexV1Beta1 (Agent Platform Gemini API (formerly Vertex AI)).
  • event.data.model: il percorso completo della risorsa del modello (ad esempio, projects/{PROJECT_ID}/locations/global/publishers/google/models/gemini-3.8-flash).
  • event.data.template: metadati relativi al template di prompt del server utilizzato (PromptTemplateInfo), se applicabile.
  • event.data.request: il payload della richiesta in uscita. Il tipo di oggetto e le proprietà dipendono dal provider Gemini API:

Dati sugli eventi post-richiesta (afterGenerateContent)

In una funzione afterGenerateContent, event.data viene compilato con un oggetto AfterGenerateContentData. Questo oggetto estende BeforeGenerateContentData (fornendo api, model, template e request) e aggiunge la risposta del modello:



Limitazioni e comportamenti

Quando implementi queste funzioni, tieni presente i seguenti comportamenti e limitazioni:

  • Solo richieste generateContent: queste funzioni possono essere attivate solo da richieste generateContent a Gemini API tramite Firebase AI Logic.

    Le seguenti azioni non attiveranno queste funzioni, che verranno ignorate silenziosamente per la richiesta:

    • Le richieste a generateContentStream non attiveranno queste funzioni.

    • Le richieste a Gemini Live API non attiveranno queste funzioni.

  • Nessuna modifica al codice lato client: oltre ad assicurarti di utilizzare le richieste generateContent quando vuoi eseguire queste funzioni, non sono necessarie modifiche al codebase lato client.

    Il deployment di queste funzioni viene eseguito sui nostri server e vengono registrate come trigger Firebase AI Logic in modo che il proxy Firebase AI Logic possa intercettare richieste e risposte lato server.

  • Ambito a livello di progetto: puoi eseguire il deployment di al massimo una funzione beforeGenerateContent e una funzione afterGenerateContent per progetto Firebase.

  • Località predefinite: per impostazione predefinita, il deployment di queste funzioni verrà eseguito in us-central1 (scopri di più sulle località per le funzioni). Tuttavia, la funzione verrà registrata come trigger Firebase AI Logic nella regione global, indipendentemente da dove esegui il deployment della funzione.