ב-Cloud Functions for Firebase יש שיטה onCallGenkit
שמאפשרת ליצור במהירות פונקציה שניתן להפעיל באמצעות פעולת Genkit (למשל, תהליך). אפשר להפעיל את הפונקציות האלה באמצעות genkit/beta/client
או באמצעות Functions client SDK, שמוסיף באופן אוטומטי את פרטי האימות.
לפני שמתחילים
- כדאי שתכירו את המושג flows ב-Genkit ואת האופן שבו כותבים אותם. ההוראות בדף הזה מבוססות על ההנחה שכבר הגדרתם תהליכים מסוימים שאתם רוצים לפרוס.
- מומלץ, אבל לא חובה, שכבר השתמשתם ב-Cloud Functions for Firebase.
1. הגדרת פרויקט Firebase
אם עדיין אין לכם פרויקט Firebase עם הגדרה של TypeScript Cloud Functions, עליכם לפעול לפי השלבים הבאים:
יוצרים פרויקט Firebase חדש באמצעות מסוף Firebase או בוחרים פרויקט קיים.
משדרגים את הפרויקט לתוכנית Blaze, שנדרשת לפריסה של Cloud Functions.
מתקינים את Firebase CLI.
מתחברים באמצעות CLI של Firebase:
firebase login
firebase login --reauth # alternative, if necessary
firebase login --no-localhost # if running in a remote shell
יוצרים ספריית פרויקט חדשה:
export PROJECT_ROOT=~/tmp/genkit-firebase-project1
mkdir -p $PROJECT_ROOT
מפעילים פרויקט Firebase בספרייה:
cd $PROJECT_ROOT
firebase init genkit
בהמשך הדף נניח שהחלטתם לכתוב את הפונקציות ב-TypeScript, אבל אפשר לפרוס את תהליכי העבודה של Genkit גם אם משתמשים ב-JavaScript.
2. עטיפה של ה-Flow ב-onCallGenkit
אחרי שמגדירים פרויקט Firebase עם Cloud Functions, אפשר להעתיק או לכתוב הגדרות של תהליכים בספרייה functions/src
של הפרויקט ולייצא אותן ב-index.ts
.
כדי שתוכלו לפרוס את התהליכים, צריך לעטוף אותם ב-onCallGenkit
.
השיטה הזו כוללת את כל התכונות של onCall
הרגיל. הוא תומך באופן אוטומטי גם בתגובות בסטרימינג וגם בתגובות JSON.
נניח שיש לכם את התהליך הבא:
const generatePoemFlow = ai.defineFlow(
{
name: "generatePoem",
inputSchema: z.string(),
outputSchema: z.string(),
},
async (subject: string) => {
const { text } = await ai.generate(`Compose a poem about ${subject}.`);
return text;
}
);
אפשר לחשוף את התהליך הזה כפונקציה שניתן להפעיל באמצעות onCallGenkit
:
import { onCallGenkit } from 'firebase-functions/https';
export generatePoem = onCallGenkit(generatePoemFlow);
הגדרת מדיניות הרשאה
לכל תהליכי העבודה שנפרסו, בין שהם נפרסו ב-Firebase ובין שלא, צריכה להיות מדיניות הרשאה. בלי מדיניות כזו, כל אחד יוכל להפעיל את תהליכי ה-AI הגנרטיביים שלכם, שעשויים להיות יקרים. כדי להגדיר מדיניות הרשאה, משתמשים בפרמטר authPolicy
של onCallGenkit
:
export const generatePoem = onCallGenkit({
authPolicy: (auth) => auth?.token?.email_verified,
}, generatePoemFlow);
בדוגמה הזו נעשה שימוש בפונקציה ידנית כמדיניות האימות. בנוסף, הספרייה https מייצאת את הכלים signedIn()
ו-hasClaim()
. זהו אותו קוד עם אחד מהעוזרים האלה:
import { hasClaim } from 'firebase-functions/https';
export const generatePoem = onCallGenkit({
authPolicy: hasClaim('email_verified'),
}, generatePoemFlow);
איך מאפשרים לפרטי הכניסה ל-API להיות זמינים לתהליכים שנפרסו
אחרי הפריסה, תצטרכו למצוא דרך לאמת את התהליכים עם השירותים המרוחקים שהם מסתמכים עליהם. ברוב התהליכים נדרשים לפחות פרטי כניסה כדי לגשת לשירות ה-API של המודל שבו נעשה שימוש.
בדוגמה הזו, מבצעים אחת מהפעולות הבאות, בהתאם לספק המודל שבחרתם:
Gemini (AI מבית Google)
מוודאים ש-Google AI זמין באזור שלכם.
יוצרים מפתח API ל-Gemini API באמצעות Google AI Studio.
אחסון מפתח ה-API ב-Cloud Secret Manager:
firebase functions:secrets:set GOOGLE_GENAI_API_KEY
השלב הזה חשוב כדי למנוע דליפת מפתח ה-API בטעות, שמעניק גישה לשירות שעשוי להיות מותאם לחיוב.
למידע נוסף על ניהול סודות, ראו אחסון של מידע רגיש של הגדרות והרשאות גישה אליו.
עורכים את הקובץ
src/index.ts
ומוסיפים את הקטע הבא אחרי הייבוא הקיים:import {defineSecret} from "firebase-functions/params"; const googleAIapiKey = defineSecret("GOOGLE_GENAI_API_KEY");
לאחר מכן, בהגדרת התהליך, מצהירים שלפונקציית הענן דרושה גישה לערך הסודי הזה:
export const generatePoem = onCallGenkit({ secrets: [googleAIapiKey] }, generatePoemFlow);
עכשיו, כשפורסים את הפונקציה הזו, מפתח ה-API נשמר ב-Cloud Secret Manager וזמין מסביבת Cloud Functions.
Gemini (Vertex AI)
במסוף Cloud, מפעילים את Vertex AI API לפרויקט ב-Firebase.
בדף IAM, מוודאים שלחשבון השירות המוגדר כברירת מחדל ל-Compute הוקצה התפקיד Vertex AI User.
הסוד היחיד שצריך להגדיר במדריך הזה הוא של ספק המודל, אבל באופן כללי צריך לעשות משהו דומה לכל שירות שבו נעשה שימוש בתהליך.
הוספת אכיפה של בדיקת האפליקציות
Firebase App Check משתמש במנגנון אימות מובנה כדי לוודא שהקריאה לממשק ה-API מתבצעת רק על ידי האפליקציה. onCallGenkit
תומך באכיפה של בדיקת האפליקציות באופן דקלרטיבי.
export const generatePoem = onCallGenkit({
enforceAppCheck: true,
// Optional. Makes App Check tokens only usable once. This adds extra security
// at the expense of slowing down your app to generate a token for every API
// call
consumeAppCheckToken: true,
}, generatePoemFlow);
הגדרת מדיניות CORS
כברירת מחדל, פונקציות שניתן להפעיל מאפשרות לכל דומיין להפעיל את הפונקציה. אם רוצים להתאים אישית את הדומיינים שיכולים לעשות זאת, משתמשים באפשרות cors
.
כשיש אימות תקין (במיוחד App Check), בדרך כלל אין צורך ב-CORS.
export const generatePoem = onCallGenkit({
cors: 'mydomain.com',
}, generatePoemFlow);
דוגמה מלאה
אחרי שמבצעים את כל השינויים שמפורטים למעלה, התהליך לפריסה ייראה בערך כך:
import { genkit } from 'genkit';
import { onCallGenkit, hasClaim } from 'firebase-functions/https';
import { defineSecret } from 'firebase-functions/params';
const apiKey = defineSecret("GOOGLE_GENAI_API_KEY");
const generatePoemFlow = ai.defineFlow({
name: "generatePoem",
inputSchema: z.string(),
outputSchema: z.string(),
}, async (subject: string) => {
const { text } = await ai.generate(`Compose a poem about ${subject}.`);
return text;
});
export const generateFlow = onCallGenkit({
secrets: [apiKey],
authPolicy: hasClaim("email_verified"),
enforceAppCheck: true,
}, generatePoemFlow);
3. פריסת תהליכים ב-Firebase
אחרי שמגדירים תהליכים באמצעות onCallGenkit
, אפשר לפרוס אותם באותו אופן שבו פורסים פונקציות אחרות של Cloud Functions:
cd $PROJECT_ROOT
firebase deploy --only functions
סיימתם לפרוס את התהליך כפונקציית Cloud. עם זאת, לא תוכלו לגשת לנקודת הקצה שנפרסה באמצעות curl
או באמצעות שירות דומה, בגלל מדיניות ההרשאה של התהליך. בקטע הבא מוסבר איך לגשת לתהליך בצורה מאובטחת.
אופציונלי: ניסיון בתהליך הפריסה
כדי לנסות את נקודת הקצה של התהליך, אפשר לפרוס את אפליקציית האינטרנט לדוגמה הבאה:
בקטע Project settings (הגדרות הפרויקט) במסוף Firebase, מוסיפים אפליקציית אינטרנט חדשה ובוחרים גם להגדיר אירוח.
בקטע Authentication במסוף Firebase, מפעילים את הספק Google שמשמש בדוגמה הזו.
בספריית הפרויקט, מגדירים את Firebase Hosting, שבו תפרסו את האפליקציה לדוגמה:
cd $PROJECT_ROOT
firebase init hosting
מאשרים את ברירת המחדל לכל ההנחיות.
מחליפים את
public/index.html
בקוד הבא:<!DOCTYPE html> <html> <head> <title>Genkit demo</title> </head> <body> <div id="signin" hidden> <button id="signinBtn">Sign in with Google</button> </div> <div id="callGenkit" hidden> Subject: <input type="text" id="subject" /> <button id="generatePoem">Compose a poem on this subject</button> <p id="generatedPoem"></p> </div> <script type="module"> import { initializeApp } from "https://www.gstatic.com/firebasejs/11.0.1/firebase-app.js"; import { getAuth, onAuthStateChanged, GoogleAuthProvider, signInWithPopup, } from "https://www.gstatic.com/firebasejs/11.0.1/firebase-auth.js"; import { getFunctions, httpsCallable, } from "https://www.gstatic.com/firebasejs/11.0.1/firebase-functions.js"; const firebaseConfig = await fetch("/__/firebase/init.json"); initializeApp(await firebaseConfig.json()); async function generatePoem() { const poemFlow = httpsCallable(getFunctions(), "generatePoem"); const subject = document.querySelector("#subject").value; const response = await poemFlow(subject); document.querySelector("#generatedPoem").innerText = response.data; } function signIn() { signInWithPopup(getAuth(), new GoogleAuthProvider()); } document.querySelector("#signinBtn").addEventListener("click", signIn); document .querySelector("#generatePoem") .addEventListener("click", generatePoem); const signinEl = document.querySelector("#signin"); const genkitEl = document.querySelector("#callGenkit"); onAuthStateChanged(getAuth(), (user) => { if (!user) { signinEl.hidden = false; genkitEl.hidden = true; } else { signinEl.hidden = true; genkitEl.hidden = false; } }); </script> </body> </html>
פורסים את אפליקציית האינטרנט ואת הפונקציה של Cloud Functions:
cd $PROJECT_ROOT
firebase deploy
פותחים את אפליקציית האינטרנט על ידי כניסה לכתובת ה-URL שמודפסת על ידי הפקודה deploy
. באפליקציה צריך להיכנס באמצעות חשבון Google, ואז אפשר להתחיל לשלוח בקשות לנקודות קצה.
אופציונלי: הפעלת תהליכים בממשק המשתמש למפתחים
אפשר להריץ תהליכים שהוגדרו באמצעות onCallGenkit
בממשק המשתמש למפתחים, בדיוק באותו אופן שבו מפעילים תהליכים שהוגדרו באמצעות defineFlow
, כך שאין צורך לעבור בין השניים בין הפריסה לפיתוח.
cd $PROJECT_ROOT/functions
npx genkit start -- npx tsx --watch src/index.ts
או
cd $PROJECT_ROOT/functions
npm run genkit:start
עכשיו אפשר לנווט לכתובת ה-URL שנדפסה על ידי הפקודה genkit start
כדי לגשת אליה.
אופציונלי: פיתוח באמצעות Firebase Local Emulator Suite
ב-Firebase יש חבילת אמולטורים לפיתוח מקומי, שאפשר להשתמש בה עם Genkit.
כדי להשתמש בממשק המשתמש של Genkit Dev עם Firebase Emulator Suite, מפעילים את האמולטורים של Firebase באופן הבא:
npx genkit start -- firebase emulators:start --inspect-functions
הפקודה הזו מפעילה את הקוד במהדמ, ומפעילה את מסגרת Genkit במצב פיתוח. הפקודה הזו מפעילה את Genkit reflection API ומציגה אותו (אבל לא את ממשק המשתמש למפתחים).
כדי לראות את הטרייסים מ-Firestore בממשק המשתמש של הפיתוח, עוברים לכרטיסייה Inspect ומעבירים את המתג Dev/Prod. כשמפעילים את המתג ל-prod, מתבצעת טעינת עקבות מ-Firestore.