1. Membangun aplikasi Flutter yang didukung Gemini
Yang akan Anda build
Dalam codelab ini, Anda akan mem-build Colorist - aplikasi Flutter interaktif yang menghadirkan kecanggihan Gemini API langsung ke aplikasi Flutter Anda. Pernah ingin membiarkan pengguna mengontrol aplikasi Anda melalui bahasa alami, tetapi tidak tahu harus mulai dari mana? Codelab ini menunjukkan caranya.
Colorist memungkinkan pengguna mendeskripsikan warna dalam bahasa alami (seperti "oranye saat matahari terbenam" atau "biru laut dalam"), dan aplikasi:
- Memproses deskripsi ini menggunakan Gemini API Google
- Menafsirkan deskripsi menjadi nilai warna RGB yang tepat
- Menampilkan warna di layar secara real-time
- Memberikan detail warna teknis dan konteks menarik tentang warna
- Mempertahankan histori warna yang baru-baru ini dibuat
Aplikasi ini memiliki antarmuka layar terpisah dengan area tampilan berwarna dan sistem chat interaktif di satu sisi, serta panel log mendetail yang menampilkan interaksi LLM mentah di sisi lainnya. Log ini memungkinkan Anda lebih memahami cara kerja integrasi LLM di balik layar.
Mengapa hal ini penting bagi developer Flutter
LLM merevolusi cara pengguna berinteraksi dengan aplikasi, tetapi mengintegrasikannya secara efektif ke dalam aplikasi seluler dan desktop menimbulkan tantangan tersendiri. Codelab ini mengajarkan pola praktis yang tidak hanya sekadar panggilan API mentah.
Perjalanan pembelajaran Anda
Codelab ini akan memandu Anda dalam proses pembuatan Colorist langkah demi langkah:
- Penyiapan project - Anda akan memulai dengan struktur aplikasi Flutter dasar dan paket
colorist_ui
- Integrasi Gemini dasar - Hubungkan aplikasi Anda ke Firebase AI Logic dan terapkan komunikasi LLM
- Perintah yang efektif - Buat perintah sistem yang memandu LLM untuk memahami deskripsi warna
- Deklarasi fungsi - Menentukan alat yang dapat digunakan LLM untuk menyetel warna di aplikasi Anda
- Penanganan alat - Memproses panggilan fungsi dari LLM dan menghubungkannya ke status aplikasi Anda
- Respons streaming - Meningkatkan pengalaman pengguna dengan respons LLM streaming real-time
- Sinkronisasi Konteks LLM - Menciptakan pengalaman yang kohesif dengan memberi tahu LLM tentang tindakan pengguna
Yang akan Anda pelajari
- Mengonfigurasi Firebase AI Logic untuk aplikasi Flutter
- Buat perintah sistem yang efektif untuk memandu perilaku LLM
- Menerapkan deklarasi fungsi yang menghubungkan bahasa alami dan fitur aplikasi
- Memproses respons streaming untuk pengalaman pengguna yang responsif
- Menyinkronkan status antara peristiwa UI dan LLM
- Mengelola status percakapan LLM menggunakan Riverpod
- Menangani error dengan baik di aplikasi yang didukung LLM
Pratinjau kode: Gambaran tentang apa yang akan Anda terapkan
Berikut sekilas deklarasi fungsi yang akan Anda buat agar LLM dapat menetapkan warna di aplikasi Anda:
FunctionDeclaration get setColorFuncDecl => FunctionDeclaration(
'set_color',
'Set the color of the display square based on red, green, and blue values.',
parameters: {
'red': Schema.number(description: 'Red component value (0.0 - 1.0)'),
'green': Schema.number(description: 'Green component value (0.0 - 1.0)'),
'blue': Schema.number(description: 'Blue component value (0.0 - 1.0)'),
},
);
Ringkasan video codelab ini
Tonton Craig Labenz dan Andrew Brogdon mendiskusikan codelab ini di episode #59 Observable Flutter:
Prasyarat
Untuk mendapatkan hasil maksimal dari codelab ini, Anda harus:
- Pengalaman pengembangan Flutter - Pemahaman tentang dasar-dasar Flutter dan sintaksis Dart
- Pengetahuan pemrograman asinkron - Pemahaman tentang Futures, async/await, dan stream
- Akun Firebase - Anda memerlukan Akun Google untuk menyiapkan Firebase
Mari mulai membangun aplikasi Flutter pertama Anda yang didukung LLM.
2. Penyiapan project & layanan echo
Pada langkah pertama ini, Anda akan menyiapkan struktur project dan menerapkan layanan echo yang nantinya akan digantikan dengan integrasi Gemini API. Hal ini menetapkan arsitektur aplikasi dan memastikan UI Anda berfungsi dengan benar sebelum menambahkan kompleksitas panggilan LLM.
Yang akan Anda pelajari di langkah ini
- Menyiapkan project Flutter dengan dependensi yang diperlukan
- Bekerja dengan paket
colorist_ui
untuk komponen UI - Menerapkan layanan pesan echo dan menghubungkannya ke UI
Membuat project Flutter baru
Mulailah dengan membuat project Flutter baru menggunakan perintah berikut:
flutter create -e colorist --platforms=android,ios,macos,web,windows
Flag -e
menunjukkan bahwa Anda menginginkan project kosong tanpa aplikasi counter
default. Aplikasi ini dirancang untuk berfungsi di desktop, perangkat seluler, dan web. Namun, flutterfire
saat ini tidak mendukung Linux.
Menambahkan dependensi
Buka direktori project Anda dan tambahkan dependensi yang diperlukan:
cd colorist
flutter pub add colorist_ui flutter_riverpod riverpod_annotation
flutter pub add --dev build_runner riverpod_generator riverpod_lint json_serializable
Tindakan ini akan menambahkan paket kunci berikut:
colorist_ui
: Paket kustom yang menyediakan komponen UI untuk aplikasi Coloristflutter_riverpod
danriverpod_annotation
: Untuk pengelolaan statuslogging
: Untuk logging terstruktur- Dependensi pengembangan untuk pembuatan dan linting kode
pubspec.yaml
Anda akan terlihat seperti ini:
pubspec.yaml
name: colorist
description: "A new Flutter project."
publish_to: 'none'
version: 0.1.0
environment:
sdk: ^3.9.2
dependencies:
flutter:
sdk: flutter
colorist_ui: ^0.3.0
flutter_riverpod: ^3.0.0
riverpod_annotation: ^3.0.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^6.0.0
build_runner: ^2.7.1
riverpod_generator: ^3.0.0
riverpod_lint: ^3.0.0
json_serializable: ^6.11.1
flutter:
uses-material-design: true
Menerapkan file main.dart
Ganti konten lib/main.dart
dengan konten berikut:
lib/main.dart
import 'package:colorist_ui/colorist_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() async {
runApp(ProviderScope(child: MainApp()));
}
class MainApp extends ConsumerWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: MainScreen(
sendMessage: (message) {
sendMessage(message, ref);
},
),
);
}
// A fake LLM that just echoes back what it receives.
void sendMessage(String message, WidgetRef ref) {
final chatStateNotifier = ref.read(chatStateProvider.notifier);
final logStateNotifier = ref.read(logStateProvider.notifier);
chatStateNotifier.addUserMessage(message);
logStateNotifier.logUserText(message);
chatStateNotifier.addLlmMessage(message, MessageState.complete);
logStateNotifier.logLlmText(message);
}
}
Hal ini menyiapkan aplikasi Flutter yang mengimplementasikan layanan echo yang meniru perilaku LLM dengan menampilkan pesan pengguna.
Memahami arsitektur
Mari luangkan waktu sejenak untuk memahami arsitektur aplikasi colorist
:
Paket colorist_ui
Paket colorist_ui
menyediakan komponen UI siap pakai dan alat pengelolaan status:
- MainScreen: Komponen UI utama yang menampilkan:
- Tata letak layar terpisah di desktop (area interaksi dan panel log)
- Antarmuka bertab di perangkat seluler
- Tampilan warna, antarmuka chat, dan thumbnail histori
- Pengelolaan Status: Aplikasi menggunakan beberapa notifikasi status:
- ChatStateNotifier: Mengelola pesan chat
- ColorStateNotifier: Mengelola warna dan histori saat ini
- LogStateNotifier: Mengelola entri log untuk proses debug
- Penanganan Pesan: Aplikasi menggunakan model pesan dengan status yang berbeda:
- Pesan pengguna: Dimasukkan oleh pengguna
- Pesan LLM: Dibuat oleh LLM (atau layanan echo Anda untuk saat ini)
- MessageState: Melacak apakah pesan LLM sudah selesai atau masih dalam proses streaming
Arsitektur aplikasi
Aplikasi mengikuti arsitektur berikut:
- Lapisan UI: Disediakan oleh paket
colorist_ui
- Pengelolaan Status: Menggunakan Riverpod untuk pengelolaan status reaktif
- Service Layer: Saat ini berisi layanan echo sederhana Anda, yang akan diganti dengan Gemini Chat Service
- Integrasi LLM: Akan ditambahkan pada langkah selanjutnya
Dengan pemisahan ini, Anda dapat berfokus pada penerapan integrasi LLM, sementara komponen UI sudah ditangani.
Menjalankan aplikasi
Jalankan aplikasi dengan perintah berikut:
flutter run -d DEVICE
Ganti DEVICE
dengan perangkat target Anda, seperti macos
, windows
, chrome
, atau ID perangkat.
Sekarang Anda akan melihat aplikasi Colorist dengan:
- Area tampilan warna dengan warna default
- Antarmuka chat tempat Anda dapat mengetik pesan
- Panel log yang menampilkan interaksi chat
Coba ketik pesan seperti "Saya ingin warna biru tua", lalu tekan Kirim. Layanan echo hanya akan mengulangi pesan Anda. Pada langkah selanjutnya, Anda akan mengganti nilai ini dengan interpretasi warna sebenarnya menggunakan Firebase AI Logic.
Apa langkah selanjutnya?
Pada langkah berikutnya, Anda akan mengonfigurasi Firebase dan menerapkan integrasi Gemini API dasar untuk menggantikan layanan echo dengan layanan chat Gemini. Hal ini akan memungkinkan aplikasi menafsirkan deskripsi warna dan memberikan respons cerdas.
Pemecahan masalah
Masalah paket UI
Jika Anda mengalami masalah dengan paket colorist_ui
:
- Pastikan Anda menggunakan versi terbaru
- Pastikan Anda telah menambahkan dependensi dengan benar
- Periksa apakah ada versi paket yang bertentangan
Error build
Jika Anda melihat error build:
- Pastikan Anda telah menginstal Flutter SDK saluran stabil terbaru
- Jalankan
flutter clean
, laluflutter pub get
- Periksa output konsol untuk melihat pesan error tertentu
Konsep utama yang dipelajari
- Menyiapkan project Flutter dengan dependensi yang diperlukan
- Memahami arsitektur aplikasi dan tanggung jawab komponen
- Menerapkan layanan sederhana yang meniru perilaku LLM
- Menghubungkan layanan ke komponen UI
- Menggunakan Riverpod untuk pengelolaan status
3. Integrasi chat Gemini dasar
Pada langkah ini, Anda akan mengganti layanan echo dari langkah sebelumnya dengan integrasi Gemini API menggunakan Firebase AI Logic. Anda akan mengonfigurasi Firebase, menyiapkan penyedia yang diperlukan, dan menerapkan layanan chat dasar yang berkomunikasi dengan Gemini API.
Yang akan Anda pelajari di langkah ini
- Menyiapkan Firebase di aplikasi Flutter
- Mengonfigurasi Firebase AI Logic untuk akses Gemini
- Membuat penyedia Riverpod untuk layanan Firebase dan Gemini
- Menerapkan layanan chat dasar dengan Gemini API
- Menangani respons API asinkron dan status error
Menyiapkan Firebase
Pertama, Anda perlu menyiapkan Firebase untuk project Flutter Anda. Hal ini mencakup pembuatan project Firebase, penambahan aplikasi Anda ke project tersebut, dan konfigurasi setelan Logika AI Firebase yang diperlukan.
Membuat project Firebase
- Buka Firebase Console dan login dengan Akun Google Anda.
- Klik Create a Firebase project atau pilih project yang ada.
- Ikuti wizard penyiapan untuk membuat project Anda.
Menyiapkan Logika AI Firebase di project Firebase Anda
- Di Firebase console, buka project Anda.
- Di sidebar kiri, pilih AI.
- Di menu drop-down AI, pilih AI Logic.
- Di kartu Firebase AI Logic, pilih Mulai.
- Ikuti perintah untuk mengaktifkan Gemini Developer API untuk project Anda.
Instal FlutterFire CLI
FlutterFire CLI menyederhanakan penyiapan Firebase di aplikasi Flutter:
dart pub global activate flutterfire_cli
Menambahkan Firebase ke aplikasi Flutter
- Tambahkan paket Firebase core dan Firebase AI Logic ke project Anda:
flutter pub add firebase_core firebase_ai
- Jalankan perintah konfigurasi FlutterFire:
flutterfire configure
Perintah ini akan:
- Meminta Anda memilih project Firebase yang baru saja Anda buat
- Mendaftarkan aplikasi Flutter Anda ke Firebase
- Buat file
firebase_options.dart
dengan konfigurasi project Anda
Perintah akan otomatis mendeteksi platform yang Anda pilih (iOS, Android, macOS, Windows, web) dan mengonfigurasinya dengan tepat.
Konfigurasi khusus platform
Firebase memerlukan versi minimum yang lebih tinggi daripada default untuk Flutter. Aplikasi ini juga memerlukan akses jaringan untuk berkomunikasi dengan server Firebase AI Logic.
Mengonfigurasi izin macOS
Untuk macOS, Anda harus mengaktifkan akses jaringan di hak aplikasi Anda:
- Buka
macos/Runner/DebugProfile.entitlements
dan tambahkan:
macos/Runner/DebugProfile.entitlements
<key>com.apple.security.network.client</key>
<true/>
- Buka juga
macos/Runner/Release.entitlements
dan tambahkan entri yang sama.
Mengonfigurasi setelan iOS
Untuk iOS, perbarui versi minimum di bagian atas ios/Podfile
:
ios/Podfile
# Firebase requires at least iOS 15.0
platform :ios, '15.0'
Membuat penyedia model Gemini
Sekarang Anda akan membuat penyedia Riverpod untuk Firebase dan Gemini. Buat file baru lib/providers/gemini.dart
:
lib/providers/gemini.dart
import 'dart:async';
import 'package:firebase_ai/firebase_ai.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../firebase_options.dart';
part 'gemini.g.dart';
@riverpod
Future<FirebaseApp> firebaseApp(Ref ref) =>
Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
@riverpod
Future<GenerativeModel> geminiModel(Ref ref) async {
await ref.watch(firebaseAppProvider.future);
final model = FirebaseAI.googleAI().generativeModel(
model: 'gemini-2.0-flash',
);
return model;
}
@Riverpod(keepAlive: true)
Future<ChatSession> chatSession(Ref ref) async {
final model = await ref.watch(geminiModelProvider.future);
return model.startChat();
}
File ini menentukan dasar untuk tiga penyedia utama. Penyedia ini dibuat saat Anda menjalankan dart run build_runner
oleh generator kode Riverpod.
firebaseAppProvider
: Menginisialisasi Firebase dengan konfigurasi project AndageminiModelProvider
: Membuat instance model generatif GeminichatSessionProvider
: Membuat dan mempertahankan sesi chat dengan model Gemini
Anotasi keepAlive: true
pada sesi chat memastikan sesi tersebut tetap ada di seluruh siklus proses aplikasi, sehingga mempertahankan konteks percakapan.
Menerapkan layanan chat Gemini
Buat file lib/services/gemini_chat_service.dart
baru untuk menerapkan layanan chat:
lib/services/gemini_chat_service.dart
import 'dart:async';
import 'package:colorist_ui/colorist_ui.dart';
import 'package:firebase_ai/firebase_ai.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../providers/gemini.dart';
part 'gemini_chat_service.g.dart';
class GeminiChatService {
GeminiChatService(this.ref);
final Ref ref;
Future<void> sendMessage(String message) async {
final chatSession = await ref.read(chatSessionProvider.future);
final chatStateNotifier = ref.read(chatStateProvider.notifier);
final logStateNotifier = ref.read(logStateProvider.notifier);
chatStateNotifier.addUserMessage(message);
logStateNotifier.logUserText(message);
final llmMessage = chatStateNotifier.createLlmMessage();
try {
final response = await chatSession.sendMessage(Content.text(message));
final responseText = response.text;
if (responseText != null) {
logStateNotifier.logLlmText(responseText);
chatStateNotifier.appendToMessage(llmMessage.id, responseText);
}
} catch (e, st) {
logStateNotifier.logError(e, st: st);
chatStateNotifier.appendToMessage(
llmMessage.id,
"\nI'm sorry, I encountered an error processing your request. "
"Please try again.",
);
} finally {
chatStateNotifier.finalizeMessage(llmMessage.id);
}
}
}
@riverpod
GeminiChatService geminiChatService(Ref ref) => GeminiChatService(ref);
Layanan ini:
- Menerima pesan pengguna dan mengirimkannya ke Gemini API
- Memperbarui antarmuka chat dengan respons dari model
- Mencatat semua komunikasi untuk memudahkan pemahaman alur LLM yang sebenarnya
- Menangani error dengan masukan pengguna yang sesuai
Catatan: Jendela Log akan terlihat hampir sama dengan jendela chat pada tahap ini. Log akan menjadi lebih menarik setelah Anda memperkenalkan panggilan fungsi dan kemudian respons streaming.
Membuat kode Riverpod
Jalankan perintah build runner untuk membuat kode Riverpod yang diperlukan:
dart run build_runner build --delete-conflicting-outputs
Tindakan ini akan membuat file .g.dart
yang diperlukan Riverpod agar dapat berfungsi.
Perbarui file main.dart
Perbarui file lib/main.dart
Anda untuk menggunakan layanan Gemini Chat yang baru:
lib/main.dart
import 'package:colorist_ui/colorist_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'providers/gemini.dart';
import 'services/gemini_chat_service.dart';
void main() async {
runApp(ProviderScope(child: MainApp()));
}
class MainApp extends ConsumerWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final model = ref.watch(geminiModelProvider);
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: model.when(
data: (data) => MainScreen(
sendMessage: (text) {
ref.read(geminiChatServiceProvider).sendMessage(text);
},
),
loading: () => LoadingScreen(message: 'Initializing Gemini Model'),
error: (err, st) => ErrorScreen(error: err),
),
);
}
}
Perubahan utama dalam update ini adalah:
- Mengganti layanan echo dengan layanan chat berbasis Gemini API
- Menambahkan layar pemuatan dan error menggunakan pola
AsyncValue
Riverpod dengan metodewhen
- Menghubungkan UI ke layanan chat baru Anda melalui callback
sendMessage
Menjalankan aplikasi
Jalankan aplikasi dengan perintah berikut:
flutter run -d DEVICE
Ganti DEVICE
dengan perangkat target Anda, seperti macos
, windows
, chrome
, atau ID perangkat.
Sekarang, saat Anda mengetik pesan, pesan tersebut akan dikirim ke Gemini API, dan Anda akan menerima respons dari LLM, bukan echo. Panel log akan menampilkan interaksi dengan API.
Memahami komunikasi LLM
Mari kita luangkan waktu sejenak untuk memahami apa yang terjadi saat Anda berkomunikasi dengan Gemini API:
Alur komunikasi
- Input pengguna: Pengguna memasukkan teks di antarmuka chat
- Pemformatan Permintaan: Aplikasi memformat teks sebagai objek
Content
untuk Gemini API - Komunikasi API: Teks dikirim ke Gemini API melalui Firebase AI Logic
- Pemrosesan LLM: Model Gemini memproses teks dan menghasilkan respons
- Penanganan Respons: Aplikasi menerima respons dan memperbarui UI
- Logging: Semua komunikasi dicatat untuk transparansi
Sesi chat dan konteks percakapan
Sesi chat Gemini mempertahankan konteks di antara pesan, sehingga memungkinkan interaksi percakapan. Artinya, LLM "mengingat" pertukaran sebelumnya dalam sesi saat ini, sehingga memungkinkan percakapan yang lebih koheren.
Anotasi keepAlive: true
pada penyedia sesi chat Anda memastikan konteks ini tetap ada di seluruh siklus proses aplikasi. Konteks persisten ini sangat penting untuk mempertahankan alur percakapan alami dengan LLM.
Apa langkah selanjutnya?
Pada tahap ini, Anda dapat bertanya apa pun kepada Gemini API, karena tidak ada batasan terkait apa yang akan diresponsnya. Misalnya, Anda dapat memintanya untuk membuat ringkasan Perang Mawar, yang tidak terkait dengan tujuan aplikasi warna Anda.
Pada langkah berikutnya, Anda akan membuat perintah sistem untuk memandu Gemini dalam menafsirkan deskripsi warna secara lebih efektif. Bagian ini akan menunjukkan cara menyesuaikan perilaku LLM untuk kebutuhan khusus aplikasi dan memfokuskan kemampuannya pada domain aplikasi Anda.
Pemecahan masalah
Masalah konfigurasi Firebase
Jika Anda mengalami error saat inisialisasi Firebase:
- Pastikan file
firebase_options.dart
Anda dibuat dengan benar - Pastikan Anda telah mengupgrade ke paket Blaze untuk akses Logika AI Firebase
Error akses API
Jika Anda mengalami error saat mengakses Gemini API:
- Konfirmasi bahwa penagihan telah disiapkan dengan benar di project Firebase Anda
- Periksa apakah Firebase AI Logic dan Cloud AI API diaktifkan di project Firebase Anda
- Periksa konektivitas jaringan dan setelan firewall Anda
- Pastikan nama model (
gemini-2.0-flash
) sudah benar dan tersedia
Masalah konteks percakapan
Jika Anda melihat bahwa Gemini tidak mengingat konteks sebelumnya dari percakapan:
- Pastikan fungsi
chatSession
dianotasi dengan@Riverpod(keepAlive: true)
- Pastikan Anda menggunakan kembali sesi chat yang sama untuk semua pertukaran pesan
- Pastikan sesi chat diinisialisasi dengan benar sebelum mengirim pesan
Masalah khusus platform
Untuk masalah khusus platform:
- iOS/macOS: Pastikan hak yang tepat ditetapkan dan versi minimum dikonfigurasi
- Android: Verifikasi bahwa versi SDK minimum telah ditetapkan dengan benar
- Periksa pesan error khusus platform di konsol
Konsep utama yang dipelajari
- Menyiapkan Firebase di aplikasi Flutter
- Mengonfigurasi Firebase AI Logic untuk akses ke Gemini
- Membuat penyedia Riverpod untuk layanan asinkron
- Menerapkan layanan chat yang berkomunikasi dengan LLM
- Menangani status API asinkron (memuat, error, data)
- Memahami alur komunikasi LLM dan sesi chat
4. Penulisan perintah yang efektif untuk deskripsi warna
Pada langkah ini, Anda akan membuat dan menerapkan perintah sistem yang memandu Gemini dalam menafsirkan deskripsi warna. Perintah sistem adalah cara efektif untuk menyesuaikan perilaku LLM untuk tugas tertentu tanpa mengubah kode Anda.
Yang akan Anda pelajari di langkah ini
- Memahami perintah sistem dan kepentingannya dalam aplikasi LLM
- Membuat perintah yang efektif untuk tugas khusus domain
- Memuat dan menggunakan perintah sistem di aplikasi Flutter
- Mengarahkan LLM untuk memberikan respons yang diformat secara konsisten
- Menguji pengaruh perintah sistem terhadap perilaku LLM
Memahami perintah sistem
Sebelum mempelajari implementasinya, mari kita pahami apa itu perintah sistem dan mengapa perintah tersebut penting:
Apa itu perintah sistem?
Perintah sistem adalah jenis petunjuk khusus yang diberikan kepada LLM yang menetapkan konteks, panduan perilaku, dan ekspektasi untuk responsnya. Tidak seperti pesan pengguna, perintah sistem:
- Menetapkan peran dan persona LLM
- Menentukan pengetahuan atau kemampuan khusus
- Memberikan petunjuk pemformatan
- Menetapkan batasan pada respons
- Menjelaskan cara menangani berbagai skenario
Anggap perintah sistem sebagai "deskripsi tugas" LLM - perintah ini memberi tahu model cara berperilaku sepanjang percakapan.
Mengapa perintah sistem itu penting
Perintah sistem sangat penting untuk menciptakan interaksi LLM yang konsisten dan berguna karena:
- Memastikan konsistensi: Memandu model untuk memberikan respons dalam format yang konsisten
- Meningkatkan relevansi: Memfokuskan model pada domain spesifik Anda (dalam kasus Anda, warna)
- Menetapkan batasan: Tentukan hal-hal yang boleh dan tidak boleh dilakukan model
- Meningkatkan pengalaman pengguna: Menciptakan pola interaksi yang lebih alami dan bermanfaat
- Mengurangi pasca-pemrosesan: Dapatkan respons dalam format yang lebih mudah diuraikan atau ditampilkan
Untuk aplikasi Colorist, Anda memerlukan LLM agar secara konsisten menafsirkan deskripsi warna dan memberikan nilai RGB dalam format tertentu.
Membuat aset perintah sistem
Pertama, Anda akan membuat file perintah sistem yang akan dimuat saat runtime. Pendekatan ini memungkinkan Anda mengubah perintah tanpa mengompilasi ulang aplikasi.
Buat file assets/system_prompt.md
baru dengan konten berikut:
assets/system_prompt.md
# Colorist System Prompt
You are a color expert assistant integrated into a desktop app called Colorist. Your job is to interpret natural language color descriptions and provide the appropriate RGB values that best represent that description.
## Your Capabilities
You are knowledgeable about colors, color theory, and how to translate natural language descriptions into specific RGB values. When users describe a color, you should:
1. Analyze their description to understand the color they are trying to convey
2. Determine the appropriate RGB values (values should be between 0.0 and 1.0)
3. Respond with a conversational explanation and explicitly state the RGB values
## How to Respond to User Inputs
When users describe a color:
1. First, acknowledge their color description with a brief, friendly response
2. Interpret what RGB values would best represent that color description
3. Always include the RGB values clearly in your response, formatted as: `RGB: (red=X.X, green=X.X, blue=X.X)`
4. Provide a brief explanation of your interpretation
Example:
User: "I want a sunset orange"
You: "Sunset orange is a warm, vibrant color that captures the golden-red hues of the setting sun. It combines a strong red component with moderate orange tones.
RGB: (red=1.0, green=0.5, blue=0.25)
I've selected values with high red, moderate green, and low blue to capture that beautiful sunset glow. This creates a warm orange with a slightly reddish tint, reminiscent of the sun low on the horizon."
## When Descriptions are Unclear
If a color description is ambiguous or unclear, please ask the user clarifying questions, one at a time.
## Important Guidelines
- Always keep RGB values between 0.0 and 1.0
- Always format RGB values as: `RGB: (red=X.X, green=X.X, blue=X.X)` for easy parsing
- Provide thoughtful, knowledgeable responses about colors
- When possible, include color psychology, associations, or interesting facts about colors
- Be conversational and engaging in your responses
- Focus on being helpful and accurate with your color interpretations
Memahami struktur perintah sistem
Mari kita uraikan fungsi perintah ini:
- Definisi peran: Menetapkan LLM sebagai "asisten ahli warna"
- Penjelasan tugas: Menentukan tugas utama sebagai menafsirkan deskripsi warna ke dalam nilai RGB
- Format respons: Menentukan secara persis cara nilai RGB harus diformat agar konsisten
- Contoh pertukaran: Memberikan contoh konkret dari pola interaksi yang diharapkan
- Penanganan kasus ekstrem: Memberikan petunjuk cara menangani deskripsi yang tidak jelas
- Batasan dan panduan: Menetapkan batas seperti menjaga nilai RGB antara 0,0 dan 1,0
Pendekatan terstruktur ini memastikan respons LLM akan konsisten, informatif, dan diformat dengan cara yang mudah diuraikan jika Anda ingin mengekstrak nilai RGB secara terprogram.
Perbarui pubspec.yaml
Sekarang, perbarui bagian bawah pubspec.yaml
Anda untuk menyertakan direktori aset:
pubspec.yaml
flutter:
uses-material-design: true
assets:
- assets/
Jalankan flutter pub get
untuk memperbarui paket aset.
Membuat penyedia perintah sistem
Buat file baru lib/providers/system_prompt.dart
untuk memuat perintah sistem:
lib/providers/system_prompt.dart
import 'package:flutter/services.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'system_prompt.g.dart';
@riverpod
Future<String> systemPrompt(Ref ref) =>
rootBundle.loadString('assets/system_prompt.md');
Penyedia ini menggunakan sistem pemuatan aset Flutter untuk membaca file perintah saat runtime.
Memperbarui penyedia model Gemini
Sekarang, ubah file lib/providers/gemini.dart
Anda untuk menyertakan perintah sistem:
lib/providers/gemini.dart
import 'dart:async';
import 'package:firebase_ai/firebase_ai.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../firebase_options.dart';
import 'system_prompt.dart'; // Add this import
part 'gemini.g.dart';
@riverpod
Future<FirebaseApp> firebaseApp(Ref ref) =>
Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
@riverpod
Future<GenerativeModel> geminiModel(Ref ref) async {
await ref.watch(firebaseAppProvider.future);
final systemPrompt = await ref.watch(systemPromptProvider.future); // Add this line
final model = FirebaseAI.googleAI().generativeModel(
model: 'gemini-2.0-flash',
systemInstruction: Content.system(systemPrompt), // And this line
);
return model;
}
@Riverpod(keepAlive: true)
Future<ChatSession> chatSession(Ref ref) async {
final model = await ref.watch(geminiModelProvider.future);
return model.startChat();
}
Perubahan utamanya adalah menambahkan systemInstruction: Content.system(systemPrompt)
saat membuat model generatif. Tindakan ini akan memberi tahu Gemini untuk menggunakan petunjuk Anda sebagai perintah sistem untuk semua interaksi dalam sesi percakapan ini.
Membuat kode Riverpod
Jalankan perintah build runner untuk membuat kode Riverpod yang diperlukan:
dart run build_runner build --delete-conflicting-outputs
Menjalankan dan menguji aplikasi
Sekarang jalankan aplikasi Anda:
flutter run -d DEVICE
Coba uji dengan berbagai deskripsi warna:
- "Saya ingin warna biru langit"
- "Give me a forest green" (Beri saya warna hijau hutan)
- "Buat warna oranye senja yang cerah"
- "Saya ingin warna lavender segar"
- "Show me something like a deep ocean blue" (Tampilkan sesuatu seperti warna biru laut dalam)
Anda akan melihat bahwa Gemini kini merespons dengan penjelasan percakapan tentang warna beserta nilai RGB yang diformat secara konsisten. Perintah sistem telah secara efektif memandu LLM untuk memberikan jenis respons yang Anda butuhkan.
Coba juga minta konten di luar konteks warna. Misalnya, penyebab utama Perang Mawar. Anda akan melihat perbedaan dari langkah sebelumnya.
Pentingnya rekayasa perintah untuk tugas khusus
Perintah sistem adalah seni dan sains. Hal ini merupakan bagian penting dari integrasi LLM yang dapat memengaruhi secara signifikan seberapa berguna model tersebut untuk aplikasi spesifik Anda. Yang telah Anda lakukan di sini adalah bentuk rekayasa prompt - menyesuaikan petunjuk agar model berperilaku sesuai dengan kebutuhan aplikasi Anda.
Rekayasa perintah yang efektif melibatkan:
- Definisi peran yang jelas: Menetapkan tujuan LLM
- Petunjuk eksplisit: Menjelaskan secara persis bagaimana LLM harus merespons
- Contoh konkret: Menunjukkan, bukan hanya memberi tahu seperti apa respons yang baik
- Penanganan kasus ekstrem: Menginstruksikan LLM tentang cara menangani skenario ambigu
- Spesifikasi pemformatan: Memastikan respons disusun dengan cara yang konsisten dan dapat digunakan
Perintah sistem yang telah Anda buat mengubah kemampuan umum Gemini menjadi asisten interpretasi warna khusus yang memberikan respons yang diformat secara khusus untuk kebutuhan aplikasi Anda. Ini adalah pola canggih yang dapat Anda terapkan ke berbagai domain dan tugas.
Apa langkah selanjutnya?
Pada langkah berikutnya, Anda akan membangun fondasi ini dengan menambahkan deklarasi fungsi, yang memungkinkan LLM tidak hanya menyarankan nilai RGB, tetapi benar-benar memanggil fungsi di aplikasi Anda untuk menetapkan warna secara langsung. Hal ini menunjukkan bagaimana LLM dapat menjembatani kesenjangan antara bahasa alami dan fitur aplikasi konkret.
Pemecahan masalah
Masalah pemuatan aset
Jika Anda mengalami error saat memuat perintah sistem:
- Pastikan
pubspec.yaml
Anda mencantumkan direktori aset dengan benar - Pastikan jalur di
rootBundle.loadString()
cocok dengan lokasi file Anda - Jalankan
flutter clean
, diikuti denganflutter pub get
untuk memperbarui paket aset
Respons tidak konsisten
Jika LLM tidak secara konsisten mengikuti petunjuk format Anda:
- Coba buat persyaratan format yang lebih jelas dalam perintah sistem
- Tambahkan lebih banyak contoh untuk menunjukkan pola yang diharapkan
- Pastikan format yang Anda minta wajar untuk model
Pembatasan kapasitas API
Jika Anda mengalami error terkait pembatasan kapasitas:
- Perhatikan bahwa layanan Firebase AI Logic memiliki batas penggunaan
- Pertimbangkan untuk menerapkan logika percobaan ulang dengan backoff eksponensial
- Periksa Firebase console Anda untuk mengetahui apakah ada masalah kuota
Konsep utama yang dipelajari
- Memahami peran dan pentingnya perintah sistem dalam aplikasi LLM
- Membuat perintah yang efektif dengan petunjuk, contoh, dan batasan yang jelas
- Memuat dan menggunakan perintah sistem di aplikasi Flutter
- Memandu perilaku LLM untuk tugas khusus domain
- Menggunakan rekayasa perintah untuk membentuk respons LLM
Langkah ini menunjukkan cara Anda dapat mencapai penyesuaian perilaku LLM yang signifikan tanpa mengubah kode Anda - cukup dengan memberikan petunjuk yang jelas dalam perintah sistem.
5. Deklarasi fungsi untuk alat LLM
Pada langkah ini, Anda akan memulai pekerjaan untuk mengaktifkan Gemini agar dapat mengambil tindakan di aplikasi Anda dengan menerapkan deklarasi fungsi. Fitur canggih ini memungkinkan LLM tidak hanya menyarankan nilai RGB, tetapi juga menetapkannya di UI aplikasi Anda melalui panggilan alat khusus. Namun, langkah berikutnya diperlukan untuk melihat permintaan LLM yang dieksekusi di aplikasi Flutter.
Yang akan Anda pelajari di langkah ini
- Memahami panggilan fungsi LLM dan manfaatnya untuk aplikasi Flutter
- Menentukan deklarasi fungsi berbasis skema untuk Gemini
- Mengintegrasikan deklarasi fungsi dengan model Gemini Anda
- Memperbarui perintah sistem untuk memanfaatkan kemampuan alat
Memahami pemanggilan fungsi
Sebelum menerapkan deklarasi fungsi, mari kita pahami apa itu dan mengapa hal ini penting:
Apa itu panggilan fungsi?
Pemanggilan fungsi (terkadang disebut "penggunaan alat") adalah kemampuan yang memungkinkan LLM untuk:
- Mengenali kapan permintaan pengguna akan diuntungkan dengan memanggil fungsi tertentu
- Buat objek JSON terstruktur dengan parameter yang diperlukan untuk fungsi tersebut
- Biarkan aplikasi Anda menjalankan fungsi dengan parameter tersebut
- Menerima hasil fungsi dan memasukkannya ke dalam responsnya
Daripada hanya mendeskripsikan apa yang harus dilakukan, panggilan fungsi memungkinkan LLM memicu tindakan konkret di aplikasi Anda.
Alasan pentingnya panggilan fungsi untuk aplikasi Flutter
Panggilan fungsi menciptakan jembatan yang kuat antara bahasa alami dan fitur aplikasi:
- Tindakan langsung: Pengguna dapat mendeskripsikan apa yang mereka inginkan dalam bahasa alami, dan aplikasi merespons dengan tindakan konkret
- Output terstruktur: LLM menghasilkan data terstruktur yang bersih, bukan teks yang perlu diuraikan
- Operasi kompleks: Memungkinkan LLM mengakses data eksternal, melakukan perhitungan, atau mengubah status aplikasi
- Pengalaman pengguna yang lebih baik: Menciptakan integrasi yang lancar antara percakapan dan fungsi
Di aplikasi Colorist, panggilan fungsi memungkinkan pengguna mengatakan "Saya ingin warna hijau hutan" dan UI akan segera diperbarui dengan warna tersebut, tanpa harus mengurai nilai RGB dari teks.
Menentukan deklarasi fungsi
Buat file lib/services/gemini_tools.dart
baru untuk menentukan deklarasi fungsi Anda:
lib/services/gemini_tools.dart
import 'package:firebase_ai/firebase_ai.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'gemini_tools.g.dart';
class GeminiTools {
GeminiTools(this.ref);
final Ref ref;
FunctionDeclaration get setColorFuncDecl => FunctionDeclaration(
'set_color',
'Set the color of the display square based on red, green, and blue values.',
parameters: {
'red': Schema.number(description: 'Red component value (0.0 - 1.0)'),
'green': Schema.number(description: 'Green component value (0.0 - 1.0)'),
'blue': Schema.number(description: 'Blue component value (0.0 - 1.0)'),
},
);
List<Tool> get tools => [
Tool.functionDeclarations([setColorFuncDecl]),
];
}
@riverpod
GeminiTools geminiTools(Ref ref) => GeminiTools(ref);
Memahami deklarasi fungsi
Mari kita uraikan fungsi kode ini:
- Penamaan fungsi: Anda memberi nama fungsi
set_color
untuk menunjukkan tujuannya dengan jelas - Deskripsi fungsi: Anda memberikan deskripsi yang jelas untuk membantu LLM memahami kapan harus menggunakannya
- Definisi parameter: Anda menentukan parameter terstruktur dengan deskripsinya sendiri:
red
: Komponen merah RGB, ditentukan sebagai angka antara 0,0 dan 1,0green
: Komponen hijau RGB, ditentukan sebagai angka antara 0,0 dan 1,0blue
: Komponen biru RGB, ditentukan sebagai angka antara 0,0 dan 1,0
- Jenis skema: Anda menggunakan
Schema.number()
untuk menunjukkan bahwa ini adalah nilai numerik - Kumpulan alat: Anda membuat daftar alat yang berisi deklarasi fungsi Anda
Pendekatan terstruktur ini membantu LLM Gemini memahami:
- Kapan fungsi ini harus dipanggil
- Parameter yang perlu disediakan
- Batasan yang berlaku untuk parameter tersebut (seperti rentang nilai)
Memperbarui penyedia model Gemini
Sekarang, ubah file lib/providers/gemini.dart
Anda untuk menyertakan deklarasi fungsi saat menginisialisasi model Gemini:
lib/providers/gemini.dart
import 'dart:async';
import 'package:firebase_ai/firebase_ai.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../firebase_options.dart';
import '../services/gemini_tools.dart'; // Add this import
import 'system_prompt.dart';
part 'gemini.g.dart';
@riverpod
Future<FirebaseApp> firebaseApp(Ref ref) =>
Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
@riverpod
Future<GenerativeModel> geminiModel(Ref ref) async {
await ref.watch(firebaseAppProvider.future);
final systemPrompt = await ref.watch(systemPromptProvider.future);
final geminiTools = ref.watch(geminiToolsProvider); // Add this line
final model = FirebaseAI.googleAI().generativeModel(
model: 'gemini-2.0-flash',
systemInstruction: Content.system(systemPrompt),
tools: geminiTools.tools, // And this line
);
return model;
}
@Riverpod(keepAlive: true)
Future<ChatSession> chatSession(Ref ref) async {
final model = await ref.watch(geminiModelProvider.future);
return model.startChat();
}
Perubahan utamanya adalah menambahkan parameter tools: geminiTools.tools
saat membuat model generatif. Hal ini membuat Gemini mengetahui fungsi yang tersedia untuk dipanggilnya.
Memperbarui perintah sistem
Sekarang Anda perlu mengubah perintah sistem untuk menginstruksikan LLM tentang penggunaan alat set_color
yang baru. Update assets/system_prompt.md
:
assets/system_prompt.md
# Colorist System Prompt
You are a color expert assistant integrated into a desktop app called Colorist. Your job is to interpret natural language color descriptions and set the appropriate color values using a specialized tool.
## Your Capabilities
You are knowledgeable about colors, color theory, and how to translate natural language descriptions into specific RGB values. You have access to the following tool:
`set_color` - Sets the RGB values for the color display based on a description
## How to Respond to User Inputs
When users describe a color:
1. First, acknowledge their color description with a brief, friendly response
2. Interpret what RGB values would best represent that color description
3. Use the `set_color` tool to set those values (all values should be between 0.0 and 1.0)
4. After setting the color, provide a brief explanation of your interpretation
Example:
User: "I want a sunset orange"
You: "Sunset orange is a warm, vibrant color that captures the golden-red hues of the setting sun. It combines a strong red component with moderate orange tones."
[Then you would call the set_color tool with approximately: red=1.0, green=0.5, blue=0.25]
After the tool call: "I've set a warm orange with strong red, moderate green, and minimal blue components that is reminiscent of the sun low on the horizon."
## When Descriptions are Unclear
If a color description is ambiguous or unclear, please ask the user clarifying questions, one at a time.
## Important Guidelines
- Always keep RGB values between 0.0 and 1.0
- Provide thoughtful, knowledgeable responses about colors
- When possible, include color psychology, associations, or interesting facts about colors
- Be conversational and engaging in your responses
- Focus on being helpful and accurate with your color interpretations
Perubahan utama pada perintah sistem adalah:
- Pengenalan alat: Alih-alih meminta nilai RGB yang diformat, Anda sekarang memberi tahu LLM tentang alat
set_color
- Proses yang diubah: Anda mengubah langkah 3 dari "format nilai dalam respons" menjadi "gunakan alat untuk menetapkan nilai"
- Contoh yang diperbarui: Anda menunjukkan cara respons harus menyertakan panggilan alat, bukan teks yang diformat
- Persyaratan pemformatan dihapus: Karena Anda menggunakan panggilan fungsi terstruktur, Anda tidak lagi memerlukan format teks tertentu
Perintah yang diperbarui ini mengarahkan LLM untuk menggunakan panggilan fungsi, bukan hanya memberikan nilai RGB dalam bentuk teks.
Membuat kode Riverpod
Jalankan perintah build runner untuk membuat kode Riverpod yang diperlukan:
dart run build_runner build --delete-conflicting-outputs
Menjalankan aplikasi
Pada tahap ini, Gemini akan membuat konten yang mencoba menggunakan panggilan fungsi, tetapi Anda belum menerapkan handler untuk panggilan fungsi. Saat Anda menjalankan aplikasi dan mendeskripsikan warna, Anda akan melihat Gemini merespons seolah-olah telah memanggil alat, tetapi Anda tidak akan melihat perubahan warna apa pun di UI hingga langkah berikutnya.
Jalankan aplikasi Anda:
flutter run -d DEVICE
Coba deskripsikan warna seperti "biru laut dalam" atau "hijau hutan" dan amati responsnya. LLM mencoba memanggil fungsi yang ditentukan di atas, tetapi kode Anda belum mendeteksi panggilan fungsi.
Proses panggilan fungsi
Mari kita pahami apa yang terjadi saat Gemini menggunakan panggilan fungsi:
- Pemilihan fungsi: LLM memutuskan apakah panggilan fungsi akan bermanfaat berdasarkan permintaan pengguna
- Pembuatan parameter: LLM membuat nilai parameter yang sesuai dengan skema fungsi
- Format panggilan fungsi: LLM mengirim objek panggilan fungsi terstruktur dalam responsnya
- Penanganan aplikasi: Aplikasi Anda akan menerima panggilan ini dan menjalankan fungsi yang relevan (diterapkan pada langkah berikutnya)
- Integrasi respons: Dalam percakapan bolak-balik, LLM mengharapkan hasil fungsi ditampilkan
Dalam status aplikasi Anda saat ini, tiga langkah pertama terjadi, tetapi Anda belum menerapkan langkah 4 atau 5 (menangani panggilan fungsi), yang akan Anda lakukan pada langkah berikutnya.
Detail teknis: Cara Gemini memutuskan kapan harus menggunakan fungsi
Gemini membuat keputusan cerdas tentang kapan harus menggunakan fungsi berdasarkan:
- Maksud pengguna: Apakah permintaan pengguna akan lebih baik dipenuhi oleh fungsi
- Relevansi fungsi: Seberapa baik kecocokan fungsi yang tersedia dengan tugas
- Ketersediaan parameter: Apakah dapat menentukan nilai parameter dengan yakin
- Petunjuk sistem: Panduan dari perintah sistem Anda tentang penggunaan fungsi
Dengan memberikan deklarasi fungsi dan petunjuk sistem yang jelas, Anda telah menyiapkan Gemini untuk mengenali permintaan deskripsi warna sebagai peluang untuk memanggil fungsi set_color
.
Apa langkah selanjutnya?
Pada langkah berikutnya, Anda akan menerapkan handler untuk panggilan fungsi yang berasal dari Gemini. Hal ini akan melengkapi siklus, sehingga deskripsi pengguna dapat memicu perubahan warna aktual di UI melalui panggilan fungsi LLM.
Pemecahan masalah
Masalah deklarasi fungsi
Jika Anda mengalami error dengan deklarasi fungsi:
- Pastikan nama dan jenis parameter cocok dengan yang diharapkan
- Pastikan nama fungsi jelas dan deskriptif
- Pastikan deskripsi fungsi menjelaskan tujuannya secara akurat
Masalah perintah sistem
Jika LLM tidak mencoba menggunakan fungsi:
- Pastikan perintah sistem Anda dengan jelas menginstruksikan LLM untuk menggunakan alat
set_color
- Pastikan contoh dalam perintah sistem menunjukkan penggunaan fungsi
- Coba buat petunjuk penggunaan alat lebih jelas
Masalah umum
Jika Anda mengalami masalah lain:
- Periksa konsol untuk mengetahui apakah ada error terkait deklarasi fungsi
- Pastikan alat diteruskan dengan benar ke model
- Pastikan semua kode yang dihasilkan Riverpod sudah terbaru
Konsep utama yang dipelajari
- Menentukan deklarasi fungsi untuk memperluas kemampuan LLM di aplikasi Flutter
- Membuat skema parameter untuk pengumpulan data terstruktur
- Mengintegrasikan deklarasi fungsi dengan model Gemini
- Memperbarui perintah sistem untuk mendorong penggunaan fungsi
- Memahami cara LLM memilih dan memanggil fungsi
Langkah ini menunjukkan bagaimana LLM dapat menjembatani kesenjangan antara input bahasa alami dan panggilan fungsi terstruktur, sehingga meletakkan dasar untuk integrasi yang lancar antara percakapan dan fitur aplikasi.
6. Menerapkan penanganan alat
Pada langkah ini, Anda akan menerapkan handler untuk panggilan fungsi yang berasal dari Gemini. Hal ini melengkapi lingkaran komunikasi antara input bahasa alami dan fitur aplikasi konkret, sehingga memungkinkan LLM memanipulasi UI Anda secara langsung berdasarkan deskripsi pengguna.
Yang akan Anda pelajari di langkah ini
- Memahami pipeline panggilan fungsi lengkap dalam aplikasi LLM
- Memproses panggilan fungsi dari Gemini di aplikasi Flutter
- Menerapkan handler fungsi yang mengubah status aplikasi
- Menangani respons fungsi dan menampilkan hasil ke LLM
- Membuat alur komunikasi lengkap antara LLM dan UI
- Mencatat panggilan dan respons fungsi untuk transparansi
Memahami pipeline panggilan fungsi
Sebelum mempelajari implementasi, mari kita pahami pipeline panggilan fungsi lengkap:
Alur end-to-end
- Input pengguna: Pengguna mendeskripsikan warna dalam bahasa alami (misalnya, "forest green")
- Pemrosesan LLM: Gemini menganalisis deskripsi dan memutuskan untuk memanggil fungsi
set_color
- Pembuatan panggilan fungsi: Gemini membuat JSON terstruktur dengan parameter (nilai merah, hijau, biru)
- Penerimaan panggilan fungsi: Aplikasi Anda menerima data terstruktur ini dari Gemini
- Eksekusi fungsi: Aplikasi Anda mengeksekusi fungsi dengan parameter yang diberikan
- Pembaruan status: Fungsi ini memperbarui status aplikasi Anda (mengubah warna yang ditampilkan)
- Pembuatan respons: Fungsi Anda menampilkan hasil kembali ke LLM
- Penggabungan respons: LLM menggabungkan hasil ini ke dalam respons akhirnya
- Pembaruan UI: UI Anda bereaksi terhadap perubahan status, menampilkan warna baru
Siklus komunikasi yang lengkap sangat penting untuk integrasi LLM yang tepat. Saat melakukan panggilan fungsi, LLM tidak hanya mengirimkan permintaan dan melanjutkan. Sebagai gantinya, fungsi ini menunggu aplikasi Anda menjalankan fungsi dan menampilkan hasil. Kemudian, LLM menggunakan hasil ini untuk merumuskan respons akhirnya, sehingga menciptakan alur percakapan alami yang mengakui tindakan yang telah dilakukan.
Menerapkan pengendali fungsi
Mari perbarui file lib/services/gemini_tools.dart
Anda untuk menambahkan pengendali untuk panggilan fungsi:
lib/services/gemini_tools.dart
import 'package:colorist_ui/colorist_ui.dart';
import 'package:firebase_ai/firebase_ai.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'gemini_tools.g.dart';
class GeminiTools {
GeminiTools(this.ref);
final Ref ref;
FunctionDeclaration get setColorFuncDecl => FunctionDeclaration(
'set_color',
'Set the color of the display square based on red, green, and blue values.',
parameters: {
'red': Schema.number(description: 'Red component value (0.0 - 1.0)'),
'green': Schema.number(description: 'Green component value (0.0 - 1.0)'),
'blue': Schema.number(description: 'Blue component value (0.0 - 1.0)'),
},
);
List<Tool> get tools => [
Tool.functionDeclarations([setColorFuncDecl]),
];
Map<String, Object?> handleFunctionCall( // Add from here
String functionName,
Map<String, Object?> arguments,
) {
final logStateNotifier = ref.read(logStateProvider.notifier);
logStateNotifier.logFunctionCall(functionName, arguments);
return switch (functionName) {
'set_color' => handleSetColor(arguments),
_ => handleUnknownFunction(functionName),
};
}
Map<String, Object?> handleSetColor(Map<String, Object?> arguments) {
final colorStateNotifier = ref.read(colorStateProvider.notifier);
final red = (arguments['red'] as num).toDouble();
final green = (arguments['green'] as num).toDouble();
final blue = (arguments['blue'] as num).toDouble();
final functionResults = {
'success': true,
'current_color': colorStateNotifier
.updateColor(red: red, green: green, blue: blue)
.toLLMContextMap(),
};
final logStateNotifier = ref.read(logStateProvider.notifier);
logStateNotifier.logFunctionResults(functionResults);
return functionResults;
}
Map<String, Object?> handleUnknownFunction(String functionName) {
final logStateNotifier = ref.read(logStateProvider.notifier);
logStateNotifier.logWarning('Unsupported function call $functionName');
return {
'success': false,
'reason': 'Unsupported function call $functionName',
};
} // To here.
}
@riverpod
GeminiTools geminiTools(Ref ref) => GeminiTools(ref);
Memahami handler fungsi
Mari kita uraikan fungsi handler ini:
handleFunctionCall
: Dispatcher pusat yang:- Mencatat panggilan fungsi untuk transparansi di panel log
- Merutekan ke pengendali yang sesuai berdasarkan nama fungsi
- Menampilkan respons terstruktur yang akan dikirim kembali ke LLM
handleSetColor
: Handler khusus untuk fungsiset_color
Anda yang:- Mengekstrak nilai RGB dari peta argumen
- Mengonversinya ke jenis yang diharapkan (double)
- Memperbarui status warna aplikasi menggunakan
colorStateNotifier
- Membuat respons terstruktur dengan status berhasil dan informasi warna saat ini
- Mencatat hasil fungsi untuk proses debug
handleUnknownFunction
: Pengendali penggantian untuk fungsi yang tidak diketahui yang:- Mencatat peringatan tentang fungsi yang tidak didukung
- Menampilkan respons error ke LLM
Fungsi handleSetColor
sangat penting karena menjembatani kesenjangan antara pemahaman bahasa alami LLM dan perubahan UI yang konkret.
Memperbarui layanan chat Gemini untuk memproses panggilan dan respons fungsi
Sekarang, mari kita perbarui file lib/services/gemini_chat_service.dart
untuk memproses panggilan fungsi dari respons LLM dan mengirimkan hasilnya kembali ke LLM:
lib/services/gemini_chat_service.dart
import 'dart:async';
import 'package:colorist_ui/colorist_ui.dart';
import 'package:firebase_ai/firebase_ai.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../providers/gemini.dart';
import 'gemini_tools.dart'; // Add this import
part 'gemini_chat_service.g.dart';
class GeminiChatService {
GeminiChatService(this.ref);
final Ref ref;
Future<void> sendMessage(String message) async {
final chatSession = await ref.read(chatSessionProvider.future);
final chatStateNotifier = ref.read(chatStateProvider.notifier);
final logStateNotifier = ref.read(logStateProvider.notifier);
chatStateNotifier.addUserMessage(message);
logStateNotifier.logUserText(message);
final llmMessage = chatStateNotifier.createLlmMessage();
try {
final response = await chatSession.sendMessage(Content.text(message));
final responseText = response.text;
if (responseText != null) {
logStateNotifier.logLlmText(responseText);
chatStateNotifier.appendToMessage(llmMessage.id, responseText);
}
if (response.functionCalls.isNotEmpty) { // Add from here
final geminiTools = ref.read(geminiToolsProvider);
final functionResultResponse = await chatSession.sendMessage(
Content.functionResponses([
for (final functionCall in response.functionCalls)
FunctionResponse(
functionCall.name,
geminiTools.handleFunctionCall(
functionCall.name,
functionCall.args,
),
),
]),
);
final responseText = functionResultResponse.text;
if (responseText != null) {
logStateNotifier.logLlmText(responseText);
chatStateNotifier.appendToMessage(llmMessage.id, responseText);
}
} // To here.
} catch (e, st) {
logStateNotifier.logError(e, st: st);
chatStateNotifier.appendToMessage(
llmMessage.id,
"\nI'm sorry, I encountered an error processing your request. "
"Please try again.",
);
} finally {
chatStateNotifier.finalizeMessage(llmMessage.id);
}
}
}
@riverpod
GeminiChatService geminiChatService(Ref ref) => GeminiChatService(ref);
Memahami alur komunikasi
Penambahan utama di sini adalah penanganan lengkap panggilan dan respons fungsi:
if (response.functionCalls.isNotEmpty) {
final geminiTools = ref.read(geminiToolsProvider);
final functionResultResponse = await chatSession.sendMessage(
Content.functionResponses([
for (final functionCall in response.functionCalls)
FunctionResponse(
functionCall.name,
geminiTools.handleFunctionCall(
functionCall.name,
functionCall.args,
),
),
]),
);
final responseText = functionResultResponse.text;
if (responseText != null) {
logStateNotifier.logLlmText(responseText);
chatStateNotifier.appendToMessage(llmMessage.id, responseText);
}
}
Kode ini:
- Memeriksa apakah respons LLM berisi panggilan fungsi
- Untuk setiap panggilan fungsi, panggil metode
handleFunctionCall
Anda dengan nama dan argumen fungsi - Mengumpulkan hasil setiap panggilan fungsi
- Mengirimkan kembali hasil ini ke LLM menggunakan
Content.functionResponses
- Memproses respons LLM terhadap hasil fungsi
- Mengupdate UI dengan teks respons akhir
Tindakan ini akan membuat alur perjalanan pulang pergi:
- Pengguna → LLM: Meminta warna
- LLM → Aplikasi: Panggilan fungsi dengan parameter
- Aplikasi → Pengguna: Warna baru ditampilkan
- Aplikasi → LLM: Hasil fungsi
- LLM → Pengguna: Respons akhir yang menggabungkan hasil fungsi
Membuat kode Riverpod
Jalankan perintah build runner untuk membuat kode Riverpod yang diperlukan:
dart run build_runner build --delete-conflicting-outputs
Menjalankan dan menguji alur lengkap
Sekarang jalankan aplikasi Anda:
flutter run -d DEVICE
Coba masukkan berbagai deskripsi warna:
- "Saya ingin warna merah kirmizi tua"
- "Show me a calming sky blue" (Tampilkan warna biru langit yang menenangkan)
- "Beri tahu saya warna daun mint segar"
- "I want to see a warm sunset orange" (Saya ingin melihat warna oranye senja yang hangat)
- "Buat warna ungu kerajaan yang kaya"
Sekarang Anda akan melihat:
- Pesan Anda muncul di antarmuka chat
- Respons Gemini muncul dalam percakapan
- Panggilan fungsi yang dicatat dalam panel log
- Hasil fungsi dicatat dalam log segera setelah
- Persegi panjang warna diperbarui untuk menampilkan warna yang dijelaskan
- Nilai RGB diperbarui untuk menampilkan komponen warna baru
- Respons akhir Gemini muncul, sering kali mengomentari warna yang ditetapkan
Panel log memberikan insight tentang apa yang terjadi di balik layar. Anda akan melihat:
- Panggilan fungsi persis yang dilakukan Gemini
- Parameter yang dipilihnya untuk setiap nilai RGB
- Hasil yang ditampilkan fungsi Anda
- Respons lanjutan dari Gemini
Pemberi tahu status warna
colorStateNotifier
yang Anda gunakan untuk memperbarui warna adalah bagian dari paket colorist_ui
. API ini mengelola:
- Warna saat ini yang ditampilkan di UI
- Histori warna (10 warna terakhir)
- Pemberitahuan perubahan status ke komponen UI
Saat Anda memanggil updateColor
dengan nilai RGB baru, tindakan ini akan:
- Membuat objek
ColorData
baru dengan nilai yang diberikan - Memperbarui warna saat ini dalam status aplikasi
- Menambahkan warna ke histori
- Memicu update UI melalui pengelolaan status Riverpod
Komponen UI dalam paket colorist_ui
memantau status ini dan otomatis diperbarui saat berubah, sehingga menciptakan pengalaman reaktif.
Memahami penanganan error
Penerapan Anda mencakup penanganan error yang andal:
- Blok try-catch: Membungkus semua interaksi LLM untuk menangkap pengecualian apa pun
- Pencatatan error: Mencatat error di panel log dengan stack trace
- Masukan pengguna: Memberikan pesan error yang mudah dipahami dalam chat
- Pembersihan status: Menyelesaikan status pesan meskipun terjadi error
Hal ini memastikan aplikasi tetap stabil dan memberikan masukan yang sesuai meskipun terjadi masalah pada layanan LLM atau eksekusi fungsi.
Manfaat panggilan fungsi untuk pengalaman pengguna
Apa yang telah Anda capai di sini menunjukkan bagaimana LLM dapat membuat antarmuka alami yang efektif:
- Antarmuka natural language: Pengguna menyatakan maksud dalam bahasa sehari-hari
- Interpretasi cerdas: LLM menerjemahkan deskripsi yang tidak jelas menjadi nilai yang tepat
- Manipulasi langsung: UI diperbarui sebagai respons terhadap bahasa alami
- Respons kontekstual: LLM memberikan konteks percakapan tentang perubahan
- Beban kognitif rendah: Pengguna tidak perlu memahami nilai RGB atau teori warna
Pola penggunaan panggilan fungsi LLM untuk menjembatani bahasa alami dan tindakan UI ini dapat diperluas ke banyak domain lain di luar pemilihan warna.
Apa langkah selanjutnya?
Pada langkah berikutnya, Anda akan meningkatkan kualitas pengalaman pengguna dengan menerapkan respons streaming. Daripada menunggu respons lengkap, Anda akan memproses potongan teks dan panggilan fungsi saat diterima, sehingga membuat aplikasi yang lebih responsif dan menarik.
Pemecahan masalah
Masalah panggilan fungsi
Jika Gemini tidak memanggil fungsi Anda atau parameter salah:
- Pastikan deklarasi fungsi Anda cocok dengan yang dijelaskan dalam perintah sistem
- Pastikan nama dan jenis parameter konsisten
- Pastikan perintah sistem Anda secara eksplisit menginstruksikan LLM untuk menggunakan alat tersebut
- Pastikan nama fungsi di handler Anda sama persis dengan yang ada dalam deklarasi
- Periksa panel log untuk mendapatkan informasi mendetail tentang panggilan fungsi
Masalah respons fungsi
Jika hasil fungsi tidak dikirim kembali ke LLM dengan benar:
- Pastikan fungsi Anda menampilkan Peta yang diformat dengan benar
- Pastikan Content.functionResponses dibuat dengan benar
- Cari error apa pun di log yang terkait dengan respons fungsi
- Pastikan Anda menggunakan sesi chat yang sama untuk respons
Masalah tampilan warna
Jika warna tidak ditampilkan dengan benar:
- Pastikan nilai RGB dikonversi dengan benar menjadi ganda (LLM mungkin mengirimkannya sebagai bilangan bulat)
- Pastikan nilai berada dalam rentang yang diharapkan (0,0 hingga 1,0)
- Pastikan notifikasi status warna dipanggil dengan benar
- Periksa log untuk mengetahui nilai persis yang diteruskan ke fungsi
Masalah umum
Untuk masalah umum:
- Periksa error atau peringatan dalam log
- Memverifikasi konektivitas Firebase AI Logic
- Periksa apakah ada ketidakcocokan jenis dalam parameter fungsi
- Pastikan semua kode yang dihasilkan Riverpod sudah terbaru
Konsep utama yang dipelajari
- Menerapkan pipeline panggilan fungsi lengkap di Flutter
- Membuat komunikasi penuh antara LLM dan aplikasi Anda
- Memproses data terstruktur dari respons LLM
- Mengirim hasil fungsi kembali ke LLM untuk dimasukkan ke dalam respons
- Menggunakan panel log untuk mendapatkan visibilitas ke dalam interaksi aplikasi LLM
- Menghubungkan input bahasa alami dengan perubahan UI yang konkret
Setelah langkah ini selesai, aplikasi Anda kini menunjukkan salah satu pola paling efektif untuk integrasi LLM: menerjemahkan input bahasa alami ke dalam tindakan UI yang konkret, sekaligus mempertahankan percakapan yang koheren yang mengakui tindakan ini. Hal ini menciptakan antarmuka percakapan yang intuitif dan terasa ajaib bagi pengguna.
7. Respons streaming untuk UX yang lebih baik
Pada langkah ini, Anda akan meningkatkan kualitas pengalaman pengguna dengan menerapkan respons streaming dari Gemini. Daripada menunggu seluruh respons dibuat, Anda akan memproses potongan teks dan panggilan fungsi saat diterima, sehingga membuat aplikasi yang lebih responsif dan menarik.
Yang akan Anda bahas dalam langkah ini
- Pentingnya streaming untuk aplikasi yang didukung LLM
- Menerapkan respons LLM streaming di aplikasi Flutter
- Memproses potongan teks parsial saat tiba dari API
- Mengelola status percakapan untuk mencegah konflik pesan
- Menangani panggilan fungsi dalam respons streaming
- Membuat indikator visual untuk respons yang sedang berlangsung
Mengapa streaming penting untuk aplikasi LLM
Sebelum menerapkan, mari pahami mengapa respons streaming sangat penting untuk menciptakan pengalaman pengguna yang luar biasa dengan LLM:
Pengalaman pengguna yang ditingkatkan
Respons streaming memberikan beberapa manfaat signifikan bagi pengalaman pengguna:
- Mengurangi latensi yang dirasakan: Pengguna melihat teks mulai muncul dengan segera (biasanya dalam waktu 100-300 md), bukan menunggu beberapa detik untuk mendapatkan respons lengkap. Persepsi tentang keinstanan ini secara signifikan meningkatkan kepuasan pengguna.
- Ritme percakapan alami: Teks yang muncul secara bertahap meniru cara manusia berkomunikasi, sehingga menciptakan pengalaman dialog yang lebih alami.
- Pemrosesan informasi progresif: Pengguna dapat mulai memproses informasi saat informasi tersebut tiba, daripada kewalahan dengan blok teks besar sekaligus.
- Peluang untuk interupsi awal: Dalam aplikasi lengkap, pengguna berpotensi menginterupsi atau mengalihkan LLM jika mereka melihatnya bergerak ke arah yang tidak membantu.
- Konfirmasi visual aktivitas: Teks streaming memberikan masukan langsung bahwa sistem berfungsi, sehingga mengurangi ketidakpastian.
Keunggulan teknis
Selain peningkatan UX, streaming menawarkan manfaat teknis:
- Eksekusi fungsi awal: Panggilan fungsi dapat dideteksi dan dieksekusi segera setelah muncul dalam stream, tanpa menunggu respons lengkap.
- Update UI inkremental: Anda dapat memperbarui UI secara progresif saat informasi baru tiba, sehingga menciptakan pengalaman yang lebih dinamis.
- Pengelolaan status percakapan: Streaming memberikan sinyal yang jelas tentang kapan respons selesai dan kapan masih dalam proses, sehingga memungkinkan pengelolaan status yang lebih baik.
- Mengurangi risiko waktu tunggu habis: Dengan respons non-streaming, pembuatan yang berjalan lama berisiko menyebabkan waktu tunggu koneksi habis. Streaming membuat koneksi lebih awal dan mempertahankannya.
Untuk aplikasi Colorist Anda, penerapan streaming berarti pengguna akan melihat respons teks dan perubahan warna yang muncul lebih cepat, sehingga menciptakan pengalaman yang jauh lebih responsif.
Menambahkan pengelolaan status percakapan
Pertama, mari kita tambahkan penyedia status untuk melacak apakah aplikasi saat ini menangani respons streaming. Perbarui file lib/services/gemini_chat_service.dart
Anda:
lib/services/gemini_chat_service.dart
import 'dart:async';
import 'package:colorist_ui/colorist_ui.dart';
import 'package:firebase_ai/firebase_ai.dart';
import 'package:flutter_riverpod/legacy.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../providers/gemini.dart';
import 'gemini_tools.dart';
part 'gemini_chat_service.g.dart';
final conversationStateProvider = StateProvider( // Add from here...
(ref) => ConversationState.idle,
); // To here.
class GeminiChatService {
GeminiChatService(this.ref);
final Ref ref;
Future<void> sendMessage(String message) async {
final chatSession = await ref.read(chatSessionProvider.future);
final conversationState = ref.read(conversationStateProvider); // Add this line
final chatStateNotifier = ref.read(chatStateProvider.notifier);
final logStateNotifier = ref.read(logStateProvider.notifier);
if (conversationState == ConversationState.busy) { // Add from here...
logStateNotifier.logWarning(
"Can't send a message while a conversation is in progress",
);
throw Exception(
"Can't send a message while a conversation is in progress",
);
}
final conversationStateNotifier = ref.read(
conversationStateProvider.notifier,
);
conversationStateNotifier.state = ConversationState.busy; // To here.
chatStateNotifier.addUserMessage(message);
logStateNotifier.logUserText(message);
final llmMessage = chatStateNotifier.createLlmMessage();
try { // Modify from here...
final responseStream = chatSession.sendMessageStream(
Content.text(message),
);
await for (final block in responseStream) {
await _processBlock(block, llmMessage.id);
} // To here.
} catch (e, st) {
logStateNotifier.logError(e, st: st);
chatStateNotifier.appendToMessage(
llmMessage.id,
"\nI'm sorry, I encountered an error processing your request. "
"Please try again.",
);
} finally {
chatStateNotifier.finalizeMessage(llmMessage.id);
conversationStateNotifier.state = ConversationState.idle; // Add this line.
}
}
Future<void> _processBlock( // Add from here...
GenerateContentResponse block,
String llmMessageId,
) async {
final chatSession = await ref.read(chatSessionProvider.future);
final chatStateNotifier = ref.read(chatStateProvider.notifier);
final logStateNotifier = ref.read(logStateProvider.notifier);
final blockText = block.text;
if (blockText != null) {
logStateNotifier.logLlmText(blockText);
chatStateNotifier.appendToMessage(llmMessageId, blockText);
}
if (block.functionCalls.isNotEmpty) {
final geminiTools = ref.read(geminiToolsProvider);
final responseStream = chatSession.sendMessageStream(
Content.functionResponses([
for (final functionCall in block.functionCalls)
FunctionResponse(
functionCall.name,
geminiTools.handleFunctionCall(
functionCall.name,
functionCall.args,
),
),
]),
);
await for (final response in responseStream) {
final responseText = response.text;
if (responseText != null) {
logStateNotifier.logLlmText(responseText);
chatStateNotifier.appendToMessage(llmMessageId, responseText);
}
}
}
} // To here.
}
@riverpod
GeminiChatService geminiChatService(Ref ref) => GeminiChatService(ref);
Memahami penerapan streaming
Mari kita uraikan fungsi kode ini:
- Pelacakan status percakapan:
conversationStateProvider
melacak apakah aplikasi saat ini sedang memproses respons- Status bertransisi dari
idle
→busy
saat diproses, lalu kembali keidle
- Hal ini mencegah beberapa permintaan serentak yang dapat menimbulkan konflik
- Inisialisasi streaming:
sendMessageStream()
menampilkan Stream potongan respons, bukanFuture
dengan respons lengkap- Setiap bagian dapat berisi teks, panggilan fungsi, atau keduanya
- Pemrosesan progresif:
await for
memproses setiap potongan saat tiba secara real-time- Teks ditambahkan ke UI secara langsung, sehingga menciptakan efek streaming
- Panggilan fungsi akan dieksekusi segera setelah terdeteksi
- Penanganan panggilan fungsi:
- Saat panggilan fungsi terdeteksi dalam chunk, panggilan tersebut akan segera dieksekusi
- Hasil dikirim kembali ke LLM melalui panggilan streaming lain
- Respons LLM terhadap hasil ini juga diproses secara streaming
- Penanganan error dan pembersihan:
try
/catch
menyediakan penanganan error yang andal- Blok
finally
memastikan status percakapan direset dengan benar - Pesan selalu diselesaikan, meskipun terjadi error
Implementasi ini menciptakan pengalaman streaming yang responsif dan andal sekaligus mempertahankan status percakapan yang tepat.
Memperbarui layar utama untuk menghubungkan status percakapan
Ubah file lib/main.dart
untuk meneruskan status percakapan ke layar utama:
lib/main.dart
import 'package:colorist_ui/colorist_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'providers/gemini.dart';
import 'services/gemini_chat_service.dart';
void main() async {
runApp(ProviderScope(child: MainApp()));
}
class MainApp extends ConsumerWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final model = ref.watch(geminiModelProvider);
final conversationState = ref.watch(conversationStateProvider); // Add this line
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: model.when(
data: (data) => MainScreen(
conversationState: conversationState, // And this line
sendMessage: (text) {
ref.read(geminiChatServiceProvider).sendMessage(text);
},
),
loading: () => LoadingScreen(message: 'Initializing Gemini Model'),
error: (err, st) => ErrorScreen(error: err),
),
);
}
}
Perubahan utama di sini adalah meneruskan conversationState
ke widget MainScreen
. MainScreen
(disediakan oleh paket colorist_ui
) akan menggunakan status ini untuk menonaktifkan input teks saat respons sedang diproses.
Hal ini menciptakan pengalaman pengguna yang kohesif di mana UI mencerminkan status percakapan saat ini.
Membuat kode Riverpod
Jalankan perintah build runner untuk membuat kode Riverpod yang diperlukan:
dart run build_runner build --delete-conflicting-outputs
Menjalankan dan menguji respons streaming
Jalankan aplikasi Anda:
flutter run -d DEVICE
Sekarang coba uji perilaku streaming dengan berbagai deskripsi warna. Coba deskripsi seperti:
- "Show me the deep teal color of the ocean at twilight" (Tampilkan warna biru kehijauan laut saat senja)
- "Saya ingin melihat karang cerah yang mengingatkan saya pada bunga tropis"
- "Buat warna hijau zaitun redup seperti seragam tentara lama"
Alur teknis streaming secara mendetail
Mari kita periksa apa yang sebenarnya terjadi saat melakukan streaming respons:
Pembuatan koneksi
Saat Anda memanggil sendMessageStream()
, hal berikut akan terjadi:
- Aplikasi membuat koneksi ke layanan Firebase AI Logic
- Permintaan pengguna dikirim ke layanan
- Server mulai memproses permintaan
- Koneksi streaming tetap terbuka, siap mengirimkan potongan
Transmisi bagian
Saat Gemini membuat konten, potongan konten dikirim melalui aliran:
- Server mengirimkan potongan teks saat dibuat (biasanya beberapa kata atau kalimat)
- Saat memutuskan untuk melakukan panggilan fungsi, Gemini akan mengirimkan informasi panggilan fungsi
- Chunk teks tambahan dapat mengikuti panggilan fungsi
- Streaming berlanjut hingga pembuatan selesai
Pemrosesan progresif
Aplikasi Anda memproses setiap bagian secara inkremental:
- Setiap bagian teks ditambahkan ke respons yang ada
- Panggilan fungsi akan dieksekusi segera setelah terdeteksi
- UI diperbarui secara real-time dengan hasil teks dan fungsi
- Status dilacak untuk menunjukkan bahwa respons masih di-streaming
Penyelesaian streaming
Setelah pembuatan selesai:
- Aliran ditutup oleh server
- Loop
await for
Anda keluar secara alami - Pesan ditandai sebagai selesai
- Status percakapan disetel kembali ke tidak ada aktivitas
- UI diperbarui untuk mencerminkan status selesai
Perbandingan streaming vs. non-streaming
Untuk lebih memahami manfaat streaming, mari kita bandingkan pendekatan streaming vs. non-streaming:
Rasio | Non-Streaming | Streaming |
Latensi yang dirasakan | Pengguna tidak melihat apa pun hingga respons lengkap siap | Pengguna melihat kata-kata pertama dalam milidetik |
Pengalaman pengguna | Penantian lama yang diikuti dengan kemunculan teks secara tiba-tiba | Tampilan teks yang alami dan progresif |
Pengelolaan status | Lebih sederhana (pesan tertunda atau selesai) | Lebih kompleks (pesan dapat dalam status streaming) |
Eksekusi fungsi | Hanya terjadi setelah respons lengkap | Terjadi selama pembuatan respons |
Kompleksitas penerapan | Lebih mudah diterapkan | Memerlukan pengelolaan status tambahan |
Pemulihan dari error | Respons semua atau tidak sama sekali | Respons sebagian mungkin masih berguna |
Kompleksitas kode | Tidak terlalu rumit | Lebih kompleks karena penanganan streaming |
Untuk aplikasi seperti Colorist, manfaat UX dari streaming lebih besar daripada kompleksitas penerapan, terutama untuk interpretasi warna yang mungkin memerlukan waktu beberapa detik untuk dibuat.
Praktik terbaik untuk UX streaming
Saat menerapkan streaming di aplikasi LLM Anda sendiri, pertimbangkan praktik terbaik berikut:
- Indikator visual yang jelas: Selalu berikan isyarat visual yang jelas yang membedakan pesan streaming vs. pesan lengkap
- Pemblokiran input: Menonaktifkan input pengguna selama streaming untuk mencegah beberapa permintaan yang tumpang-tindih
- Pemulihan error: Desain UI Anda untuk menangani pemulihan yang lancar jika streaming terganggu
- Transisi status: Memastikan transisi yang lancar antara status tidak ada aktivitas, streaming, dan selesai
- Visualisasi progres: Pertimbangkan animasi atau indikator halus yang menunjukkan pemrosesan aktif
- Opsi pembatalan: Dalam aplikasi lengkap, berikan cara bagi pengguna untuk membatalkan pembuatan yang sedang berlangsung
- Integrasi hasil fungsi: Desain UI Anda untuk menangani hasil fungsi yang muncul di tengah proses
- Pengoptimalan performa: Minimalkan pembangunan ulang UI selama pembaruan streaming cepat
Paket colorist_ui
menerapkan banyak praktik terbaik ini untuk Anda, tetapi ini merupakan pertimbangan penting untuk penerapan LLM streaming apa pun.
Apa langkah selanjutnya?
Pada langkah berikutnya, Anda akan menerapkan sinkronisasi LLM dengan memberi tahu Gemini saat pengguna memilih warna dari histori. Hal ini akan menciptakan pengalaman yang lebih kohesif di mana LLM mengetahui perubahan yang dimulai pengguna pada status aplikasi.
Pemecahan masalah
Masalah pemrosesan streaming
Jika Anda mengalami masalah dengan pemrosesan streaming:
- Gejala: Respons sebagian, teks hilang, atau penghentian streaming yang tiba-tiba
- Solusi: Periksa konektivitas jaringan dan pastikan pola async/await yang tepat dalam kode Anda
- Diagnosis: Periksa panel log untuk melihat pesan error atau peringatan terkait pemrosesan streaming
- Perbaikan: Pastikan semua pemrosesan streaming menggunakan penanganan error yang tepat dengan blok
try
/catch
Panggilan fungsi yang tidak ada
Jika panggilan fungsi tidak terdeteksi dalam aliran data:
- Gejala: Teks muncul, tetapi warna tidak diperbarui, atau log tidak menampilkan panggilan fungsi
- Solusi: Verifikasi petunjuk perintah sistem tentang penggunaan panggilan fungsi
- Diagnosis: Periksa panel log untuk melihat apakah panggilan fungsi diterima
- Perbaikan: Sesuaikan perintah sistem Anda untuk menginstruksikan LLM secara lebih eksplisit agar menggunakan alat
set_color
Penanganan error umum
Untuk masalah lainnya:
- Langkah 1: Periksa panel log untuk melihat pesan error
- Langkah 2: Verifikasi konektivitas Firebase AI Logic
- Langkah 3: Pastikan semua kode yang dibuat Riverpod sudah terbaru
- Langkah 4: Tinjau penerapan streaming untuk menemukan pernyataan tunggu yang tidak ada
Konsep utama yang dipelajari
- Menerapkan respons streaming dengan Gemini API untuk UX yang lebih responsif
- Mengelola status percakapan untuk menangani interaksi streaming dengan benar
- Memproses teks real-time dan panggilan fungsi saat tiba
- Membuat UI responsif yang diperbarui secara bertahap selama streaming
- Menangani streaming serentak dengan pola asinkron yang tepat
- Memberikan respons visual yang sesuai selama respons streaming
Dengan menerapkan streaming, Anda telah meningkatkan pengalaman pengguna aplikasi Colorist secara signifikan, sehingga menciptakan antarmuka yang lebih responsif dan menarik yang terasa benar-benar seperti percakapan.
8. Sinkronisasi Konteks LLM
Pada langkah bonus ini, Anda akan mengimplementasikan Sinkronisasi Konteks LLM dengan memberi tahu Gemini saat pengguna memilih warna dari histori. Hal ini menciptakan pengalaman yang lebih kohesif di mana LLM menyadari tindakan pengguna di antarmuka, bukan hanya pesan eksplisit mereka.
Yang akan Anda bahas dalam langkah ini
- Membuat Sinkronisasi Konteks LLM antara UI dan LLM Anda
- Menyerialkan peristiwa UI ke dalam konteks yang dapat dipahami LLM
- Memperbarui konteks percakapan berdasarkan tindakan pengguna
- Menciptakan pengalaman yang koheren di berbagai metode interaksi
- Meningkatkan kesadaran konteks LLM di luar pesan chat eksplisit
Memahami Sinkronisasi Konteks LLM
Chatbot tradisional hanya merespons pesan pengguna yang eksplisit, sehingga menciptakan ketidakselarasan saat pengguna berinteraksi dengan aplikasi melalui cara lain. Sinkronisasi Konteks LLM mengatasi batasan ini:
Alasan pentingnya Sinkronisasi Konteks LLM
Saat pengguna berinteraksi dengan aplikasi Anda melalui elemen UI (seperti memilih warna dari histori), LLM tidak dapat mengetahui apa yang terjadi kecuali Anda memberitahunya secara eksplisit. Sinkronisasi Konteks LLM:
- Mempertahankan konteks: Terus memberi tahu LLM tentang semua tindakan pengguna yang relevan
- Menciptakan koherensi: Menghasilkan pengalaman yang kohesif saat LLM mengakui interaksi UI
- Meningkatkan kecerdasan: Memungkinkan LLM merespons semua tindakan pengguna dengan tepat
- Meningkatkan pengalaman pengguna: Membuat seluruh aplikasi terasa lebih terintegrasi dan responsif
- Mengurangi upaya pengguna: Menghilangkan kebutuhan pengguna untuk menjelaskan tindakan UI mereka secara manual
Di aplikasi Colorist, saat pengguna memilih warna dari histori, Anda ingin Gemini mengonfirmasi tindakan ini dan memberikan komentar cerdas tentang warna yang dipilih, sehingga mempertahankan ilusi asisten yang lancar dan sadar.
Memperbarui layanan chat Gemini untuk notifikasi pemilihan warna
Pertama, Anda akan menambahkan metode ke GeminiChatService
untuk memberi tahu LLM saat pengguna memilih warna dari histori. Perbarui file lib/services/gemini_chat_service.dart
Anda:
lib/services/gemini_chat_service.dart
import 'dart:async';
import 'dart:convert'; // Add this import
import 'package:colorist_ui/colorist_ui.dart';
import 'package:firebase_ai/firebase_ai.dart';
import 'package:flutter_riverpod/legacy.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../providers/gemini.dart';
import 'gemini_tools.dart';
part 'gemini_chat_service.g.dart';
final conversationStateProvider = StateProvider(
(ref) => ConversationState.idle,
);
class GeminiChatService {
GeminiChatService(this.ref);
final Ref ref;
Future<void> notifyColorSelection(ColorData color) => sendMessage( // Add from here...
'User selected color from history: ${json.encode(color.toLLMContextMap())}',
); // To here.
Future<void> sendMessage(String message) async {
final chatSession = await ref.read(chatSessionProvider.future);
final conversationState = ref.read(conversationStateProvider);
final chatStateNotifier = ref.read(chatStateProvider.notifier);
final logStateNotifier = ref.read(logStateProvider.notifier);
if (conversationState == ConversationState.busy) {
logStateNotifier.logWarning(
"Can't send a message while a conversation is in progress",
);
throw Exception(
"Can't send a message while a conversation is in progress",
);
}
final conversationStateNotifier = ref.read(
conversationStateProvider.notifier,
);
conversationStateNotifier.state = ConversationState.busy;
chatStateNotifier.addUserMessage(message);
logStateNotifier.logUserText(message);
final llmMessage = chatStateNotifier.createLlmMessage();
try {
final responseStream = chatSession.sendMessageStream(
Content.text(message),
);
await for (final block in responseStream) {
await _processBlock(block, llmMessage.id);
}
} catch (e, st) {
logStateNotifier.logError(e, st: st);
chatStateNotifier.appendToMessage(
llmMessage.id,
"\nI'm sorry, I encountered an error processing your request. "
"Please try again.",
);
} finally {
chatStateNotifier.finalizeMessage(llmMessage.id);
conversationStateNotifier.state = ConversationState.idle;
}
}
Future<void> _processBlock(
GenerateContentResponse block,
String llmMessageId,
) async {
final chatSession = await ref.read(chatSessionProvider.future);
final chatStateNotifier = ref.read(chatStateProvider.notifier);
final logStateNotifier = ref.read(logStateProvider.notifier);
final blockText = block.text;
if (blockText != null) {
logStateNotifier.logLlmText(blockText);
chatStateNotifier.appendToMessage(llmMessageId, blockText);
}
if (block.functionCalls.isNotEmpty) {
final geminiTools = ref.read(geminiToolsProvider);
final responseStream = chatSession.sendMessageStream(
Content.functionResponses([
for (final functionCall in block.functionCalls)
FunctionResponse(
functionCall.name,
geminiTools.handleFunctionCall(
functionCall.name,
functionCall.args,
),
),
]),
);
await for (final response in responseStream) {
final responseText = response.text;
if (responseText != null) {
logStateNotifier.logLlmText(responseText);
chatStateNotifier.appendToMessage(llmMessageId, responseText);
}
}
}
}
}
@riverpod
GeminiChatService geminiChatService(Ref ref) => GeminiChatService(ref);
Penambahan utama adalah metode notifyColorSelection
, yang:
- Mengambil objek
ColorData
yang mewakili warna yang dipilih - Mengenkodenya ke format JSON yang dapat disertakan dalam pesan
- Mengirim pesan berformat khusus ke LLM yang menunjukkan pilihan pengguna
- Menggunakan kembali metode
sendMessage
yang ada untuk menangani notifikasi
Pendekatan ini menghindari duplikasi dengan memanfaatkan infrastruktur penanganan pesan yang sudah ada.
Memperbarui aplikasi utama untuk menghubungkan notifikasi pilihan warna
Sekarang, ubah file lib/main.dart
Anda untuk meneruskan fungsi notifikasi pemilihan warna ke layar utama:
lib/main.dart
import 'package:colorist_ui/colorist_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'providers/gemini.dart';
import 'services/gemini_chat_service.dart';
void main() async {
runApp(ProviderScope(child: MainApp()));
}
class MainApp extends ConsumerWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final model = ref.watch(geminiModelProvider);
final conversationState = ref.watch(conversationStateProvider);
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: model.when(
data: (data) => MainScreen(
conversationState: conversationState,
notifyColorSelection: (color) { // Add from here...
ref.read(geminiChatServiceProvider).notifyColorSelection(color);
}, // To here.
sendMessage: (text) {
ref.read(geminiChatServiceProvider).sendMessage(text);
},
),
loading: () => LoadingScreen(message: 'Initializing Gemini Model'),
error: (err, st) => ErrorScreen(error: err),
),
);
}
}
Perubahan utamanya adalah menambahkan callback notifyColorSelection
, yang menghubungkan peristiwa UI (memilih warna dari histori) ke sistem notifikasi LLM.
Memperbarui perintah sistem
Sekarang, Anda perlu memperbarui perintah sistem untuk menginstruksikan LLM tentang cara merespons notifikasi pemilihan warna. Ubah file assets/system_prompt.md
Anda:
assets/system_prompt.md
# Colorist System Prompt
You are a color expert assistant integrated into a desktop app called Colorist. Your job is to interpret natural language color descriptions and set the appropriate color values using a specialized tool.
## Your Capabilities
You are knowledgeable about colors, color theory, and how to translate natural language descriptions into specific RGB values. You have access to the following tool:
`set_color` - Sets the RGB values for the color display based on a description
## How to Respond to User Inputs
When users describe a color:
1. First, acknowledge their color description with a brief, friendly response
2. Interpret what RGB values would best represent that color description
3. Use the `set_color` tool to set those values (all values should be between 0.0 and 1.0)
4. After setting the color, provide a brief explanation of your interpretation
Example:
User: "I want a sunset orange"
You: "Sunset orange is a warm, vibrant color that captures the golden-red hues of the setting sun. It combines a strong red component with moderate orange tones."
[Then you would call the set_color tool with approximately: red=1.0, green=0.5, blue=0.25]
After the tool call: "I've set a warm orange with strong red, moderate green, and minimal blue components that is reminiscent of the sun low on the horizon."
## When Descriptions are Unclear
If a color description is ambiguous or unclear, please ask the user clarifying questions, one at a time.
## When Users Select Historical Colors
Sometimes, the user will manually select a color from the history panel. When this happens, you'll receive a notification about this selection that includes details about the color. Acknowledge this selection with a brief response that recognizes what they've done and comments on the selected color.
Example notification:
User: "User selected color from history: {red: 0.2, green: 0.5, blue: 0.8, hexCode: #3380CC}"
You: "I see you've selected an ocean blue from your history. This tranquil blue with a moderate intensity has a calming, professional quality to it. Would you like to explore similar shades or create a contrasting color?"
## Important Guidelines
- Always keep RGB values between 0.0 and 1.0
- Provide thoughtful, knowledgeable responses about colors
- When possible, include color psychology, associations, or interesting facts about colors
- Be conversational and engaging in your responses
- Focus on being helpful and accurate with your color interpretations
Penambahan utama adalah bagian "Saat Pengguna Memilih Warna Historis", yang:
- Menjelaskan konsep notifikasi pemilihan histori kepada LLM
- Memberikan contoh tampilan notifikasi ini
- Menampilkan contoh respons yang sesuai
- Menetapkan ekspektasi untuk mengonfirmasi pilihan dan mengomentari warna
Hal ini membantu LLM memahami cara merespons pesan khusus ini dengan tepat.
Membuat Kode Riverpod
Jalankan perintah build runner untuk membuat kode Riverpod yang diperlukan:
dart run build_runner build --delete-conflicting-outputs
Menjalankan dan menguji Sinkronisasi Konteks LLM
Jalankan aplikasi Anda:
flutter run -d DEVICE
Pengujian Sinkronisasi Konteks LLM melibatkan:
- Pertama, buat beberapa warna dengan mendeskripsikannya di chat
- "Show me a vibrant purple" (Tampilkan warna ungu cerah)
- "Saya ingin warna hijau hutan"
- "Give me a bright red" (Beri saya warna merah cerah)
- Kemudian, klik salah satu thumbnail warna di deretan histori
Anda akan melihat:
- Warna yang dipilih akan muncul di layar utama
- Pesan pengguna akan muncul di chat yang menunjukkan pilihan warna
- LLM merespons dengan mengonfirmasi pilihan dan mengomentari warna
- Seluruh interaksi terasa alami dan kohesif
Hal ini menciptakan pengalaman yang lancar di mana LLM mengetahui dan merespons dengan tepat pesan langsung dan interaksi UI.
Cara kerja Sinkronisasi Konteks LLM
Mari kita pelajari detail teknis cara kerja sinkronisasi ini:
Aliran Data
- Tindakan pengguna: Pengguna mengklik warna di deretan histori
- Peristiwa UI: Widget
MainScreen
mendeteksi pilihan ini - Eksekusi callback: Callback
notifyColorSelection
dipicu - Pembuatan pesan: Pesan berformat khusus dibuat dengan data warna
- Pemrosesan LLM: Pesan dikirim ke Gemini, yang mengenali formatnya
- Respons kontekstual: Gemini merespons dengan tepat berdasarkan perintah sistem
- Pembaruan UI: Respons muncul dalam chat, sehingga menciptakan pengalaman yang kohesif
Serialisasi data
Aspek utama dari pendekatan ini adalah cara Anda melakukan serialisasi data warna:
'User selected color from history: ${json.encode(color.toLLMContextMap())}'
Metode toLLMContextMap()
(disediakan oleh paket colorist_ui
) mengonversi objek ColorData
menjadi peta dengan properti utama yang dapat dipahami LLM. Hal ini biasanya mencakup:
- Nilai RGB (merah, hijau, biru)
- Representasi kode hex
- Nama atau deskripsi apa pun yang terkait dengan warna
Dengan memformat data ini secara konsisten dan menyertakannya dalam pesan, Anda memastikan LLM memiliki semua informasi yang diperlukan untuk merespons dengan tepat.
Aplikasi yang lebih luas dari Sinkronisasi Konteks LLM
Pola pemberitahuan LLM tentang peristiwa UI ini memiliki banyak aplikasi di luar pemilihan warna:
Kasus penggunaan lainnya
- Perubahan filter: Memberi tahu LLM saat pengguna menerapkan filter ke data
- Peristiwa navigasi: Memberi tahu LLM saat pengguna membuka bagian yang berbeda
- Perubahan pilihan: Perbarui LLM saat pengguna memilih item dari daftar atau petak
- Pembaruan preferensi: Memberi tahu LLM saat pengguna mengubah setelan atau preferensi
- Manipulasi data: Memberi tahu LLM saat pengguna menambahkan, mengedit, atau menghapus data
Dalam setiap kasus, polanya tetap sama:
- Mendeteksi peristiwa UI
- Menserialkan data yang relevan
- Mengirim notifikasi berformat khusus ke LLM
- Mengarahkan LLM untuk merespons dengan tepat melalui perintah sistem
Praktik terbaik untuk Sinkronisasi Konteks LLM
Berdasarkan penerapan Anda, berikut beberapa praktik terbaik untuk Sinkronisasi Konteks LLM yang efektif:
1. Format yang konsisten
Gunakan format yang konsisten untuk notifikasi agar LLM dapat mengidentifikasinya dengan mudah:
"User [action] [object]: [structured data]"
2. Konteks lengkap
Sertakan detail yang cukup dalam notifikasi agar LLM dapat merespons dengan cerdas. Untuk warna, ini berarti nilai RGB, kode hex, dan properti relevan lainnya.
3. Petunjuk yang jelas
Berikan petunjuk yang jelas dalam perintah sistem tentang cara menangani notifikasi, sebaiknya dengan contoh.
4. Integrasi alami
Desain notifikasi agar mengalir secara alami dalam percakapan, bukan sebagai gangguan teknis.
5. Notifikasi selektif
Hanya beri tahu LLM tentang tindakan yang relevan dengan percakapan. Tidak semua peristiwa UI perlu dikomunikasikan.
Pemecahan masalah
Masalah notifikasi
Jika LLM tidak merespons pemilihan warna dengan benar:
- Pastikan format pesan notifikasi cocok dengan yang dijelaskan dalam perintah sistem
- Pastikan data warna diserialisasi dengan benar
- Pastikan perintah sistem memiliki petunjuk yang jelas untuk menangani pilihan
- Cari error apa pun di layanan chat saat mengirim notifikasi
Pengelolaan konteks
Jika LLM tampaknya kehilangan konteks:
- Pastikan sesi chat dipertahankan dengan benar
- Pastikan transisi status percakapan sudah benar
- Pastikan notifikasi dikirim melalui sesi chat yang sama
Masalah umum
Untuk masalah umum:
- Periksa error atau peringatan dalam log
- Memverifikasi konektivitas Firebase AI Logic
- Periksa apakah ada ketidakcocokan jenis dalam parameter fungsi
- Pastikan semua kode yang dihasilkan Riverpod sudah terbaru
Konsep utama yang dipelajari
- Membuat Sinkronisasi Konteks LLM antara UI dan LLM
- Menyerialkan peristiwa UI ke dalam konteks yang kompatibel dengan LLM
- Mengarahkan perilaku LLM untuk pola interaksi yang berbeda
- Menciptakan pengalaman yang kohesif di seluruh interaksi pesan dan non-pesan
- Meningkatkan pemahaman LLM tentang status aplikasi yang lebih luas
Dengan menerapkan Sinkronisasi Konteks LLM, Anda telah menciptakan pengalaman yang benar-benar terintegrasi di mana LLM terasa seperti asisten yang responsif dan sadar, bukan hanya generator teks. Pola ini dapat diterapkan ke banyak aplikasi lain untuk membuat antarmuka yang lebih alami dan intuitif yang didukung AI.
9. Selamat!
Anda berhasil menyelesaikan codelab Colorist. 🎉
Yang telah Anda bangun
Anda telah membuat aplikasi Flutter yang berfungsi penuh dan mengintegrasikan Gemini API Google untuk menafsirkan deskripsi warna dalam bahasa alami. Aplikasi Anda kini dapat:
- Memproses deskripsi bahasa alami seperti "oranye senja" atau "biru laut dalam"
- Menggunakan Gemini untuk menerjemahkan deskripsi ini secara cerdas ke dalam nilai RGB
- Menampilkan warna yang diinterpretasikan secara real-time dengan respons streaming
- Menangani interaksi pengguna melalui elemen chat dan UI
- Mempertahankan kesadaran kontekstual di berbagai metode interaksi
Tujuan berikutnya
Setelah Anda menguasai dasar-dasar mengintegrasikan Gemini dengan Flutter, berikut beberapa cara untuk melanjutkan perjalanan Anda:
Meningkatkan kualitas aplikasi Colorist Anda
- Palet warna: Menambahkan fungsi untuk membuat skema warna pelengkap atau yang cocok
- Input suara: Mengintegrasikan pengenalan ucapan untuk deskripsi warna verbal
- Pengelolaan histori: Menambahkan opsi untuk memberi nama, mengatur, dan mengekspor set warna
- Perintah kustom: Buat antarmuka bagi pengguna untuk menyesuaikan perintah sistem
- Analisis lanjutan: Melacak deskripsi mana yang paling efektif atau menyebabkan kesulitan
Menjelajahi fitur Gemini lainnya
- Input multimodal: Menambahkan input gambar untuk mengekstrak warna dari foto
- Pembuatan konten: Menggunakan Gemini untuk membuat konten terkait warna seperti deskripsi atau cerita
- Peningkatan panggilan fungsi: Buat integrasi alat yang lebih kompleks dengan beberapa fungsi
- Setelan keamanan: Jelajahi berbagai setelan keamanan dan dampaknya terhadap respons
Terapkan pola ini ke domain lain
- Analisis dokumen: Buat aplikasi yang dapat memahami dan menganalisis dokumen
- Bantuan penulisan kreatif: Buat alat penulisan dengan saran yang didukung LLM
- Otomatisasi tugas: Merancang aplikasi yang menerjemahkan bahasa alami menjadi tugas otomatis
- Aplikasi berbasis pengetahuan: Membuat sistem pakar di domain tertentu
Resource
Berikut beberapa referensi berharga untuk melanjutkan pembelajaran Anda:
Dokumentasi resmi
Kursus dan panduan penulisan perintah
Komunitas
Seri Observable Flutter Agentic
Dalam episode #59, Craig Labenz dan Andrew Brogden menjelajahi codelab ini, dengan menyoroti bagian-bagian menarik dari pembuatan aplikasi.
Dalam episode #60, bergabunglah kembali dengan Craig dan Andrew saat mereka memperluas aplikasi codelab dengan kemampuan baru dan berjuang untuk membuat LLM melakukan apa yang diperintahkan.
Dalam episode #61, Craig ditemani Chris Sells untuk menganalisis judul berita dan membuat gambar yang sesuai.
Masukan
Kami ingin mendengar pengalaman Anda dengan codelab ini. Harap pertimbangkan untuk memberikan masukan melalui:
Terima kasih telah menyelesaikan codelab ini, dan kami harap Anda terus menjelajahi berbagai kemungkinan menarik di persimpangan Flutter dan AI.