Solusi Kompas

Membangun aplikasi perencanaan perjalanan yang didukung agen dengan AI Generatif

Diagram berikut menunjukkan ringkasan umum tentang cara menggabungkan layanan developer Google yang terbaik di kelasnya untuk membangun aplikasi berbasis AI.

Bangun aplikasi menarik dengan teknologi AI untuk seluler dan web

Anda dapat menggunakan Flutter dan Firebase Genkit untuk membangun aplikasi multi-platform yang dapat terintegrasi secara lancar dengan AI.
Anda dapat menggunakan Genkit agar aplikasi Anda dapat menggunakan data dari LLM tanpa ragu dengan menentukan skema yang dapat memvalidasi output LLM. Di Flutter, Anda dapat menggunakan Dart untuk membuat serialisasi permintaan dan mendeserialisasi respons agar sesuai dengan skema Genkit menggunakan permintaan HTTP standar.
Dengan IDX, Anda dapat membuat aplikasi Flutter tanpa perlu menginstal software apa pun. Hal ini memungkinkan pengembangan dan pengujian aplikasi Android dan aplikasi web Anda di browser.
Firebase Data Connect adalah layanan database relasional untuk aplikasi web dan seluler yang memungkinkan Anda membangun dan menskalakan menggunakan database PostgreSQL yang terkelola sepenuhnya dan didukung Cloud SQL. Vertex AI menyediakan skema yang aman serta pengelolaan kueri dan mutasi menggunakan GraphQL yang terintegrasi dengan baik dengan Firebase Authentication. Data Connect mencakup dukungan SDK untuk Kotlin Android dan web.

Membangun agen dengan Firebase Genkit

Agen menggunakan framework orkestrasi AI untuk menerima input pengguna dan menghasilkan respons.
---
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}}
Saat menggunakan AI generatif, penting untuk membuat perintah yang efektif sehingga model dapat menampilkan respons berkualitas tinggi. Firebase Genkit menyediakan plugin Dotprompt dan format teks untuk membantu Anda menulis dan mengatur prompt AI generatif. Formatnya mencakup perintah, skema input dan output, model, serta konfigurasi dalam satu file.

Contoh kode berikut menunjukkan file Dotprompt yang digunakan di aplikasi perjalanan. Skema ini didasarkan pada informasi yang diberikan pengguna saat menjelaskan perjalanan impiannya.
Dotprompt didesain berdasarkan premis bahwa prompt adalah kode. Anda akan menulis dan mengelola perintah dalam file berformat khusus yang disebut file dotprompt, melacak perubahan menggunakan sistem kontrol versi yang sama dengan yang digunakan untuk kode, dan men-deploy-nya bersama dengan kode yang memanggil model AI generatif.
Flow adalah fungsi yang diketik dengan ketat, dapat di-streaming, dapat dipanggil secara lokal dan jarak jauh, serta sepenuhnya dapat diamati. Firebase Genkit menyediakan antarmuka command line dan UI developer untuk menangani alur, seperti alur yang berjalan atau men-debug.
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;
}
Anda dapat menggunakan panggilan fungsi di Genkit untuk memperluas fungsi agen sehingga agen dapat lebih meningkatkan kualitas respons dan menyelesaikan tugas tambahan. Aplikasi perjalanan menentukan alat yang dapat menampilkan informasi restoran dari Places API berdasarkan perjalanan yang diinginkan pengguna. Kode ini menggunakan Zod untuk menentukan skema input dan output sehingga hasil kueri dapat divalidasi.
...
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();
});
Untuk membantu memberi pengguna pengalaman penelusuran yang lebih disesuaikan, setelah pengguna menjelaskan perjalanan impian mereka, Gemini menentukan apakah informasi lebih lanjut diperlukan berdasarkan perintah yang diberikan aplikasi perjalanan, dan memberi tahu aplikasi jika menurutnya diperlukan lebih banyak informasi. Aplikasi kemudian meminta informasi tersebut kepada pengguna dan menambahkannya ke permintaan di backend.
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());
  }
Aplikasi perjalanan ini meminta pengguna untuk menentukan perjalanan impian mereka dengan menggunakan input teks atau dengan mengetuk tombol mikrofon untuk mengaktifkan speech-to-text. Pengguna juga dapat mengupload gambar secara opsional.

Aplikasi ini memanfaatkan paket Dart dari pub.dev untuk diintegrasikan dengan kemampuan speech-to-text native di setiap platform, dan menggunakan Gemini API di dalam Firebase Genkit untuk menangani input multi-modal, seperti gambar atau video. Gemini API menggunakan Retrieval-augmented generation (RAG) untuk menampilkan kumpulan perjalanan yang disarankan menggunakan Firebase Data Connect dan penyematan untuk melakukan penelusuran tetangga terdekat.

Menskalakan aplikasi untuk produksi

Firebase Hosting terintegrasi dengan framework web modern yang populer, termasuk Flutter. Dengan menggunakan Firebase Hosting dan Cloud Functions for Firebase dengan framework ini, Anda dapat mengembangkan aplikasi dan microservice di lingkungan framework pilihan Anda, lalu men-deploy-nya di lingkungan server yang aman dan terkelola. Sebelum ke tahap produksi, pahami keamanan dan performa semua layanan di aplikasi Anda. Lihat checklist peluncuran Firebase untuk mengetahui informasi selengkapnya.
Aplikasi perjalanan ini menggunakan AI Google untuk melakukan iterasi data pengujian dengan cepat, dan merupakan pilihan yang baik untuk aplikasi dengan kasus penggunaan AI minimal yang tidak perlu diskalakan. Vertex AI memiliki kuota yang lebih tinggi untuk membantu menskalakan aplikasi produksi dan kebijakan privasi yang lebih kuat guna melindungi data pengguna. Genkit memiliki fungsi bawaan untuk beralih model dengan mudah sehingga Anda tidak perlu menulis ulang perintah atau panggilan API.