Trình bổ trợ Firebase

Trình bổ trợ Firebase cung cấp một số tính năng tích hợp với các dịch vụ của Firebase:

  • Trình lập chỉ mục và trình truy xuất dữ liệu sử dụng kho lưu trữ vectơ trên Cloud Firestore
  • Theo dõi bộ nhớ bằng Cloud Firestore
  • Triển khai quy trình bằng Cloud Functions
  • Chính sách ủy quyền cho người dùng tính năng Xác thực Firebase

Cài đặt

npm i --save @genkit-ai/firebase

Điều kiện tiên quyết

  • Tất cả các sản phẩm Firebase đều yêu cầu phải có dự án Firebase. Bạn có thể tạo một dự án mới hoặc bật Firebase trong một dự án hiện có trên Google Cloud bằng cách sử dụng bảng điều khiển của Firebase.
  • Ngoài ra, nếu muốn triển khai luồng đến Cloud Functions, bạn phải nâng cấp dự án của mình lên gói linh hoạt trả tiền theo mức dùng.

Cấu hình

Để sử dụng trình bổ trợ này, hãy chỉ định trình bổ trợ này khi bạn gọi configureGenkit():

import {configureGenkit} from "@genkit-ai/core";
import {firebase} from "@genkit-ai/firebase";

configureGenkit({
  plugins: [firebase({projectId: "your-firebase-project"})],
});

Trình bổ trợ này yêu cầu bạn chỉ định mã dự án Firebase. Bạn có thể chỉ định mã dự án Firebase bằng một trong những cách sau:

  • Đặt projectId trong đối tượng cấu hình firebase().

  • Đặt biến môi trường GCLOUD_PROJECT. Nếu bạn đang chạy luồng từ môi trường Google Cloud (Cloud Functions, Cloud Run, v.v.), GCLOUD_PROJECT sẽ tự động được đặt thành mã dự án của môi trường đó.

    Nếu đặt GCLOUD_PROJECT, bạn có thể bỏ qua thông số cấu hình: firebase()

Để cung cấp thông tin đăng nhập Firebase, bạn cũng cần thiết lập Thông tin xác thực mặc định của ứng dụng Google Cloud. Để chỉ định thông tin đăng nhập của bạn:

  • Nếu bạn đang chạy quy trình từ một môi trường Google Cloud (Cloud Functions, Cloud Run, v.v.), thì chế độ này sẽ được đặt tự động.

  • Đối với các môi trường khác:

    1. Tạo thông tin xác thực tài khoản dịch vụ cho dự án Firebase của bạn và tải tệp khoá JSON xuống. Bạn có thể thực hiện việc này trên trang Tài khoản dịch vụ của bảng điều khiển của Firebase.
    2. Đặt biến môi trường GOOGLE_APPLICATION_CREDENTIALS thành đường dẫn tệp của tệp JSON chứa khoá tài khoản dịch vụ của bạn.

Hoạt động sử dụng

Trình bổ trợ này cung cấp một số tính năng tích hợp với các dịch vụ Firebase mà bạn có thể sử dụng cùng nhau hoặc riêng lẻ.

Kho lưu trữ vectơ trên Cloud Firestore

Bạn có thể sử dụng Cloud Firestore làm kho lưu trữ vectơ để lập chỉ mục và truy xuất RAG.

Phần này trình bày thông tin dành riêng cho trình bổ trợ firebase và tính năng tìm kiếm vectơ của CloudFirestore. Vui lòng xem trang Thế hệ tăng cường truy xuất để biết nội dung thảo luận chi tiết hơn về cách triển khai RAG bằng Genkit.

Trình bổ trợ firebase cung cấp một hàm tiện lợi để xác định các truy xuất Firestore, defineFirestoreRetriever():

import {defineFirestoreRetriever} from "@genkit-ai/firebase";
import {retrieve} from "@genkit-ai/ai/retriever";

import {initializeApp} from "firebase-admin/app";
import {getFirestore} from "firebase-admin/firestore";

const app = initializeApp();
const firestore = getFirestore(app);

const yourRetrieverRef = defineFirestoreRetriever({
  name: "yourRetriever",
  firestore: getFirestore(app),
  collection: "yourCollection",
  contentField: "yourDataChunks",
  vectorField: "embedding",
  embedder: textEmbeddingGecko, // Import from '@genkit-ai/googleai' or '@genkit-ai/vertexai'
  distanceMeasure: "COSINE", // "EUCLIDEAN", "DOT_PRODUCT", or "COSINE" (default)
});

Để sử dụng, hãy truyền hàm này vào hàm retrieve():

const docs = await retrieve({
  retriever: yourRetrieverRef,
  query: "look for something",
  options: {limit: 5},
});

Các tuỳ chọn truy xuất hiện có bao gồm:

  • limit: Chỉ định số lượng kết quả trùng khớp cần trả về.
  • where: Các cặp trường/giá trị cần khớp (ví dụ: {category: 'food'}) ngoài tìm kiếm vectơ.
  • collection: Ghi đè tập hợp mặc định để tìm kiếm, chẳng hạn như tìm kiếm tập hợp con.

Để điền sẵn bộ sưu tập Firestore của bạn, hãy sử dụng trình tạo nhúng cùng với SDK quản trị. Ví dụ: tập lệnh nhập trình đơn trên trang Tạo tăng cường truy xuất có thể được điều chỉnh cho Firestore theo cách sau:

import { configureGenkit } from "@genkit-ai/core";
import { embed } from "@genkit-ai/ai/embedder";
import { defineFlow, run } from "@genkit-ai/flow";
import { textEmbeddingGecko, vertexAI } from "@genkit-ai/vertexai";

import { applicationDefault, initializeApp } from "firebase-admin/app";
import { FieldValue, getFirestore } from "firebase-admin/firestore";

import { chunk } from "llm-chunk";
import pdf from "pdf-parse";
import * as z from "zod";

import { readFile } from "fs/promises";
import path from "path";

// Change these values to match your Firestore config/schema
const indexConfig = {
  collection: "menuInfo",
  contentField: "text",
  vectorField: "embedding",
  embedder: textEmbeddingGecko,
};

configureGenkit({
  plugins: [vertexAI({ location: "us-central1" })],
  enableTracingAndMetrics: false,
});

const app = initializeApp({ credential: applicationDefault() });
const firestore = getFirestore(app);

export const indexMenu = defineFlow(
  {
    name: "indexMenu",
    inputSchema: z.string().describe("PDF file path"),
    outputSchema: z.void(),
  },
  async (filePath: string) => {
    filePath = path.resolve(filePath);

    // Read the PDF.
    const pdfTxt = await run("extract-text", () =>
      extractTextFromPdf(filePath)
    );

    // Divide the PDF text into segments.
    const chunks = await run("chunk-it", async () => chunk(pdfTxt));

    // Add chunks to the index.
    await run("index-chunks", async () => indexToFirestore(chunks));
  }
);

async function indexToFirestore(data: string[]) {
  for (const text of data) {
    const embedding = await embed({
      embedder: indexConfig.embedder,
      content: text,
    });
    await firestore.collection(indexConfig.collection).add({
      [indexConfig.vectorField]: FieldValue.vector(embedding),
      [indexConfig.contentField]: text,
    });
  }
}

async function extractTextFromPdf(filePath: string) {
  const pdfFile = path.resolve(filePath);
  const dataBuffer = await readFile(pdfFile);
  const data = await pdf(dataBuffer);
  return data.text;
}

Firestore phụ thuộc vào các chỉ mục để cung cấp khả năng truy vấn nhanh chóng và hiệu quả trên các bộ sưu tập. (Xin lưu ý rằng "chỉ mục" ở đây đề cập đến các chỉ mục cơ sở dữ liệu, chứ không phải là bản tóm tắt trình lập chỉ mục và trình truy xuất của Genkit.)

Ví dụ trước yêu cầu trường embedding phải được lập chỉ mục để hoạt động. Cách tạo chỉ mục:

  • Chạy lệnh gcloud được mô tả trong phần Tạo chỉ mục vectơ một trường của tài liệu về Firestore.

    Lệnh có dạng như sau:

    gcloud alpha firestore indexes composite create --project=your-project-id \
      --collection-group=yourCollectionName --query-scope=COLLECTION \
      --field-config=vector-config='{"dimension":"768","flat": "{}"}',field-path=yourEmbeddingField
    

    Tuy nhiên, cấu hình lập chỉ mục chính xác phụ thuộc vào các truy vấn bạn sẽ thực hiện và mô hình nhúng bạn đang sử dụng.

  • Ngoài ra, hãy gọi retrieve() và Firestore sẽ báo lỗi với lệnh đúng để tạo chỉ mục.

Tìm hiểu thêm

Bộ nhớ theo dõi trên Cloud Firestore

Bạn có thể sử dụng Cloud Firestore để lưu trữ dấu vết:

import {firebase} from "@genkit-ai/firebase";

configureGenkit({
  plugins: [firebase()],
  traceStore: "firebase",
  enableTracingAndMetrics: true,
});

Theo mặc định, trình bổ trợ này lưu trữ các dấu vết trong một bộ sưu tập có tên là genkit-traces trong cơ sở dữ liệu mặc định của dự án. Để thay đổi một trong hai chế độ cài đặt này, hãy làm như sau:

firebase({
  traceStore: {
    collection: "your-collection";
    databaseId: "your-db";
  }
})

Khi sử dụng bộ nhớ theo dõi dựa trên Firestore, bạn cần bật TTL cho các tài liệu theo dõi: https://firebase.google.com/docs/firestore/ttl

Cloud Functions

Trình bổ trợ này cung cấp hàm khởi tạo onFlow(). Hàm này sẽ tạo ra một luồng được hỗ trợ bởi hàm được kích hoạt bằng HTTPS của Cloud Functions cho Firebase. Các hàm này phù hợp với giao diện hàm có thể gọi của Firebase và bạn có thể dùng SDK ứng dụng Cloud Functions để gọi các hàm đó.

import {firebase} from "@genkit-ai/firebase";
import {onFlow, noAuth} from "@genkit-ai/firebase/functions";

configureGenkit({
  plugins: [firebase()],
});

export const exampleFlow = onFlow(
  {
    name: "exampleFlow",
    authPolicy: noAuth(), // WARNING: noAuth() creates an open endpoint!
  },
  async (prompt) => {
    // Flow logic goes here.

    return response;
  }
);

Triển khai quy trình bằng giao diện dòng lệnh (CLI) của Firebase:

firebase deploy --only functions

Hàm onFlow() có một số tuỳ chọn không có trong defineFlow():

  • httpsOptions: một đối tượng HttpsOptions dùng để định cấu hình Hàm đám mây của bạn: js export const exampleFlow = onFlow( { name: "exampleFlow", httpsOptions: { cors: true, }, // ... }, async (prompt) => { // ... } );

  • enforceAppCheck: khi true, từ chối các yêu cầu có mã thông báo Kiểm tra ứng dụng bị thiếu hoặc không hợp lệ.

  • consumeAppCheckToken: khi true, hãy vô hiệu hoá mã thông báo Kiểm tra ứng dụng sau khi xác minh.

    Hãy xem bài viết Chống phát lại.

Firebase Auth

Trình bổ trợ này cung cấp chức năng trợ giúp để tạo chính sách uỷ quyền xung quanh tính năng Xác thực Firebase:

import {firebaseAuth} from "@genkit-ai/firebase/auth";

export const exampleFlow = onFlow(
  {
    name: "exampleFlow",
    authPolicy: firebaseAuth((user) => {
      if (!user.email_verified) throw new Error("Requires verification!");
    }),
  },
  async (prompt) => {
    // ...
  }
);

Để xác định chính sách xác thực, hãy cung cấp cho firebaseAuth() hàm callback lấy DecodedIdToken làm tham số duy nhất. Trong hàm này, hãy kiểm tra mã thông báo của người dùng và báo cáo lỗi nếu người dùng không đáp ứng bất kỳ tiêu chí nào mà bạn muốn.

Hãy xem phần Uỷ quyền và tính toàn vẹn để thảo luận kỹ hơn về chủ đề này.