Executar scripts personalizados do lado do servidor antes e depois das solicitações


É possível executar seus próprios scripts personalizados do lado do servidor antes e depois de cada solicitação que o app envia ao Gemini API via Firebase AI Logicsem mudar o código do cliente. Implemente esses scripts como funções de estilo de callback implantadas em Cloud Functions for Firebase.

Com esse recurso, é possível moderar comandos, limitar o uso de tokens, registrar gerações para análise ou ocultar o conteúdo da resposta.

Há dois tipos de eventos disponíveis:

  • beforeGenerateContent: é executado antes que uma solicitação chegue ao Gemini API. A função pode inspecionar ou modificar a solicitação ou bloquear a solicitação por completo ao gerar um erro.

  • afterGenerateContent: é executada depois que a resposta é enviada de volta do Gemini API e antes de ser retornada ao app cliente. A função pode inspecionar ou modificar a resposta, bloquear a resposta completamente ou apenas observar a resposta (como para registro ou auditoria).

Depois que os scripts são implantados como funções no Cloud Functions for Firebase, eles são registrados como Firebase AI Logic gatilhos, o que significa que serão executados para cada solicitação generateContent no seu projeto para o Gemini API via Firebase AI Logic, incluindo solicitações feitas com modelos de comandos do servidor.

Essas funções não são acionadas por solicitações feitas ao Gemini API que não são feitas por Firebase AI Logic.

Pré-requisitos

Etapa 1: configurar seu projeto para o Cloud Functions for Firebase

Se você nunca usou o Cloud Functions for Firebase no seu projeto do Firebase, conclua a configuração a seguir.

  1. Verifique se o projeto do Firebase está no plano de preços Blaze de pagamento por uso (obrigatório para usar o Cloud Functions for Firebase).

  2. Instale as interfaces de linha de comando (CLIs): gcloud CLI e CLI Firebase.

  3. Conceda à conta de serviço padrão do Compute o papel de conta de serviço do Cloud Build (roles/cloudbuild.builds.builder) necessário para criar sua função. Execute este 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. Inicialize Cloud Functions for Firebase no seu projeto do Firebase:

    1. Execute o seguinte comando da CLI Firebase:

      firebase init functions
      
    2. Quando solicitado, escolha TypeScript.

    3. Verifique se o firebase-functions no seu functions/package.json é a versão 6.3.0 ou mais recente. Veja como verificar sua versão:

      npm --prefix functions list firebase-functions
      

Etapa 2: escrever as funções

Escrever uma função de pré-solicitação (beforeGenerateContent) Escrever uma função de pós-solicitação (afterGenerateContent)

Escrever uma função de pré-solicitação (beforeGenerateContent)

Com o tipo de evento beforeGenerateContent, a função é acionada quando o proxy Firebase AI Logic recebe uma solicitação generateContent. A função é executada na solicitação antes de ela ser enviada ao Gemini API. A função pode modificar ou bloquear completamente a solicitação.

Revise as informações a seguir antes de escrever sua função:

Exemplo

Confira um exemplo de função de pré-solicitação que faz o seguinte:

  • Especifica que a função só deve ser executada quando a solicitação for de um provedor Gemini API específico.

  • Inspeciona o comando em busca de tópicos bloqueados e rejeita a solicitação gerando um erro.

  • Limita o número máximo de tokens de saída para modelos de geração de texto.

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

Principais considerações sobre funções de pré-solicitação

  • Especifique o provedor Gemini API:event.data.request pode ser para Gemini Developer API ou Agent Platform Gemini API (formerly Vertex AI). Os objetos de solicitação dessas APIs têm formatos diferentes. Para trabalhar com segurança com o objeto de solicitação, verifique event.data.api (por exemplo, compare com geminiV1Beta ou vertexV1Beta1, respectivamente).

  • Gerar um erro bloqueia a solicitação:se você gerar um HttpsError, a solicitação será rejeitada.

  • Retorne a solicitação inteira:se a função modificar a solicitação, retorne o objeto de solicitação completo e modificado. Não retornar nada (ou undefined) deixa a solicitação inalterada.

  • Teste de latência:dependendo da função, ela pode adicionar latência e afetar a experiência do usuário.

Escrever uma função de pós-solicitação (afterGenerateContent)

Com o tipo de evento afterGenerateContent, a função é acionada quando o proxy Firebase AI Logic recebe uma resposta de uma solicitação generateContent. A função é executada na resposta antes de ela ser retornada ao app cliente. Ela pode registrar o uso, modificar ou bloquear a resposta completamente.

Revise as informações a seguir antes de escrever sua função:

Exemplo

Confira um exemplo de função pós-solicitação que registra o uso de tokens e o motivo da conclusão:

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

Principais considerações sobre funções pós-solicitação

  • Especifique o provedor Gemini API:event.data.response pode ser para Gemini Developer API ou Agent Platform Gemini API (formerly Vertex AI). Para fazer a transmissão e trabalhar com o objeto de solicitação com segurança, verifique event.data.api (por exemplo, compare com geminiV1Beta ou vertexV1Beta1, respectivamente).

  • Teste de latência:dependendo da função, ela pode adicionar latência e afetar a experiência do usuário.

Etapa 3: implante suas funções

A implantação das funções no Firebase concede ao agente de serviço do Firebase AI Logic permissão para invocar essas funções e registra cada uma delas como um gatilho do Firebase AI Logic.

  1. Implante suas funções usando a CLI do Firebase:

    firebase deploy --only functions
    
  2. Depois da implantação, confirme se as funções foram implantadas no Firebase:

    firebase functions:list
    
  3. Se você precisar iterar na sua função:

    Atualize a função no diretório do projeto e execute firebase deploy --only functions novamente.

Impedir que uma função seja executada

Para impedir que uma dessas funções seja executada, ela precisa ser excluída dos nossos servidores e ter o registro cancelado como um gatilho Firebase AI Logic. É possível fazer isso usando a CLI Firebase com uma das seguintes opções:

  • Opção 1: excluir a função implicitamente

    1. Remova a função da base de código do diretório do projeto.

    2. Execute o seguinte comando da CLI Firebase:

      firebase deploy --only functions
      
  • Opção 2: excluir a função explicitamente

    1. Remova a função da base de código do diretório do projeto.

    2. Execute o seguinte comando da CLI Firebase:

      firebase functions:delete FUNCTION_NAME
      



Referência de dados de eventos

Os dois beforeGenerateContent e afterGenerateContent recebem um objeto AIBlockingEvent que contém contexto e metadados sobre a solicitação.

Metadados de solicitação de nível superior (AIBlockingEvent)

O objeto de nível superior AIBlockingEvent fornece informações sobre o caller e o ambiente de acionamento:

  • event.authType: estado de autenticação do autor da chamada: "app_user", "unauthenticated" ou "unknown".
  • event.authId: o UID do Firebase Authentication do usuário que fez a chamada, se ele tiver feito login.
  • event.authClaims: as declarações de autenticação personalizadas do autor da chamada, se houver.
  • event.appId: o ID do app do Firebase que fez a solicitação.
  • event.androidPackageName / event.iosBundleId: o nome do pacote ou ID do pacote do app de chamada (aplicável para plataformas Android ou Apple, respectivamente).
  • event.data: o payload do evento, que difere entre as funções de pré-solicitação e pós-solicitação:

Dados de eventos de pré-solicitação (beforeGenerateContent)

Em uma função beforeGenerateContent, event.data é preenchido com um objeto BeforeGenerateContentData:

  • event.data.api: o provedor Gemini API: geminiV1Beta (Gemini Developer API) ou vertexV1Beta1 (Agent Platform Gemini API (formerly Vertex AI)).
  • event.data.model: o caminho completo do recurso do modelo (por exemplo, projects/{PROJECT_ID}/locations/global/publishers/google/models/gemini-3.8-flash).
  • event.data.template: metadados sobre o modelo de comando do servidor usado (PromptTemplateInfo), se aplicável.
  • event.data.request: o payload da solicitação de saída. O tipo de objeto e as propriedades dependem do provedor Gemini API:

Dados de eventos pós-solicitação (afterGenerateContent)

Em uma função afterGenerateContent, event.data é preenchido com um objeto AfterGenerateContentData. Esse objeto estende BeforeGenerateContentData (fornecendo api, model, template e request) e adiciona a resposta do modelo:



Limitações e comportamentos

Ao implementar essas funções, lembre-se dos seguintes comportamentos e limitações:

  • Somente solicitações generateContent: essas funções só podem ser acionadas por solicitações generateContent para o Gemini API via Firebase AI Logic.

    Os seguintes itens não acionam essas funções, e elas são ignoradas silenciosamente para essa solicitação:

    • As solicitações para generateContentStream não vão acionar essas funções.

    • As solicitações para o Gemini Live API não vão acionar essas funções.

  • Nenhuma mudança no código do lado do cliente: além de garantir que você use solicitações generateContent quando quiser executar essas funções, não é necessário fazer mudanças na base de código do lado do cliente.

    Essas funções são implantadas nos nossos servidores e registradas como gatilhos Firebase AI Logic para que o proxy Firebase AI Logic possa interceptar solicitações e respostas do lado do servidor.

  • Escopo no nível do projeto: é possível implantar no máximo uma função beforeGenerateContent e uma função afterGenerateContent por projeto do Firebase.

  • Locais padrão: essas funções serão implantadas em us-central1 por padrão. Saiba mais sobre os locais das funções. No entanto, a função será registrada como um gatilho Firebase AI Logic na região global, independente de onde você implanta a função.