Как выполнять специальные серверные скрипты до и после запросов


Вы можете запускать собственные серверные скрипты до и после каждого запроса, который ваше приложение отправляет в Gemini API через Firebase AI Logic, не меняя код клиента. Эти скрипты реализуются как функции обратного вызова, развернутые в Cloud Functions for Firebase.

С помощью этой функции вы можете модерировать запросы, ограничивать использование токенов, регистрировать генерации для аналитики или редактировать контент ответов.

Доступно два типа событий:

  • beforeGenerateContent – выполняется до того, как запрос достигнет Gemini API. Функция может проверить или изменить запрос или полностью заблокировать его, выдав ошибку.

  • afterGenerateContent – выполняется после того, как ответ отправлен обратно из Gemini API, и до того, как он возвращен клиентскому приложению. Функция может проверять или изменять ответ, полностью блокировать его или просто наблюдать за ним (например, для ведения журнала или аудита).

После развертывания скриптов в качестве функций в Cloud Functions for Firebase они регистрируются как триггеры Firebase AI Logic. Это означает, что они будут выполняться для каждого запроса generateContent в вашем проекте к Gemini API через Firebase AI Logic (включая запросы, сделанные с помощью шаблонов запросов сервера).

Эти функции не активируются запросами к Gemini API, которые не проходят через Firebase AI Logic.

Требования

Шаг 1. Настройте проект для Cloud Functions for Firebase

Если вы никогда не использовали Cloud Functions for Firebase в проекте Firebase, выполните следующие действия.

  1. Убедитесь, что в проекте Firebase используется тарифный план Blaze с оплатой по мере использования (требуется для работы с Cloud Functions for Firebase).

  2. Установите интерфейсы командной строки (CLI): gcloud CLI и Firebase CLI

  3. Назначьте сервисному аккаунту Compute Engine по умолчанию роль сервисного аккаунта 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. Инициализируйте Cloud Functions for Firebase в проекте Firebase:

    1. Выполните следующую команду CLI Firebase:

      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 получает запрос generateContent. Функция выполняется для запроса до его отправки в Gemini API. Функция может изменить запрос или полностью заблокировать его.

Прежде чем писать функцию, ознакомьтесь со следующей информацией:

Пример

Ниже приведен пример функции pre-request, которая выполняет следующие действия:

  • Указывает, что функция должна выполняться, только когда запрос предназначен для определенного поставщика 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-request (afterGenerateContent)

При использовании типа события afterGenerateContent функция активируется, когда прокси-сервер Firebase AI Logic получает ответ на запрос generateContent. Функция выполняется для ответа до того, как он возвращается в клиентское приложение. Функция может регистрировать использование, изменять ответ или полностью его блокировать.

Прежде чем писать функцию, ознакомьтесь со следующей информацией:

Пример

Ниже приведен пример функции post-request, которая регистрирует использование токенов и причину завершения.

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. Разверните функции с помощью CLI Firebase:

    firebase deploy --only functions
    
  2. После развертывания убедитесь, что ваши функции развернуты в Firebase:

    firebase functions:list
    
  3. Если вам нужно изменить функцию:

    Обновите функцию в каталоге проекта и снова запустите firebase deploy --only functions.

Как остановить выполнение функции

Чтобы остановить выполнение одной из этих функций, ее необходимо удалить с наших серверов и отменить ее регистрацию в качестве триггера Firebase AI Logic. Это можно сделать с помощью Firebase CLI одним из следующих способов:

  • Вариант 1. Неявное удаление функции

    1. Удалите функцию из базы кода каталога проекта.

    2. Выполните следующую команду CLI Firebase:

      firebase deploy --only functions
      
  • Вариант 2. Удалите функцию явным образом

    1. Удалите функцию из базы кода каталога проекта.

    2. Выполните следующую команду CLI Firebase:

      firebase functions:delete FUNCTION_NAME
      



Справка по данным о событиях

И beforeGenerateContent, и afterGenerateContent получают объект AIBlockingEvent, содержащий контекст и метаданные запроса.

Метаданные запроса верхнего уровня (AIBlockingEvent)

Объект верхнего уровня AIBlockingEvent содержит информацию о вызывающем объекте и среде, в которой он был активирован.

  • event.authType – статус аутентификации вызывающего абонента: "app_user", "unauthenticated" или "unknown".
  • event.authId – UID Firebase Authentication вызывающего абонента, если он вошел в систему.
  • event.authClaims – специальные утверждения вызывающего абонента, если они есть.
  • event.appId: идентификатор приложения Firebase, которое отправило запрос.
  • event.androidPackageName/event.iosBundleId – название пакета или идентификатор пакета вызывающего приложения (для платформ 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) и добавляет ответ модели:

  • event.data.response: полезная нагрузка ответа модели. Тип объекта и свойства зависят от поставщика Gemini API:



Ограничения и особенности работы

При реализации этих функций учитывайте следующие особенности и ограничения:

  • Только запросы generateContent. Эти функции могут запускаться только запросами generateContent к Gemini API через Firebase AI Logic.

    Функции не будут активированы и будут проигнорированы для запроса в следующих случаях:

    • Запросы к generateContentStream не будут активировать эти функции.

    • Запросы к Gemini Live API не будут активировать эти функции.

  • Не нужно менять клиентский код. Вам не придется вносить изменения в клиентскую базу кода. Достаточно лишь убедиться, что для выполнения этих функций вы используете запросы generateContent.

    Эти функции развертываются на наших серверах и регистрируются как триггеры Firebase AI Logic, чтобы прокси-сервер Firebase AI Logic мог перехватывать запросы и ответы на стороне сервера.

  • Область действия на уровне проекта. В каждом проекте Firebase можно развернуть не более одной функции beforeGenerateContent и одной функции afterGenerateContent.

  • Местоположения по умолчанию. Эти функции будут развернуты в us-central1 по умолчанию (подробнее о местоположениях для функций). Однако функция будет зарегистрирована как триггер Firebase AI Logic в регионе global независимо от того, где вы ее развернете.