פתרון מצפן
איך מפתחים אפליקציה לתכנון נסיעות שיתופית באמצעות בינה מלאכותית גנרטיבית
ארכיטקטורת אפליקציות
בתרשים הבא מוצגת סקירה כללית של האופן שבו אפשר לשלב את השירותים למפתחים של Google מהשורה הראשונה כדי לפתח אפליקציות מבוססות-AI.
יוצרים אפליקציות יפות ומבוססות-AI לנייד ולאינטרנט
אתם יכולים להשתמש ב-Flutter וב-Firebase Genkit כדי ליצור אפליקציות בפלטפורמות מרובות שמשתלבות בצורה חלקה עם AI.
אפשר להתקשר ל-Firebase Genkit בצורה חלקה מאפליקציית Flutter
אתם יכולים להשתמש ב-Genkit כדי לאפשר לאפליקציה לצרוך נתונים בצורה מהימנה ממודלים גדולים של שפה (LLM), באמצעות הגדרת סכימה שיכולה לאמת את הפלט של ה-LLM. ב-Flutter, אפשר להשתמש ב-Dart כדי לבצע סריאליזציה של הבקשה ולבצע פעולת deserial כדי להתאים את התשובה לסכימת Genkit באמצעות בקשות HTTP רגילות.
תחילת העבודה עם Flutter ב-IDX
באמצעות IDX אפשר ליצור אפליקציית Flutter ללא צורך בהתקנה של תוכנה כלשהי. כך ניתן לפתח ולבדוק את האפליקציה ל-Android ואת אפליקציית האינטרנט בדפדפן.
חיבור מסד הנתונים ל-Firebase Data Connect
Firebase Data Connect הוא שירות של מסד נתונים רלציוני לאפליקציות לנייד ולאינטרנט. השירות מאפשר ליצור ולהתאים אישית את הנתונים באמצעות מסד נתונים מנוהל של PostgreSQL שמבוסס על Cloud SQL. הוא מספק סכימה מאובטחת וניהול של שאילתות ומוטציות באמצעות GraphQL שמשתלב היטב עם אימות ב-Firebase. Data Connect כולל תמיכה ב-SDK ל-Kotlin ב-Android ובאינטרנט.
יצירת נציג באמצעות Firebase Genkit
הנציג משתמש ב-framework תזמור AI כדי לקבל קלט ממשתמשים וליצור תשובה.
--- model: googleai/gemini-1.5-flash-latest config: temperature: 1.0 safetySettings: - category: HARM_CATEGORY_HATE_SPEECH threshold: BLOCK_LOW_AND_ABOVE - category: HARM_CATEGORY_DANGEROUS_CONTENT threshold: BLOCK_ONLY_HIGH - category: HARM_CATEGORY_HARASSMENT threshold: BLOCK_LOW_AND_ABOVE - category: HARM_CATEGORY_SEXUALLY_EXPLICIT threshold: BLOCK_LOW_AND_ABOVE input: schema: request: string, The users request for where they want to travel to. place: string, The place that closely represents the users request. placeDescription: string, A description of that place. activities(array, a stringify list of activities that can be found at the specified place): string restaurants?(array, a stringify list of all the restaurants found at that location): string output: schema: place: string, The place the user is traveling to. itineraryName: string, a catchy itinerary name that encapsulates the spirit of the trip and includes the place name startDate: string, the start date of the trip endDate: string, the end date of the trip tags(array, relevant tags for the trip): string itinerary(array): day: number date: string planForDay(array): activityRef: string, the reference value for the activity - this comes from the available activities JSON. If no value is present use a ref value of restaurant. activityTitle: string, a catchy title for the activity activityDesc: string, a six word description of the activity photoUri?: string, set the photo uri value for restaurants only. googleMapsUri?: string, if this is a restaurant include the googleMapsUri --- Generate an itinerary for a tourist planning on traveling to the location specified based in their request. If there is something that does not exist within the list of activities, do not include it in your answer. Feel free to relate the activitiy to the request in a meaningful way. In the plan for day array, put activities as a travel brouchure might do. Come up with a catchy name for the itinerary. Pick three activities per day, minimum of three day trip unless otherwise specified in the request. Output schema should not include the properties type or object. Pick a date after 2024-05-14 but before 2024-12-31. The output date must be in the format year-month-day. Give each activity a unique title and description. Limit activity descriptions to 6 words. If no restaurants are supplied, do not recommend any restaurants to eat at. {{#if restaurants}} Find a restaurant to eat at each day. Include a restaurant to visit in the itinerary for each day from the available restaurants. The restaurant should be the only activity with a photoUri. The photoUri for the restaurant should be from the photoUri property from the restaurant array. If there are no restaurants to pick from, do not include it in the list. The photoUri from the restaurantFinder should be in the format of places/${placeId}/photos/${photoId} Each restaurant should be unique to the overall itinerary. Each restaurant must contain a photoUri in their output JSON schema. Each restaurant must also include an activitiyRef, activityTitle, and activityDesc in their output {{/if}} Output must be in JSON format. REQUEST : {{request}} PLACE : {{place}} PLACE DESCRIPTION : {{placeDescription}} AVAILABLE ACTIVITIES : {{activities}} RESTAURANTS : {{restaurants}}
יצירת התהליך הראשון ב-Firebase Genkit
כשעובדים עם בינה מלאכותית גנרטיבית, חשוב לנסח הנחיות יעילות כדי שהמודל יחזיר תשובות באיכות גבוהה. מערכת Firebase Genkit מספקת את הפלאגין ואת פורמט הטקסט של Dotprompt, כדי לעזור לך לכתוב ולארגן את ההנחיות שלך ל-AI גנרטיבי. הפורמט כולל את ההנחיה, את סכימת הקלט והפלט, את המודל ואת ההגדרות האישיות בקובץ אחד.
הקוד לדוגמה הבא מציג קובץ Dotprompt שנעשה בו שימוש באפליקציית הנסיעות. הסכימה מבוססת על המידע שהמשתמש מספק כשהוא מתאר את טיול החלומות שלו.
הקוד לדוגמה הבא מציג קובץ Dotprompt שנעשה בו שימוש באפליקציית הנסיעות. הסכימה מבוססת על המידע שהמשתמש מספק כשהוא מתאר את טיול החלומות שלו.
Dotprompt
Dotprompt מעוצבת סביב ההנחה שההנחיות הן קוד. כותבים ומתחזקים את ההנחיות בקבצים בפורמט מיוחד שנקרא קובצי doprompt, עוקבים אחרי השינויים שבוצעו בהם באמצעות אותה מערכת לניהול גרסאות שבה אתם משתמשים לקוד, ופורסים אותן יחד עם הקוד שקורא למודלים של ה-AI הגנרטיבי.
זרימות
זרמי נתונים הם פונקציות הקלדה חזקה, העברה בסטרימינג, פונקציות מקומיות וניתנות לקריאה מרחוק, וניתנות למדידה מלאה. פלטפורמת Firebase Genkit מספקת ממשק שורת פקודה וממשק משתמש למפתחים לצורך עבודה עם תהליכים כמו הרצה או ניפוי באגים בתהליכי עבודה.
import {defineTool} from '@genkit-ai/ai/tool'; ... { name: 'restaurantFinder', description: `Used when needing to find a restaurant based on a users location. The location should be used to find nearby restaurants to a place. You can also selectively find restaurants based on the users preferences, but you should default to 'Local' if there are no indications of restaurant types in the users request. `, inputSchema: z.object({ place: z.string(), typeOfRestaurant: z.string().optional() }), outputSchema: z.unknown(), }, ... async (input) => { if (input.typeOfRestaurant == undefined) { input.typeOfRestaurant = "Local"; } const geocodeEndpoint = "https://places.googleapis.com/v1/places:searchText"; const textQuery = {textQuery: `${input.typeOfRestaurant} restaurants in ${input.place}`}; const response = await axios.post( geocodeEndpoint, JSON.stringify(textQuery), { headers: { "Content-Type": "application/json", "X-Goog-Api-Key": MAPS_API_KEY, "X-Goog-FieldMask": "places.displayName,places.formattedAddress,places.priceLevel,places.photos.name,places.editorialSummary,places.googleMapsUri" } } ); console.log(response.data); let data = (response.data as PlaceResponse); for(let i = 0; i < data.places.length; i++) { if (data.places[i].photos) { data.places[i].photos = [data.places[i].photos[0]]; } } return data as PlaceResponse; }
אפשר להרחיב את הפונקציונליות של הנציג על ידי הוספת כלים שמתממשקים עם שירותים חיצוניים.
אפשר להשתמש בקריאות לפונקציות ב-Genkit כדי להרחיב את הפונקציונליות של הנציג, כך שהוא יוכל לשפר את התשובות ולבצע משימות נוספות. אפליקציית הנסיעות מגדירה כלי שיכול להחזיר פרטים של מסעדות מ-Places API בהתאם לנסיעה הרצויה של המשתמש. הקוד משתמש ב-Zod כדי להגדיר את סכימת הקלט והפלט כך שניתן יהיה לאמת את תוצאות השאילתה.
... export const textRefinement = defineFlow( { name: 'textRefinement', inputSchema: z.string(), outputSchema: z.unknown(), }, async (userRequest) => { const refinementPrompt = await prompt('textRefinement') const result = await refinementPrompt.generate({ input: { request: userRequest }, }); return result.output(); });
צמצום שאילתת החיפוש
כדי לספק למשתמשים חוויית חיפוש ברמה גבוהה יותר של התאמה אישית, אחרי שהמשתמש מתאר את טיול החלומות שלהם, Gemini קובע אם נדרש מידע נוסף על סמך ההנחיות של אפליקציית הנסיעות, ואם היא סבורה שצריך מידע נוסף, היא שולחת אותות לאפליקציה. לאחר מכן האפליקציה מבקשת מהמשתמש לספק את המידע הזה ומצרפת אותו לבקשה בקצה העורפי.
import 'package:http:http.dart' as http; ... Future<List<Trip>> generateTrips(String description, List<Image> images) async { final uri = Uri.parse('.../generateTrips'); final request = http.MultipartRequest('POST', uri); request.fields['description'] = description; request.files.add(http.MultipartFile.fromData( images.name, images.bytes, contentType: MediaType('image', 'png'), )); var response = await request.send(); if (response.statusCode == 200) { final body = await response.body.text(); final items = jsonDecode(body) as List<dynamic>; return items.map(Trip.fromJson).toList(); } ... import { imagen2, geminiProVision } from '@genkit-ai/vertexai'; import { generate } from '@genkit-ai/ai'; const imageResult = await generate({ model: imagen2, prompt: 'Generate an image of a very specific historical time and place.', }); const generatedImage = imageResult.media(); const descriptionResult = await generate({ model: geminiProVision, prompt: [ { text: 'What is the historical time and place represented in this picture?', }, { media: generatedImage }, ], }); console.log(descriptionResult.text()); }
יצירת רשימה של הצעות לסקירות כלליות של נסיעות
אפליקציית הנסיעות מבקשת מהמשתמש להגדיר את טיול החלומות שלו באמצעות קלט טקסט, או על ידי הקשה על לחצן המיקרופון כדי להפעיל את התכונה 'המרת דיבור לטקסט'. המשתמש יכול גם להעלות תמונות.
האפליקציה משתמשת בחבילת Dart מ-pub.dev כדי לשלב יכולות מקומיות של המרת דיבור לטקסט (STT) בכל פלטפורמה. היא משתמשת ב-Gemini API ב-Firebase Genkit כדי לטפל בקלט מרובה מצבים, כמו תמונות או סרטונים. ב-Gemini API נעשה שימוש בגנרציה מבוססת-אחזור (RAG) כדי להחזיר קבוצת הצעות לנסיעות באמצעות Firebase Data Connect והטמעות לצורך חיפוש סמוך ביותר.
האפליקציה משתמשת בחבילת Dart מ-pub.dev כדי לשלב יכולות מקומיות של המרת דיבור לטקסט (STT) בכל פלטפורמה. היא משתמשת ב-Gemini API ב-Firebase Genkit כדי לטפל בקלט מרובה מצבים, כמו תמונות או סרטונים. ב-Gemini API נעשה שימוש בגנרציה מבוססת-אחזור (RAG) כדי להחזיר קבוצת הצעות לנסיעות באמצעות Firebase Data Connect והטמעות לצורך חיפוש סמוך ביותר.
התאמת האפליקציה לסביבת הייצור
הנחיות לסביבת הייצור בכל שירותי הענן
אירוח ב-Firebase משתלב עם מסגרות אינטרנט מודרניות ופופולריות, כולל Flutter. באמצעות אירוח ב-Firebase ו-Cloud Functions for Firebase עם ה-frameworks האלה, אתם יכולים לפתח אפליקציות ומיקרו-שירותים (microservices) בסביבת ה-framework המועדפת עליכם, ואז לפרוס אותם בסביבת שרת מנוהלת ומאובטחת. לפני שיוצאים לסביבת הייצור, כדאי להבין את האבטחה והביצועים של כל השירותים באפליקציה. מידע נוסף זמין ברשימת המשימות להשקה של Firebase.
Vertex AI
אפליקציית הנסיעות מתבססת על ה-AI מבית Google כדי לחזור במהירות על נתוני בדיקות, והיא אפשרות טובה לאפליקציות עם תרחישים לדוגמה מינימליים של AI שלא צריך להרחיב את הפעילות שלהן. ב-Vertex AI יש מכסה גבוהה יותר שעוזרת להתאים לעומס (scaling) של אפליקציות בסביבת ייצור, ומדיניות פרטיות חזקה יותר כדי להגן על נתוני המשתמשים. ב-Genkit יש פונקציונליות מובנית שמאפשרת לעבור בקלות בין מודלים, כך שאין צורך לשכתב את ההנחיות או את הקריאות ל-API.