เรียกใช้สคริปต์ฝั่งเซิร์ฟเวอร์ที่กำหนดเองก่อนและหลังคำขอ


คุณสามารถเรียกใช้สคริปต์ฝั่งเซิร์ฟเวอร์ที่กำหนดเองก่อนและหลังทุกคำขอที่แอปส่งไปยัง Gemini API ผ่าน Firebase AI Logic ได้ โดยไม่ต้องเปลี่ยนโค้ดฝั่งไคลเอ็นต์ คุณใช้สคริปต์เหล่านี้เป็นฟังก์ชันรูปแบบการเรียกกลับที่ติดตั้งใช้งานใน Cloud Functions for Firebase

ความสามารถนี้ช่วยให้คุณทำสิ่งต่างๆ ได้ เช่น กลั่นกรองพรอมต์ จำกัดการใช้โทเค็น บันทึกการสร้างเพื่อการวิเคราะห์ หรือปกปิดเนื้อหาการตอบกลับ

เหตุการณ์ 2 ประเภทที่ใช้ได้มีดังนี้

  • 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. มอบบทบาทบัญชีบริการ Cloud Build (roles/cloudbuild.builds.builder) ให้กับบัญชีบริการเริ่มต้นของ Compute ซึ่งจำเป็นต่อการสร้างฟังก์ชัน เรียกใช้คำสั่ง 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 ฟังก์ชันจะ ทํางานกับคําขอก่อนที่จะส่งคําขอไปยัง Gemini API ฟังก์ชันนี้สามารถแก้ไขคำขอหรือบล็อกคำขอทั้งหมดได้

โปรดตรวจสอบข้อมูลต่อไปนี้ก่อนเขียนฟังก์ชัน

ตัวอย่าง

ต่อไปนี้คือตัวอย่างฟังก์ชันก่อนคำขอที่ทำสิ่งต่อไปนี้

  • ระบุว่าฟังก์ชันควรทํางานเฉพาะเมื่อคําขอเป็นของผู้ให้บริการที่เฉพาะเจาะจง 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) จะทำให้คำขอไม่มีการเปลี่ยนแปลง

  • ทดสอบเวลาในการตอบสนอง: ฟังก์ชันอาจเพิ่มเวลาในการตอบสนองและส่งผลต่อประสบการณ์ของผู้ใช้ ทั้งนี้ขึ้นอยู่กับสิ่งที่ฟังก์ชันทำ

เขียนฟังก์ชันหลังคำขอ (afterGenerateContent)

เมื่อใช้afterGenerateContentประเภทเหตุการณ์ ฟังก์ชันจะทริกเกอร์เมื่อพร็อกซี Firebase AI Logic ได้รับการตอบกลับจากคำขอ generateContent ฟังก์ชันจะทํางานกับคําตอบก่อนที่จะส่งคําตอบ กลับไปยังแอปไคลเอ็นต์ ฟังก์ชันนี้สามารถบันทึกการใช้งาน แก้ไขคําตอบ หรือ บล็อกคําตอบทั้งหมดได้

โปรดตรวจสอบข้อมูลต่อไปนี้ก่อนเขียนฟังก์ชัน

ตัวอย่าง

ต่อไปนี้คือตัวอย่างฟังก์ชันหลังคำขอที่บันทึกการใช้โทเค็นและ เหตุผลที่ทำให้เสร็จสมบูรณ์

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. ทำให้ฟังก์ชันใช้งานได้โดยใช้ FirebaseCLI:

    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: ชื่อแพ็กเกจ หรือ Bundle ID ของแอปที่เรียกใช้ (ใช้ได้กับแพลตฟอร์ม 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พร็อกซี สามารถสกัดกั้นคำขอและการตอบกลับฝั่งเซิร์ฟเวอร์ได้

  • ขอบเขตระดับโปรเจ็กต์: คุณสามารถติดตั้งใช้งานbeforeGenerateContent ฟังก์ชันและฟังก์ชัน afterGenerateContent ได้สูงสุด 1 รายการต่อโปรเจ็กต์ Firebase

  • ตำแหน่งเริ่มต้น: ฟังก์ชันเหล่านี้จะได้รับการติดตั้งใช้งานใน us-central1 โดยค่าเริ่มต้น (ดูข้อมูลเกี่ยวกับตำแหน่งสำหรับฟังก์ชัน) อย่างไรก็ตาม ระบบจะลงทะเบียนฟังก์ชันเป็นทริกเกอร์ Firebase AI Logic ในภูมิภาค global ไม่ว่าคุณจะ ติดตั้งใช้งานฟังก์ชันที่ใดก็ตาม