Uruchamianie niestandardowych skryptów po stronie serwera przed żądaniami i po nich


Możesz uruchamiać własne niestandardowe skrypty po stronie serwera przed każdym żądaniem wysyłanym przez aplikację do Gemini API za pomocą Firebase AI Logic i po nim – bez zmiany kodu klienta. Te skrypty implementuje się jako funkcje w stylu wywołania zwrotnego wdrożone w Cloud Functions for Firebase.

Dzięki tej funkcji możesz m.in. moderować prompty, ograniczać wykorzystanie tokenów, rejestrować wygenerowane treści na potrzeby analizy lub redagować treści odpowiedzi.

Dostępne są 2 typy zdarzeń:

  • beforeGenerateContent: uruchamia się, zanim żądanie dotrze do Gemini API. Funkcja może sprawdzać lub modyfikować żądanie albo całkowicie je blokować, zgłaszając błąd.

  • afterGenerateContent: uruchamia się po wysłaniu odpowiedzi z Gemini API i przed jej zwróceniem do aplikacji klienckiej. Funkcja może sprawdzać lub modyfikować odpowiedź, całkowicie ją blokować lub tylko ją obserwować (np. na potrzeby logowania lub kontroli).

Gdy skrypty zostaną wdrożone jako funkcje w Cloud Functions for Firebase, zostaną zarejestrowane jako wyzwalacze Firebase AI Logic, co oznacza, że będą uruchamiane przy każdym żądaniu generateContent w Twoim projekcie do Gemini API przez Firebase AI Logic (w tym żądaniach wysyłanych za pomocą szablonów promptów serwera).

Te funkcje nie są aktywowane przez żądania wysyłane do Gemini API, które nie przechodzą przez Firebase AI Logic.

Wymagania wstępne

Krok 1. Skonfiguruj projekt w Cloud Functions for Firebase

Jeśli nigdy nie używano Cloud Functions for Firebase w projekcie w Firebase, wykonaj te czynności konfiguracyjne.

  1. Upewnij się, że Twój projekt w Firebase jest objęty abonamentem Blaze z płatnością według wykorzystania (wymaganym do korzystania z Cloud Functions for Firebase).

  2. Zainstaluj interfejsy wiersza poleceń (CLI): gcloud CLI i Firebase CLI

  3. Przypisz do domyślnego konta usługi Compute rolę konto usługi Cloud Build (roles/cloudbuild.builds.builder), której potrzebuje do utworzenia funkcji. Uruchom to polecenie gcloud CLI:

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

    1. Uruchom to polecenie Firebase w interfejsie wiersza poleceń:

      firebase init functions
      
    2. Gdy pojawi się prośba, wybierz TypeScript.

    3. Upewnij się, że firebase-functions w functions/package.json jest w wersji 6.3.0 lub nowszej. Aby sprawdzić wersję:

      npm --prefix functions list firebase-functions
      

Krok 2. Napisz funkcje

Tworzenie funkcji przed żądaniem (beforeGenerateContent) Tworzenie funkcji po żądaniu (afterGenerateContent)

Napisz funkcję przed żądaniem (beforeGenerateContent)

W przypadku typu zdarzenia beforeGenerateContent funkcja jest aktywowana, gdy serwer proxy Firebase AI Logic otrzymuje żądanie generateContent. Funkcja jest uruchamiana w odniesieniu do żądania przed wysłaniem żądania do Gemini API. Funkcja może zmodyfikować żądanie lub całkowicie je zablokować.

Zanim napiszesz funkcję, zapoznaj się z tymi informacjami:

Przykład

Oto przykład funkcji pre-request, która wykonuje te czynności:

  • Określa, że funkcja powinna być uruchamiana tylko wtedy, gdy żądanie dotyczy konkretnego dostawcy Gemini API.

  • Sprawdza prompta pod kątem zablokowanych tematów i odrzuca żądanie, zgłaszając błąd.

  • Ogranicza maksymalną liczbę tokenów wyjściowych w modelach generujących tekst.

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

Najważniejsze kwestie dotyczące funkcji przed wysłaniem żądania

  • Określ dostawcę Gemini API: event.data.request może dotyczyć Gemini Developer API lub Agent Platform Gemini API (formerly Vertex AI). Obiekty żądań dla tych różnych interfejsów API mają różne kształty. Aby bezpiecznie pracować z obiektem żądania, musisz sprawdzić event.data.api (np. porównać odpowiednio z geminiV1Beta lub vertexV1Beta1).

  • Zgłoszenie błędu blokuje żądanie: jeśli zgłosisz błąd HttpsError, żądanie zostanie odrzucone.

  • Zwróć całe żądanie: jeśli funkcja modyfikuje żądanie, musisz zwrócić cały zmodyfikowany obiekt żądania. Jeśli nic nie zwrócisz (lub zwrócisz undefined), żądanie pozostanie niezmienione.

  • Przetestuj pod kątem opóźnień: w zależności od tego, co robi funkcja, może ona powodować opóźnienia i wpływać na wrażenia użytkowników.

Napisz funkcję obsługującą żądanie POST (afterGenerateContent)

W przypadku typu zdarzenia afterGenerateContent funkcja jest aktywowana, gdy serwer proxy Firebase AI Logic otrzymuje odpowiedź na żądanie generateContent. Funkcja jest uruchamiana w odpowiedzi przed zwróceniem odpowiedzi do aplikacji klienckiej. Funkcja może rejestrować wykorzystanie, modyfikować odpowiedź lub całkowicie ją blokować.

Zanim napiszesz funkcję, zapoznaj się z tymi informacjami:

Przykład

Oto przykład funkcji post-request, która rejestruje wykorzystanie tokenów i przyczynę zakończenia:

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

Najważniejsze kwestie dotyczące funkcji po żądaniu

  • Określ dostawcę Gemini API: event.data.response może dotyczyć Gemini Developer API lub Agent Platform Gemini API (formerly Vertex AI). Aby bezpiecznie rzutować obiekt żądania i pracować z nim, musisz sprawdzić event.data.api (np. porównać odpowiednio z geminiV1Beta lub vertexV1Beta1).

  • Przetestuj pod kątem opóźnień: w zależności od tego, co robi funkcja, może ona powodować opóźnienia i wpływać na wrażenia użytkowników.

Krok 3. Wdróż funkcje

Wdrożenie funkcji w Firebase przyznaje agentowi usługi Firebase AI Logic uprawnienia do wywoływania tych funkcji i rejestruje każdą funkcję jako Firebase AI Logic aktywator.

  1. Wdróż funkcje za pomocą interfejsu wiersza poleceń Firebase:

    firebase deploy --only functions
    
  2. Po wdrożeniu sprawdź, czy funkcje zostały wdrożone w Firebase:

    firebase functions:list
    
  3. Jeśli chcesz wprowadzić zmiany w funkcji:

    Zaktualizuj funkcję w katalogu projektu, a następnie ponownie uruchom firebase deploy --only functions.

Zatrzymywanie działania funkcji

Aby zatrzymać działanie jednej z tych funkcji, musisz ją usunąć z naszych serwerów oraz wyrejestrować jako wyzwalacz Firebase AI Logic. Możesz to zrobić za pomocą interfejsu wiersza poleceń Firebase, korzystając z jednej z tych opcji:

  • Opcja 1. Usunięcie funkcji w sposób domyślny

    1. Usuń funkcję z bazy kodu katalogu projektu.

    2. Uruchom to polecenie Firebase w interfejsie wiersza poleceń:

      firebase deploy --only functions
      
  • Opcja 2. Usuń funkcję bezpośrednio

    1. Usuń funkcję z bazy kodu katalogu projektu.

    2. Uruchom to polecenie Firebase w interfejsie wiersza poleceń:

      firebase functions:delete FUNCTION_NAME
      



Dokumentacja danych zdarzeń

Zarówno beforeGenerateContent, jak i afterGenerateContent otrzymują obiekt AIBlockingEvent zawierający kontekst i metadane dotyczące żądania.

Metadane żądania najwyższego poziomu (AIBlockingEvent)

Obiekt najwyższego poziomu AIBlockingEvent zawiera informacje o wywołującym i środowisku wyzwalającym:

  • event.authType: stan uwierzytelniania rozmówcy: "app_user", "unauthenticated" lub "unknown".
  • event.authId: identyfikator UID uwierzytelniania Firebase elementu wywołującego, jeśli jest zalogowany.
  • event.authClaims: niestandardowe oświadczenia uwierzytelniające rozmówcy (jeśli występują).
  • event.appId: identyfikator aplikacji w Firebase, która wysłała żądanie.
  • event.androidPackageName / event.iosBundleId: nazwa pakietu lub identyfikator pakietu aplikacji wywołującej (odpowiednio w przypadku platform Android i Apple).
  • event.data: ładunek zdarzenia, który różni się w przypadku funkcji przed żądaniem i po żądaniu:

Dane zdarzenia przed żądaniem (beforeGenerateContent)

W funkcji beforeGenerateContent parametr event.data jest wypełniany obiektem BeforeGenerateContentData:

  • event.data.api: dostawca Gemini API: geminiV1Beta (Gemini Developer API) lub vertexV1Beta1 (Agent Platform Gemini API (formerly Vertex AI)).
  • event.data.model: pełna ścieżka zasobu modelu (np. projects/{PROJECT_ID}/locations/global/publishers/google/models/gemini-3.8-flash).
  • event.data.template: metadane dotyczące użytego szablonu prompta serwera (PromptTemplateInfo), jeśli dotyczy.
  • event.data.request: ładunek żądania wychodzącego. Typ obiektu i właściwości zależą od dostawcy Gemini API:

Dane zdarzenia po żądaniu (afterGenerateContent)

W funkcji afterGenerateContent parametr event.data jest wypełniany obiektem AfterGenerateContentData. Ten obiekt rozszerza BeforeGenerateContentData (zapewniając api, model, template i request) oraz dodaje odpowiedź modelu:



Ograniczenia i zachowania

Podczas implementowania tych funkcji pamiętaj o tych zachowaniach i ograniczeniach:

  • Tylko żądania generateContent: te funkcje mogą być aktywowane tylko przez żądania generateContent wysyłane do Gemini API przez Firebase AI Logic.

    Te funkcje nie zostaną wywołane w przypadku poniższych żądań i zostaną po cichu pominięte:

    • Żądania wysyłane do generateContentStream nie będą wywoływać tych funkcji.

    • Żądania wysyłane do Gemini Live API nie będą wywoływać tych funkcji.

  • Brak zmian w kodzie po stronie klienta: poza upewnieniem się, że używasz żądań generateContent, gdy chcesz uruchomić te funkcje, nie musisz wprowadzać żadnych zmian w bazie kodu po stronie klienta.

    Te funkcje są wdrażane na naszych serwerach i rejestrowane jako wyzwalacze Firebase AI Logic, dzięki czemu serwer proxy Firebase AI Logic może przechwytywać żądania i odpowiedzi po stronie serwera.

  • Zakres na poziomie projektu: w każdym projekcie w Firebase możesz wdrożyć maksymalnie 1 funkcję beforeGenerateContent i 1 funkcję afterGenerateContent.

  • Domyślne lokalizacje: te funkcje będą domyślnie wdrażane w regionie us-central1 (dowiedz się więcej o lokalizacjach funkcji). Funkcja zostanie jednak zarejestrowana jako aktywator Firebase AI Logic w regionie global niezależnie od tego, gdzie ją wdrożysz.