Запуск пользовательских серверных скриптов до и после запросов.


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

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

Доступны два типа мероприятий:

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

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

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

Эти функции не запускаются запросами к API Gemini , которые не поступают через 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. Предоставьте учетной записи вычислительной службы по умолчанию роль учетной записи службы сборки облака ( 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. Выполните следующую команду Firebase CLI:

      firebase init functions
      
    2. При появлении запроса выберите TypeScript .

    3. Убедитесь, что версия firebase-functions в вашем functions/package.json — 6.3.0 или более поздняя . Вот как проверить свою версию:

      npm --prefix functions list firebase-functions
      

Шаг 2 : Напишите свои функции

Напишите функцию перед запросом ( beforeGenerateContent ) Напишите функцию после запроса ( afterGenerateContent )

Напишите функцию предварительного запроса ( beforeGenerateContent ).

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

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

Пример

Вот пример функции предварительного запроса , которая выполняет следующие действия:

  • Указывает, что функция должна выполняться только тогда, когда запрос поступает к конкретному поставщику API Gemini .

  • Проверяет приглашение на наличие заблокированных тем и отклоняет запрос, выдавая ошибку.

  • Устанавливает ограничение на максимальное количество выходных токенов для моделей генерации текста.

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

Ключевые моменты, которые следует учитывать при выполнении функций, предшествующих запросу.

  • Укажите поставщика API Gemini : event.data.request может относиться либо к API разработчика Gemini , либо к API платформы агентов Gemini (ранее Vertex AI) . Объекты запроса для этих разных API имеют разную структуру. Для безопасной работы с объектом запроса необходимо проверить event.data.api (например, сравните geminiV1Beta или vertexV1Beta1 соответственно).

  • Выбрасывание исключения блокирует запрос: если вы выбросите исключение HttpsError , запрос будет отклонен.

  • Возвращать весь запрос: если ваша функция изменяет запрос, то вы должны вернуть полный, измененный объект запроса. Возвращение пустого значения (или undefined ) оставляет запрос без изменений.

  • Проверка на задержку: В зависимости от того, что делает ваша функция, она может добавлять задержку и влиять на пользовательский опыт.

Напишите функцию для обработки POST-запроса ( afterGenerateContent ).

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

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

Пример

Вот пример функции обработки POST-запроса , которая регистрирует использование токена и причину завершения:

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

Ключевые аспекты, которые следует учитывать при выполнении функций после запроса.

  • Укажите поставщика API Gemini : event.data.response может быть либо для API разработчика Gemini , либо для API платформы агентов Gemini (ранее Vertex AI) . Для безопасного преобразования типов и работы с объектом запроса необходимо проверить event.data.api (например, сравните с geminiV1Beta или vertexV1Beta1 соответственно).

  • Проверка на задержку: В зависимости от того, что делает ваша функция, она может добавлять задержку и влиять на пользовательский опыт.

Шаг 3 : Разверните свои функции

Развертывание ваших функций в Firebase предоставляет агенту службы Firebase AI Logic разрешение на вызов этих функций и регистрирует каждую функцию как триггер Firebase AI Logic .

  1. Развертывайте свои функции с помощью Firebase CLI:

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

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

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

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

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

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

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

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

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

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

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

      firebase functions:delete FUNCTION_NAME
      



Справочная информация о событиях

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

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

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

  • event.authType : Состояние аутентификации вызывающего объекта: "app_user" , "unauthenticated" или "unknown" .
  • event.authId : UID аутентификации Firebase вызывающего пользователя, если он авторизован.
  • event.authClaims : Пользовательские утверждения аутентификации вызывающей стороны, если таковые имеются.
  • event.appId : Идентификатор приложения Firebase, отправившего запрос.
  • event.androidPackageName / event.iosBundleId : Имя пакета или идентификатор пакета вызывающего приложения (применимо для платформ Android и Apple соответственно).
  • event.data : Полезная нагрузка события, которая различается для функций, выполняемых до и после запроса:

Данные события перед запросом ( beforeGenerateContent )

В функции beforeGenerateContent event.data заполняется объектом BeforeGenerateContentData :

  • event.data.api : Поставщик API Gemini : geminiV1Beta ( Gemini Developer API ) или vertexV1Beta1 ( Agent Platform Gemini API (ранее Vertex AI) ).
  • event.data.model : Полный путь к ресурсу модели (например, projects/{PROJECT_ID}/locations/global/publishers/google/models/gemini-3.8-flash ).
  • event.data.template : Метаданные об используемом шаблоне приглашения сервера ( PromptTemplateInfo ), если применимо.
  • event.data.request : Содержимое исходящего запроса. Тип объекта и его свойства зависят от поставщика API Gemini :

Данные события после запроса ( afterGenerateContent )

В функции afterGenerateContent event.data заполняется объектом AfterGenerateContentData . Этот объект наследует BeforeGenerateContentData (предоставляя api , model , template и request ) и добавляет ответ модели:

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



Ограничения и модели поведения

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

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

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

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

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

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

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

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

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