Aplikasi Cerdas

Membuka kemampuan agentic di aplikasi Anda dengan ML Kit GenAI

Speaker

Tentang

Tentang konferensi

Tingkatkan fitur AI Android Anda ke level berikutnya dengan membangun agen otonom di perangkat. Dalam sesi ini, kami akan membahas API agentic baru ML Kit, yang dibuat langsung di atas API akses model langsung yang sudah Anda ketahui.

Dengan menggunakan aplikasi Jetpacker open source, Anda akan mempelajari cara merangkai tindakan multi-langkah di seluruh data lokal, mengelola sesi multi-giliran stateful dengan konteks terisolasi, dan menghubungkan MCP Android untuk mendukung asisten dalam aplikasi dan platform tingkat sistem Android dengan satu codebase.

Ringkasan

  • Gemini Nano 4 mendukung Panggilan Fungsi secara native, sehingga model di perangkat dapat menerjemahkan bahasa alami menjadi tindakan dan menggerakkan API lokal.
  • Library AppFunctions Jetpack menentukan alat melalui deskripsi KDoc bahasa alami. Mengubah tingkat akses dapat mengekspos fungsi ini ke agen sistem seperti Gemini.
  • Library alur agentic baru (alfa) di ML Kit GenAI menyederhanakan pembuatan agen dengan menangani loop eksekusi dan panggilan alat.
  • AgentRunner mengoordinasikan eksekusi alat dan menyediakan metode sesi untuk percakapan multi-giliran tanpa kehilangan konteks.
  • Akses langsung melalui Prompt API tetap tersedia untuk kontrol histori sederhana atau penyiapan kompleks seperti sistem multi-agen dan hybrid.

Keahlian

Resource

Gemini Notebook

Topik

  • ml-kit
  • on-device-ai
  • gemini-nano
  • ai-agents
  • pemanggilan fungsi
  • app-functions
  • aicore

Transkrip

Pengantar AI di perangkat dan Gemini Nano

  • Nama saya Jolanda Verhoef.

  • Saya adalah Developer Relations Engineer di Android, dan hari ini, saya ditemani oleh Victoria Lestari, yang merupakan bagian dari tim engineering AICore.

  • Halo, semuanya.

  • Terima kasih telah bergabung bersama kami pagi ini.

  • Jadi, tim kami telah berkolaborasi erat selama bertahun-tahun untuk menghadirkan model AI tercanggih dari cloud dan menjalankannya langsung di perangkat Android.

  • Upaya ini dikelompokkan dalam suite GenAI ML Kit.

  • Di satu sisi, dalam rangkaian GenAI ML Kit ini, kami memiliki API tingkat tinggi untuk solusi siap pakai, seperti peringkasan teks, deskripsi gambar, dan pengenalan ucapan.

  • Di sisi lain, kami juga telah membuka akses langsung ke model di perangkat, Gemini Nano.

  • Dan hari ini, kami mengambil langkah ekstra.

  • Jadi, dengan akses langsung ini, kami akan memungkinkan Anda membangun agen dalam aplikasi, agen yang dapat menalar di beberapa giliran, yang dapat menyimpan konteks percakapan, dan yang dapat mengambil tindakan di aplikasi Anda.

  • Jadi, apa sebenarnya maksudnya, Victoria?

  • Ya.

  • Sejauh ini, saat membahas kasus penggunaan di perangkat, kita memikirkan tugas yang lebih singkat, lebih sederhana, dan terisolasi, seperti mendeteksi kemungkinan scam, atau meringkas panggilan telepon.

  • Dan saat kita ingin membangun sesuatu yang lebih kompleks, seperti mengajukan pertanyaan tentang katalog foto Anda, atau bertanya kepada Google Maps, kita tentu akan merujuk ke model cloud besar.

  • Jadi, model cloud memang menawarkan keunggulan pemrosesan yang sangat besar dan data real-time, tetapi AI di perangkat membuka kemungkinan baru untuk latensi rendah serta pemrosesan data real-time dan lokal.

  • Jadi, Gemini Nano telah memperluas hal yang dapat Anda lakukan di perangkat Anda.

  • Salah satu contohnya adalah Screenshot Pixel, yang memungkinkan Anda menelusuri screenshot lokal dan mengajukan pertanyaan tentang screenshot tersebut.

  • Jadi, saat kita menjalankan agen di perangkat, itu berarti kita memerlukan lompatan besar dalam kemampuan model, dan itulah alasan kami membangun Gemini Nano 4 yang mampu melakukan penalaran di berbagai langkah dan mengambil tindakan nyata.

  • Namun, kemampuan baru ini hanya penting jika developer memiliki perangkat sungguhan untuk ditargetkan.

  • Jadi, kabar baiknya adalah Gemini Nano 4 sudah tersedia di perangkat unggulan tertentu, dan Anda juga dapat mengujinya di lebih banyak perangkat menggunakan Pratinjau Developer AICore.

  • Kami juga sedang berupaya untuk mencapai 100 juta perangkat pada awal tahun depan.

  • Jadi, apa artinya?

  • Jadi, ini berarti Anda dapat mulai membangun dan menguji pengalaman ini sekarang, dengan mengetahui bahwa apa yang Anda bangun sekarang akan diskalakan ke audiens yang sangat besar.

  • Jadi, kita telah membahas Gemini Nano 4, kita telah membahas potensi jangkauannya, jadi sekarang, mari kita bahas apa yang sebenarnya dimaksud dengan kemampuan agentic.

  • Jadi, AI agentic mampu merencanakan tugas yang kompleks, memecah tugas ini menjadi beberapa langkah, lalu menjalankan langkah-langkah ini di seluruh aplikasi Anda.

  • Jadi, misalnya model Gemini Nano di perangkat, dapat mengkueri database lokal Anda, mengambil data dari backend, memberikan penalaran dan merespons pertanyaan kompleks Anda, serta memicu alur kerja aplikasi native di perangkat Anda.

  • Namun, bagaimana AI sebenarnya beralih dari membuat rencana ke mengambil tindakan nyata?

  • Dan inilah topik untuk hari ini, yaitu Pemanggilan Fungsi.

  • Ini adalah mesin inti dari kemampuan agentic.

  • Model ini menerjemahkan bahasa alami menjadi eksekusi sistem, dan mendorong model dari penalaran pasif menjadi eksekusi aktif dengan memilih dan mendorong API lokal yang diperlukan untuk menyelesaikan tugas yang kompleks.

  • Kami juga dengan senang hati mengumumkan bahwa Pemanggilan Fungsi didukung secara native di Gemini Nano 4.

  • Saat ini, fitur ini tersedia di Pratinjau Developer AICore dan akan segera diluncurkan ke semua perangkat yang didukung Nano 4.

  • Jadi, bagus sekali bahwa kita memiliki kemampuan seperti ini dalam model, tetapi kemampuan dalam model belum memberi Anda, sebagai developer, API.

  • Jadi, kami juga berupaya menambahkan API yang tepat ke suite GenAI ML Kit untuk memastikan bahwa pembuatan agen benar-benar menjadi mudah.

  • Jadi, kami memulai dengan API akses langsung yang sudah kami miliki, dan kami telah menambahkan jenis fungsi dan jenis histori percakapan ke dalamnya.

  • Dengan dua tambahan baru pada Prompt API ML Kit ini, Anda kini dapat membangun kemampuan agen tingkat rendah ini ke dalam aplikasi Anda.

  • Namun, ada banyak hal yang harus Anda lakukan sendiri pada tahap tersebut.

  • Jadi, Anda perlu menjalankan fungsi secara manual, menyimpan histori panggilan, dan melakukan loop sendiri pada beberapa panggilan.

  • Jadi, jika ada beberapa panggilan yang perlu Anda lakukan, Anda harus, misalnya, membangun semacam sistem pengulangan sendiri, dan Anda harus membangun guard rail sendiri untuk sistem tersebut.

  • Hal itu mungkin saja, tetapi, tentu saja, kita ingin membuatnya cepat dan mudah.

  • Jadi, selain library prompt API ini, kami juga telah menambahkan library alur agentic baru.

  • Anda dapat menemukannya dengan com.mlkit.genai:agent-api, dan saat ini tersedia dalam versi alfa.

  • Sekarang, dengan API baru ini, kami melakukan banyak pekerjaan berat untuk Anda.

  • Jadi, Anda tidak perlu melakukan banyak langkah manual, cukup dengan beberapa baris kode, Anda akan dapat membangun agen.

  • Dan itulah yang akan kita lakukan hari ini.

Demo agen Jetpacker dan panggilan fungsi

  • Jadi, kita akan melihat cara kerja API ini dengan aplikasi contoh kita, Jetpacker.

  • Anda telah melihat Jetpacker di Google I/O dan selama konferensi ini.

  • Namun, Anda dapat memindai kode QR ini, dan jika tertarik, Anda dapat melihat kodenya, mengarahkan agen ke kode tersebut, berinteraksi dengan kode tersebut, dan mempelajari lebih lanjut cara kami menerapkan semua fitur ini.

  • Jetpacker adalah asisten perjalanan modern yang kami buat untuk menampilkan berbagai fitur cerdas.

  • Jadi, aplikasi ini sudah menggunakan model di perangkat dan model cloud untuk semua jenis API perintah, tetapi yang akan kita bangun sekarang adalah menambahkan agen ke dalamnya.

  • Untuk agen Jetpacker ini, kita akan menggunakan API agen GenAI ML Kit baru yang baru saja kita bahas, dan API tersebut akan menggunakan sistem AI Core yang berjalan di perangkat Android untuk berkomunikasi dengan model Gemini Nano.

  • Sekarang, saya bisa berbicara sepuasnya, dan kita akan banyak membahasnya, tetapi, tentu saja, kami ingin mendemonstrasikannya.

  • Jadi, mari kita beralih ke ponsel, dan mari kita tunjukkan ini sebagai demo.

  • Saya punya Pixel 11 Pro di sini.

  • Dan saya rasa kita bisa beralih ke Pro, dan Anda seharusnya bisa melihatnya.

  • Nah, ini dia.

  • Seperti yang Anda lihat, aplikasi Jetpacker berjalan di sini.

  • Ada banyak perjalanan kami yang akan datang, dan saya dapat melihat perjalanan kami saat ini, dan dalam perjalanan kami saat ini, Anda dapat melihat bahwa saat ini tanggal 29 Oktober, jadi kami memiliki workshop AI di perangkat, demo showcase, dan besok saya memiliki Golden Gate Bay Cruise, dan saya akan mengunjungi museum.

  • Semua itu bagus.

  • Sekarang, kita dapat membuka layar pengeluaran tempat kita melacak anggaran perjalanan ini.

  • Seperti yang Anda lihat di kanan bawah, ada ikon kilauan agentic kecil baru, dan itulah agen di perangkat yang telah kami buat.

  • Jadi, mari kita mulai dengan perintah yang cukup sederhana.

  • Sepertinya kita bisa memintanya untuk menambahkan pengeluaran tertentu.

  • Jadi, misalnya: tambahkan pengeluaran untuk taksi ke Mountain View, dan biayanya $45.

  • Ini dia.

  • Sistem sedang menyiapkan pengeluaran, dan menambahkan pengeluaran.

  • Luar biasa.

  • Oke, demo 1 berhasil.

  • Mari kita kembali ke slide dan melihat cara kerjanya.

  • Oke, jadi pertama-tama, seperti yang Anda perhatikan, saya menggunakan suara saya, dan suara itu sebenarnya juga menggunakan model Gemini Nano menggunakan API pengenalan ucapan untuk mentranskripsikan apa pun yang saya katakan menjadi teks.

  • Teks tersebut sudah bagus, dan kita dapat mengirimkannya ke model Gemini Nano.

  • Namun, apa yang akan dilakukannya?

  • Misalnya, saya memintanya untuk menambahkan sesuatu ke pengeluaran, saya memberitahunya sesuatu tentang $45, tetapi model tidak benar-benar tahu cara bertindak, bukan?

  • Pada tahap ini, agen hanya akan memberi tahu saya, "Saya tidak tahu apa yang Anda bicarakan".

  • Jadi, kita ingin menambahkan sedikit informasi ke perintah tersebut.

  • Kita dapat menambahkan alat ke perintah, jadi kita dapat menambahkan berbagai jenis alat, dalam hal ini, saya menambahkan mendapatkan anggaran perjalanan, itinerari, dll. Dan jika Anda meneruskan ini ke model Nano dengan API kami, model tersebut akan otomatis memahami bahwa alih-alih menampilkan teks, model tersebut kini dapat menampilkan panggilan fungsi.

  • Jadi, dalam kasus kita, model ini akan mengatakan, "Daripada merespons dengan teks, saya akan menambahkan pengeluaran sebesar $45 untuk taksi ke Mountain View."

  • Bagus, tetapi, Victoria, bagaimana cara kerjanya?

  • Bagaimana cara membangunnya?

  • Ya.

  • Jadi, bagaimana cara menentukan alat dalam kode kita?

  • Jadi, inilah yang akan saya jelaskan.

  • Jadi, dengan MCP Android, kita menggunakan library AppFunctions Jetpack untuk menentukan dan memublikasikan alat ini.

  • Jadi, library AppFunctions dapat mengekspos layanan, data, dan tindakan aplikasi Anda ke registry Android OS sehingga kita dapat menggunakan kembali fungsi yang sama persis untuk mendeklarasikan dan mendeskripsikan alat dan menggunakannya di seluruh aplikasi Anda.

  • Hal ini juga memungkinkan pengguna menyelesaikan tugas ini melalui agen dan interaksi tingkat sistem.

  • Jadi, saya akan memberikan contoh konkret dalam kode.

    /**
     * Adds an expense to a trip.
     *
     * @param tripId Identifier of the trip (e.g., "paris-2026").
     * @param amount Expense amount in dollars.
     * @param description Short description of what the expense was for.
     */
    @AppFunctionDeclaration(isDescribedByKDoc = true)
    @AppFunctionAccessLevel(
      level = ACCESS_LEVEL_SELF,
      isCompatEnforcementEnabled = true,
    )
    suspend fun addExpense(tripId: String, amount: Double, description: String) {
      // Save expense to local DB / repository...
    }
  • Jadi, Anda dapat melihat bahwa ini adalah contoh AppFunctionDeclaration.

  • Anda dapat melihat bahwa komentar KDoc di atas menjelaskan fungsi dan parameternya, semuanya dalam bahasa alami.

  • Jadi, praktik terbaiknya adalah memberikan deskripsi sejelas mungkin karena kita akan mengirimkannya ke model.

  • Kemudian, Anda dapat melihat di bawahnya, ada anotasi, @AppFunctionAccessLevel.

  • Jadi, ini akan mencakup visibilitas fungsi.

  • Dalam contoh ini, kita memiliki ACCESS_LEVEL_SELF, yang berarti bahwa fungsi yang kita tulis ini hanya dapat dilihat oleh aplikasi Anda, agen aplikasi Anda.

  • Kemudian, kita dapat menentukan dan mengimplementasikan fungsi penangguhan itu sendiri, dan kita dapat menulis sebanyak mungkin fungsi aplikasi dan mengelompokkan semuanya ke dalam satu class layanan.

Membangun dan mengimplementasikan runner agen AI

  • Oke.

  • Jadi, kita memiliki alat dan kita dapat menulis alat tersebut, itu bagus.

  • Namun, tentu saja untuk membangun agen, kita memerlukan lebih dari sekadar AppFunctions tersebut.

  • Jadi, ada tiga jenis bagian lagi yang penting untuk diketahui saat Anda menulis agen.

  • Pertama-tama, kita akan menentukan agennya.

  • Jadi, kita menentukan petunjuk sistem, menentukan guardrail, konfigurasi, dan cara menggunakannya.

  • Lalu, kita juga memiliki AgentRunner.

  • AgentRunner adalah hal yang menjalankan agen untuk kita.

  • Jadi, ini akan menangani mekanisme pengulangan yang kita bicarakan.

  • Terakhir, ada AgentEvents, yang merupakan cara bagi sistem, untuk API, memberi tahu kita apa yang sebenarnya sedang dilakukan.

  • Jadi, model akan memberi tahu kita saat menampilkan teks, saat melakukan panggilan alat, dll., sehingga kita dapat menampilkannya di UI.

  • Oke.

  • Jadi, mari kita lihat kode yang sebenarnya.

  • Oke.

  • Sebelum melanjutkan penulisan kode, kita perlu memeriksa terlebih dahulu apakah Pemanggilan Fungsi tersedia di perangkat Anda, karena Pemanggilan Fungsi hanya didukung di Gemini Nano 4.

    val model = Generation.getClient()
    val features = model.getAvailableFeatures()
    if(FUNCTION_CALLING in features) {
      // Device is supported!
    } else {
      // Graceful fallback
    }
  • Pertama, kita perlu memeriksa dengan memanggil model generatif getAvailableFeatures.

  • Kita cukup memeriksa apakah pemanggilan fungsi tercantum dalam fitur.

  • Jika tidak, kita dapat menerapkan penggantian yang halus.

  • Oke.

  • Sekarang, mari kita pelajari kodenya.

    if(FUNCTION_CALLING in features) {
      // 1. Build the agent configuration
      val agent = Agent.builder()
        .setName("Assistant")
        .setInstructions("You are a helpful on-device assistant.")
        .enableAppFunctions()
        .build()
    
      // 2. Initialize the runner
      val runner = AgentRunner(agent = agent)
    
      // 3. Create your prompt
      val prompt = content { text(userPrompt)}
    
      // 4. Start the agent
      runner.runSingleTurnAsync(prompt).textTokens().collect { responseMessage += it }
    
    }
  • Kita tahu bahwa Pemanggilan Fungsi didukung di perangkat kita, lalu kita bisa mulai membuat agen menggunakan Agent.builder.

  • Lalu, kita dapat menetapkan namanya.

  • Kita dapat setInstructions untuk menentukan konteks dan persona.

  • Terakhir, kita panggil enableAppFunctions.

  • Jadi, fungsi ini akan melakukan loop dan secara otomatis menemukan semua AppFunction yang baru saja kita cantumkan sebelumnya dan kita baru saja membangun agen.

  • Selanjutnya, kita perlu melakukan inisialisasi AgentRunner.

  • Jadi, runner agen ini akan mengelola loop eksekusi untuk kita.

  • Kita cukup memanggilnya dengan memanggil instruktur, constra-- konstruktor dan meneruskan agen ke dalamnya.

  • Terakhir, kita dapat menggabungkan perintah suara yang ditranskripsikan dalam blok konten untuk membuat perintah.

  • Lalu, kita panggil runner.

  • Kita memanggil fungsi runSingleTurnAsync ini pada perintah, dan ini akan memulai agen, menjalankan inferensi, dan melakukan seluruh inferensi AI.

  • Dan jika kita hanya ingin men-streaming balasan teks akhir model ke UI, kita cukup memanggil textTokens, dan model akan mengumpulkan respons saat respons tersebut tiba.

  • Jadi, itulah.

  • Itu memang hanya beberapa baris kode, jadi kami tidak bercanda saat mengatakannya.

  • Jadi, hanya dengan beberapa baris kode ini, Anda sudah memiliki agen.

  • Agen tersebut akan melakukan apa yang Anda inginkan.

  • Model ini akan memberikan-- memberikan respons teks kepada kita.

  • Namun, tentu saja dalam demo pertama yang kami tunjukkan, kami hanya melakukan perintah yang sangat sederhana, bukan?

  • Seperti saya melakukan satu perintah dan perintah itu memberikan satu tindakan dan selesai, jadi ini belum benar-benar menjadi agen yang lengkap, bukan?

  • Jadi, mari kita buat sedikit lebih menarik.

  • Untuk bagian berikutnya, saya ingin memberikan perintah, tetapi saya ingin membuatnya sedikit lebih sulit bagi agen.

Arsitektur dan eksekusi agen multilangkah

  • Jadi, mari kita kembali ke perangkat demo saya, dan mari kita lihat apakah kita bisa membuatnya sedikit lebih sulit.

  • Kita sudah sampai.

  • Luar biasa.

  • Jadi, seperti yang saya katakan, kita punya rencana kunjungan ke museum untuk besok.

  • Dan untuk kunjungan museum tersebut, Anda dapat melihat bahwa jika saya membukanya, harga tiket masuknya adalah $25.

  • Sekarang, mari kita lihat apakah agen kita benar-benar mampu mengetahuinya sendiri.

  • Jadi, saya akan kembali ke layar pengeluaran dan memberikan perintah, "Tambahkan tiket museum ke pengeluaran saya".

  • Ini dia.

  • Dan sekarang, seperti yang Anda lihat, Gemini memeriksa itinerari saya, menemukan kunjungan museum, dan menambahkannya ke pengeluaran saya.

  • Jadi, di sini diperlukan tiga langkah untuk benar-benar mencapai sasarannya dan juga memberi saya respons teks akhir.

  • Sekali lagi, semua ini berfungsi secara otomatis.

  • Anda telah melihat kecepatan sebenarnya dari model tersebut di perangkat.

  • Jadi, mari kita kembali ke slide dan melihat cara kerjanya.

  • Jadi, seperti yang Anda lihat, kami telah sedikit mengubah beberapa hal dibandingkan dengan demo pertama kami.

  • Dalam kasus ini, seperti yang Anda lihat, saya tidak memberi tahu model tentang museum, saya tidak memberi tahu model tentang pengeluaran, sehingga, saat model mendapatkan perintah dan alat, model mencoba memutuskan apa yang harus dilakukan terlebih dahulu.

  • Jadi, di sini, model memutuskan bahwa, oh, model perlu mengetahui lebih lanjut tentang itinerari saya saat ini, sehingga model akan memanggil getItinerary.

  • Model ini mendapatkan respons dan kemudian mengetahui, oh, ada kunjungan museum dalam itinerari ini, mungkin itu yang dia bicarakan.

  • Jadi, mari kita cari detail peristiwa spesifik tersebut.

  • Dan di antara semua metadata lain dari peristiwa tertentu tersebut, Google Analytics akan melihat bahwa nilainya adalah $25.

  • Model ini memahami, kembali, dan memahami bahwa ia perlu memanggil alat tambahkan pengeluaran.

  • Jadi, di sini kita melihat beberapa langkah yang terjadi satu demi satu.

  • Jadi, Victoria, bisakah Anda membahasnya lebih dalam?

  • Ya.

  • Jadi, apa yang baru saja Jolanda jelaskan adalah contoh konkret dari demo yang baru saja dia tunjukkan, tetapi di sini, saya akan membawanya sedikit ke lapisan abstraksi yang lebih konseptual.

  • Jadi, hal ini akan terjadi setiap kali kita melakukan Pemanggilan Fungsi multi-langkah.

  • Jadi, pertama-tama, ini adalah aplikasi kita, dan itu adalah model Gemini Nano.

  • Pengguna akan memulai dengan mengirimkan kueri dan daftar alat yang tersedia ke model.

  • Jadi, model akan menggunakan informasi ini untuk memutuskan apa yang akan dikirim kembali.

  • Kemudian, misalnya, dalam kasus pertama, model mengirimkan kembali Panggilan Alat, sebut saja Panggilan Alat 1.

  • Kemudian, aplikasi akan menjalankan Panggilan Alat ini, dan memiliki Respons Alat.

  • Kemudian, yang akan dikirim kembali ke model sebenarnya adalah histori percakapan lengkap, yang mencakup kueri asli, daftar alat, Panggilan Alat pertama, dan Respons Alat pertama, kembali ke model.

  • Kemudian, model akan menggunakan informasi ini untuk memutuskan tindakan selanjutnya.

  • Jadi, proses ini dapat terus berulang hingga kita mendapatkan hasil akhir.

  • Jadi, misalnya, model akan menampilkan Panggilan Alat ke-n, lalu aplikasi akan menampilkan kembali seluruh histori percakapan.

  • Setelah model puas, oke, model tahu bahwa kueri telah terpenuhi, model akan mengirimkan Respons Akhir kembali ke aplikasi, dan aplikasi dapat menampilkan di UI bahwa, ya, prosesnya sudah selesai.

  • Oke.

  • Sekarang, saya akan menjelaskan cara menerapkan hal ini dalam kode.

    /**
    * Retrieves the itinerary events (ID, title, location) for a trip.
    * Note: Call getEventDetails(eventId) to retrieve ticket prices or notes.
    */
    @AppFunctionDeclaration(isDescribedByKDoc = true)
    @AppFunctionAccessLevel(level = ACCESS_LEVEL_SELF, isCompatEnforcementEnabled = true)
    suspend fun getItinerary(tripId: String): List<EventSummary> { ... }
    
    /**
    * Retrieves details for a specific event, including admission ticket prices.
    */
    @AppFunctionDeclaration(isDescribedByKDoc = true)
    @AppFunctionAccessLevel(level = ACCESS_LEVEL_SELF, isCompatEnforcementEnabled = true)
    suspend fun getEventDetails(eventId: String): EventDetails { ... }
  • Jadi, Anda ingat contoh dari kode Langkah Tunggal, dan ini adalah kode Multi-Langkah, jadi terlihat sangat mirip, dan poin terpentingnya adalah menulis KDoc dengan sangat, sangat jelas.

  • Jadi, dalam contoh ini, fungsi getItinerary secara eksplisit menyatakan bahwa fungsi tersebut hanya menampilkan ringkasan peristiwa tingkat tinggi.

  • Jadi, kami juga menyebutkan bahwa kami perlu memanggil getEventDetails dengan eventId jika ingin memiliki detail perjalanan yang lebih spesifik.

  • Kemudian, getEventDetails juga memiliki komentar KDoc, yang menyatakan bahwa fungsi ini dapat mengambil detail, seperti harga tiket dan catatan lainnya.

  • Jadi, dengan menggunakan komentar, dengan mendeskripsikan komentar dengan jelas, kita dapat memandu model untuk mengetahui cara alat berinteraksi satu sama lain.

  • Oke.

  • Jadi, inilah cara kita membangun agen untuk melakukan semua agent loop ini, agent loop ini.

    val agent = Agent.builder()
     .setName("Assistant")
     .setInstructions("You are a helpful travel assistant. Active tripId: $tripId")
     .enableAppFunctions()
     .setMaxTurns(5) // Guardrail against infinite tool loops
     .build()
    val runner = AgentRunner(agent = agent)
    // Automatically loops through all 3 tool calls in a single user turn!
    runner.runSingleTurnAsync(prompt).collect { event ->
     when (event) {
       is AgentEvent.FunctionCall -> showToolRunning(event.name)
       is AgentEvent.FunctionResponse -> showToolCompleted(event.name)
       is AgentEvent.TextMessage -> responseMessage += event.text
     }
    }
  • Contoh ini sangat mirip dengan contoh Langkah Tunggal, hanya ada dua tambahan di sini.

  • Pertama, kita perlu menetapkan giliran maksimum, dan dalam contoh ini, kita menetapkan lima.

  • Jadi, apa fungsinya?

  • Jadi, hal ini mencegah model melakukan loop tanpa henti.

  • Misalnya, jika ada perintah yang ambigu atau mungkin terus bolak-balik memanggil satu alat ke alat lain, lalu kembali lagi, jika kita menetapkan ini, prosesnya akan berhenti, tidak akan terus berulang.

  • Kemudian, kita masih memanggil fungsi yang sama untuk menjalankannya, runSingleTurnAsync.

  • Jadi, meskipun disebut single-turn, satu giliran sebenarnya berarti satu kueri pengguna.

  • Jadi, ekspektasi dari pengguna akhir adalah saya mengirim satu kueri, Anda menampilkan satu jawaban, tanpa benar-benar, benar-benar peduli dengan detail seperti apa yang terjadi di balik layar, seperti berapa kali kueri tersebut diulang, dan sebagainya.

  • Jadi, kita dapat terus menggunakan fungsi yang sama.

  • Lalu, karena panggilan alat multi-langkah memerlukan waktu lebih lama, Anda juga melihat dalam demo bahwa alat ini benar-benar menunjukkan fungsi apa yang sedang dipanggil, apa yang sedang dieksekusi, dan apakah sudah selesai.

  • Jadi, kita ingin menampilkan progres langsung di UI.

  • Jadi, selain mengumpulkan respons teks, kita sebenarnya dapat menampilkan nama alat, event.name, setiap kali AgentEvent memunculkan FunctionCall atau FunctionResponse, dan setelah selesai, kita dapat menampilkan TextMessage seperti sebelumnya.

Mengelola sesi percakapan multi-turn

  • Luar biasa!

  • Jadi, kita memanggil run async ini, run single-turn async, yang tentu saja mengasumsikan bahwa ada juga jenis API lain, bukan?

  • Ya.

  • Tentu saja, melakukan satu langkah saja tidak cukup.

  • Kami ingin melakukan multi-langkah.

  • Jadi, mari kita lakukan sesi multi-turn berikutnya dan saya rasa kita bisa kembali ke demo saya dan membuatnya sedikit lebih sulit di sini.

  • Jadi, kita membahas tentang kunjungan ke museum, tetapi kita juga memiliki Golden Gate Bay Cruise.

  • Jadi, untuk yang satu itu, saya hanya ingin tahu apakah saya punya cukup anggaran sebelum benar-benar memesannya.

  • Jadi, mari kita ajukan pertanyaan.

  • Mari kita lihat.

  • Jadi, saya berpikir untuk mengajak tim saya mengikuti Golden Gate Bay Cruise besok dan saya pikir harganya sekitar $180.

  • Jadi, jika saya melakukannya, berapa sisa anggaran saya sebenarnya?

  • Jadi, apa yang dilakukannya?

  • Pertanyaan ini menjawab berapa sisa anggaran saya.

  • Jadi, Gemini memahami itinerari saat ini.

  • Model memiliki informasi tersebut dan dapat menyampaikannya.

  • Namun, saya juga dapat mengajukan pertanyaan lanjutan di sini.

  • Oke, bagus.

  • Bisakah Anda menambahkannya ke pengeluaran saya?

  • Selesai, dan prosesnya akan dilanjutkan.

  • Oh, perlu mata uang, keren sekali, efek demo.

  • Oke, jadi dalam dolar.

  • $180.

  • Ini dia.

  • Ini pertama kalinya hal itu terjadi, keren.

  • Oke, jadi apa yang dilakukannya?

  • Sistem memberi tahu saya bahwa diperlukan tiga giliran dan hal ini menambah pengeluaran. Selain itu, sistem juga memungkinkan saya memuat ulang sesi ini.

  • Jadi, saya memiliki tombol muat ulang di bagian atas dan jika saya mengkliknya, saya akan menghapus histori lengkap dan dapat memulai dari awal.

  • Jadi, kita bisa kembali ke slide kita.

  • Kita memiliki demo yang berfungsi, semuanya melakukan apa yang kita inginkan, jadi menurut saya, kita bisa kembali ke kode.

  • Ya.

  • Jadi, ini sangat keren.

  • Jadi, Anda melihat bahwa Jolanda tidak menyebutkan, hanya mengatakan, oh, dalam dolar, dia tidak mengatakan seperti itu untuk tiket Golden Gate Bay Cruise.

  • Jadi, bagaimana model mengetahui semua konteksnya?

  • Jadi, ini sedikit berbeda dengan yang telah saya tunjukkan kepada Anda dalam dua cuplikan kode sebelumnya.

    // 1. Get or create an isolated session for the current trip
    val session = runner.getOrCreateSession(tripId)
    
    // 2. Run a turn (history is preserved automatically across turns)
    session.runAsync(prompt).collect { event ->
      when (event) {
        is AgentEvent.FunctionCall -> showToolRunning(event)
        is AgentEvent.FunctionResponse -> showToolCompleted(event)
        is AgentEvent.TextMessage -> responseMessage += event.text
      }
    }
    
    // 3. Clear history when the user taps "New conversation"
    session.delete()
  • Jadi, alih-alih menggunakan AgentRunner dan runSingleTurnAsync, kita perlu membuat sesi.

  • Jadi, di sini kita memanggil runner.getOrCreateSession dengan tripId.

  • Jadi, mengapa kita perlu membuat sesi?

  • Karena runSingleTurnAsync akan mereset memori, sehingga tidak akan memiliki konteks.

  • Kami tidak akan dapat melakukan percakapan multi-turn.

  • Jadi, saat Anda ingin melakukan percakapan multi-turn, kita menggunakan sesi, yaitu sesi agen.

  • Kemudian, kita meneruskan tripId.

  • Mengapa kita perlu melakukannya?

  • Karena Anda pernah melihatnya, aplikasi Jetpacker, aplikasi ini mengelola beberapa perjalanan.

  • Ada perjalanan ADS, perjalanan ke Paris, mungkin perjalanan ke Tokyo.

  • Jadi, kami ingin mempertahankan konteks dalam perjalanan.

  • Kita tidak ingin saling mengacaukan, bukan?

  • Jadi, alih-alih memanggil runSingleTurnAsync, kita memiliki runAsync.

  • Jadi, ini berbeda.

  • Jadi, ini dijalankan pada sesi dan kita masih memiliki perintah yang sama.

  • Lalu, kita masih dapat memunculkan AgentEvent, FunctionCall, FunctionResponse, dan TextMessage seperti sebelumnya, sama saja.

  • Lalu, saat Jolanda mengklik tombol percakapan baru, tombol muat ulang, kita dapat memiliki session.delete.

  • Ya.

  • Oke.

  • Jadi, kami melakukan semua ini dengan API agentic baru dan itu luar biasa dan akan berfungsi dengan baik untuk banyak kasus penggunaan Anda.

  • Namun, tentu saja, kami selalu ingin membuat hal-hal yang cepat, atau membuat hal-hal yang mudah menjadi mungkin, tetapi kami juga ingin membuat kasus yang lebih kompleks menjadi mungkin bagi Anda.

  • Jadi, kami ingin memastikan bahwa jika perlu, Anda juga masih dapat menggunakan API akses langsung untuk membuat versi yang lebih mendasar dari hal-hal ini.

  • Jadi, Victoria, mungkin Anda bisa menjelaskan apa artinya dan kapan kita akan turun ke tingkat akses langsung ini lagi?

Alur kerja agentic dan integrasi alat tingkat lanjut

  • Ya, tentu, Jolanda.

  • Jadi, untuk akses langsung ini, Anda mungkin sudah familier dengan Prompt API.

  • Jadi, kami juga mendukung panggilan fungsi di sini dan kami memiliki dua kasus penggunaan saat kami lebih memilih untuk menggunakan API ini daripada alur agen yang lebih mudah.

  • Jadi, yang pertama adalah kasus penggunaan yang sederhana, kasus penggunaan yang sangat sederhana.

  • Jadi, Anda ingat bahwa dalam alur agentic, kita mengirimkan seluruh percakapan, kueri, alat, panggilan alat, respons alat, semuanya kembali ke model.

  • Mungkin ada beberapa kasus penggunaan yang tidak memerlukan hal itu, misalnya kita hanya ingin mengirim perintah.

  • Jadi, misalnya kita ingin mengirim perintah ke model yang menampilkan panggilan alat, lalu kita tidak ingin menampilkan panggilan alat, kita hanya ingin mengirim perintah lain ke model, sehingga kita dapat mengedit histori di sana, seolah-olah kita memiliki kontrol penuh atas histori.

  • Kami akan memberikan contoh yang lebih konkret di sini.

    // Turn 1: Execute function directly without a second model call
    val turn1 = content(Content.Role.USER) {
      text("Change the background to a sunset")
    }
    val response1 = generativeModel.generateContent(
      generateContentRequest(turn1) { setTools(tools) }
    )
    executeFunctionCalls(response1)
    
    // Turn 2: Send only user prompts to save context tokens
    val customHistory = listOf(
      turn1,
      content(Content.Role.USER) { text("Oh no, I meant a beach") }
    )
    val response2 = generativeModel.generateContent(
      GenerateContentRequest.Builder(customHistory).setTools(tools).build()
    )
  • Jadi, misalnya kita memiliki aplikasi yang dapat mengubah tema latar belakang perangkat Anda.

  • Misalnya, pengguna mengirimkan kueri ini, "Ubah latar belakang menjadi matahari terbenam".

  • Kemudian, aplikasi kita menjalankan fungsi ini, latar belakangnya berubah menjadi matahari terbenam.

  • Lalu, pengguna berubah pikiran, dan berkata, "Oh, tidak, maksud saya pantai."

  • Dan yang terjadi di sini adalah kita tidak perlu mengirim status lengkap bahwa perangkat telah mengubah latar belakang menjadi matahari terbenam, dan sekarang ingin mengubahnya menjadi pantai.

  • Tidak, kita tidak perlu melakukannya.

  • Kita hanya perlu mengirimkan perintah pertama dan perintah kedua, karena perintah pertama berisi informasi latar belakang.

  • Jadi, model ini tahu bahwa, oh, ini berarti pengguna ingin mengubah latar belakang menjadi pantai.

  • Jadi, kita dapat menggunakan Prompt API untuk melakukannya.

  • Kami memiliki kontrol penuh atas histori, kami menyimpan token konteks di perangkat, karena, seperti yang Anda ketahui, di perangkat memiliki jendela token yang lebih terbatas, dan dengan ini kami dapat menghemat lebih banyak token.

  • Dan kasus penggunaan kedua, sebenarnya adalah kebalikan ekstremnya.

  • Jadi, jika kita memiliki kasus penggunaan kompleks yang belum dapat didukung oleh agentic API, misalnya jika kita memiliki sistem multi-agen saat kita memiliki beberapa sub-agen yang berinteraksi satu sama lain untuk menyelesaikan tugas yang kompleks, atau sistem hibrid saat kita memiliki model di perangkat, tetapi juga ingin memiliki model cloud, atau jika kita ingin memiliki memori kustom dan pemadatan konteks.

  • Jadi, hal ini berkaitan dengan histori, seperti kontrol penuh atas histori yang saya sebutkan sebelumnya.

  • Jadi, misalnya kita ingin, karena jendela konteks terbatas, kita tidak ingin mengirim semuanya kembali ke model, kita hanya ingin meringkas bagian yang paling penting, atau mungkin bagian terbaru, sehingga kita memiliki kontrol penuh atas hal ini, lalu kita menggunakan API akses langsung.

  • Untuk kasus penggunaan ini, kita dapat menggunakan framework seperti Agent Development Kit, atau ADK, atau Crew, atau Anda juga dapat membuat framework orkestrasi kustom sendiri.

  • Oke.

  • Jadi, itulah semua yang kami miliki tentang API agentic.

  • Namun, ada satu hal lagi yang ingin kami bahas.

  • Kita telah membahas agen dalam aplikasi, jadi Anda membangun pengalaman agen Anda sendiri di dalam aplikasi Anda sendiri, tetapi kita juga membahas cara kita menggunakan AppFunctions, dan mengapa Anda akan menggunakan AppFunctions jika satu-satunya hal yang Anda lakukan adalah di dalam aplikasi Anda sendiri?

  • Kami tahu bahwa developer seperti Anda tidak terlalu suka melakukan hal yang sama dua kali, bukan?

  • Kita tidak suka menyalin dan menempel kode, kita tidak suka harus menduplikasi logika bisnis apa pun.

  • Jadi, dengan AppFunctions, alih-alih hanya mengizinkan agen dalam aplikasi untuk menggunakannya, dengan perubahan yang sangat sederhana, kita sebenarnya dapat membuat alat kita juga tersedia untuk agen sistem.

  • Jadi, bagaimana tampilannya dengan kode?

  • Ya.

  • Jadi, dengan AppFunction, kita hanya perlu menulis sekali, lalu kita dapat mengeksposnya ke berbagai tingkat lapisan sesuai keinginan kita.

  • Ingat bahwa sebelumnya kita memiliki ACCESS_LEVEL_SELF, yang hanya mengekspos fungsi yang kita tulis ke agen dalam aplikasi, tetapi kita juga dapat mengubah tingkat akses tersebut menjadi ACCESS_LEVEL_ANDROID_TRUSTED.

  • Hal ini akan mengekspos fungsi ke agen tepercaya di Android OS.

  • Jadi, Anda tidak perlu menulis ulang fungsi, perintah, atau logika database.

  • AppFunctions sudah bertindak sebagai suara aplikasi Anda, baik secara internal maupun eksternal.

  • Kita juga ingin melihat demo untuk itu, bukan?

  • Oke, mari kita kembali ke ponsel, dan untuk demo terakhir, mari kita keluar dari aplikasi Jetpacker.

  • Jadi, kita bisa keluar, dan kita bisa masuk ke Gemini.

  • Jadi, di Gemini, kita dapat memanggil @Jetpacker.

  • Satu hal yang perlu diperhatikan adalah fitur ini hanya tersedia sebagai versi beta terbatas, jadi tidak semua orang dapat menggunakannya sekarang, tetapi Anda dapat menguji dan mencobanya.

  • Jadi, dengan Jetpacker, mari kita lihat.

  • Apa yang sebaiknya kami lakukan?

  • Oh, saya minum kopi pagi ini, kan?

  • Tolong tambahkan kopi seharga $7 ke pengeluaran perjalanan ADS.

  • Ini dia.

  • Dan yang dapat Anda lihat adalah bahwa aplikasi ini terhubung ke aplikasi Jetpacker.

  • Selesai.

  • Gemini menambahkan pengeluaran untuk saya.

  • Jadi, pada dasarnya kita telah melihat cara menggunakan semua fitur di Jetpacker.

  • Hal yang menarik dari Jetpacker adalah kita juga dapat mengaktifkan mode pesawat.

  • Jadi, kami belum benar-benar menunjukkannya hari ini, tetapi kami dapat mengaktifkan mode pesawat, dan semua yang Anda lihat dalam demo, dan saya ingin menunjukkannya, karena saya ingin memastikan bahwa Anda semua memercayai saya, jadi mari kita nonaktifkan Wi-Fi.

  • Apakah ada yang punya contoh demo yang bagus, pengeluaran yang bisa saya tambahkan?

  • Mari kita lihat.

  • Mungkin kita bisa melakukan Apa itu?

  • Oh, rental mobil akan sangat membantu, bukan?

  • Oke.

  • Mari kita coba, "Tambahkan pengeluaran sebesar $300 untuk sewa mobil".

  • Ini dia, dan berhasil.

  • Oke.

  • Luar biasa.

  • Oke, mari kita kembali ke slide.

  • Jadi, kita sedang membahas AppFunctions.

  • Saya tahu bahwa kita membahasnya dengan sangat, sangat singkat.

  • Jadi, jika Anda ingin tahu lebih lanjut, ada juga pembahasan lain dari Dan dan Sarah yang membahas lebih detail tentang cara mengaktifkan dan menguji fitur ini, alat yang kami miliki, dan sebagainya.

  • Jadi, hari ini kita telah membahas banyak hal yang berbeda.

  • Kita telah melihat Langkah Tunggal, Multi-Langkah, Multi-Giliran, dan terakhir kita juga melihat cara menggunakan AppFunction Sistem.

  • Sekarang, kami memiliki beberapa tips sebelum kita mengakhiri sesi ini.

Praktik terbaik dan kesimpulan

  • Ya.

  • Jadi, ingatlah tiga tips ini saat kita mulai membangun pengalaman agentic ini.

  • Jadi, yang pertama adalah menjaga fokus set alat.

  • Jadi, ingatlah bahwa model di perangkat memiliki kemampuan terbatas karena skalanya yang lebih kecil.

  • Jadi, daripada mendaftarkan puluhan alat, lebih baik gunakan jumlah alat yang lebih sedikit.

  • Lalu, seperti yang saya katakan sebelumnya, tulis deskripsi KDoc yang jelas karena itulah yang digunakan model untuk memutuskan apa yang akan ditampilkan.

  • Kemudian, kita juga harus menetapkan guardrail giliran maksimum.

  • Hal ini juga mencegah model melakukan loop tanpa akhir jika mengalami kebingungan.

  • Implikasinya adalah kita mungkin akan menguras baterai pengguna.

  • Jadi, jika kita memiliki ini, kita dapat menghemat baterai pengguna.

  • Terakhir, kita perlu memeriksa ketersediaan apakah Pemanggilan Fungsi sudah didukung di perangkat, dan menerapkan penggantian yang baik.

  • Misalnya, jika tidak didukung, Anda dapat merujuk ke model cloud atau UI standar Anda.

  • Oke, sepertinya kita bisa menutupnya dengan referensi kita.

  • Sekali lagi, kami akan menunjukkan kode QR kepada Anda.

  • Silakan lihat.

  • Menurut saya, salah satu hal yang perlu diingat adalah kami juga memiliki Android Skills untuk hal ini.

  • Jadi, Anda tidak perlu mempelajari setiap detailnya secara mendalam.

  • Kami memiliki dokumentasi lengkap dan Android Skill untuk melengkapi API agentic baru ini.

  • Jadi, lihatlah.

  • Download Pratinjau Developer AICore agar Anda dapat menguji semua hal ini, dan selamat membuat kode.

Kode

Cuplikan kode

Cuplikan Kotlin pada 09:53 di "Jetpacker agent demo and pemanggilan fungsi"
/**
 * Adds an expense to a trip.
 *
 * @param tripId Identifier of the trip (e.g., "paris-2026").
 * @param amount Expense amount in dollars.
 * @param description Short description of what the expense was for.
 */
@AppFunctionDeclaration(isDescribedByKDoc = true)
@AppFunctionAccessLevel(
  level = ACCESS_LEVEL_SELF,
  isCompatEnforcementEnabled = true,
)
suspend fun addExpense(tripId: String, amount: Double, description: String) {
  // Save expense to local DB / repository...
}
Cuplikan Kotlin pada menit 11:41 di "Membangun dan mengimplementasikan runner agen AI"
val model = Generation.getClient()
val features = model.getAvailableFeatures()
if(FUNCTION_CALLING in features) {
  // Device is supported!
} else {
  // Graceful fallback
}
Cuplikan Kotlin pada menit 12:07 di "Membangun dan mengimplementasikan runner agen AI"
if(FUNCTION_CALLING in features) {
  // 1. Build the agent configuration
  val agent = Agent.builder()
    .setName("Assistant")
    .setInstructions("You are a helpful on-device assistant.")
    .enableAppFunctions()
    .build()

  // 2. Initialize the runner
  val runner = AgentRunner(agent = agent)

  // 3. Create your prompt
  val prompt = content { text(userPrompt)}

  // 4. Start the agent
  runner.runSingleTurnAsync(prompt).textTokens().collect { responseMessage += it }

}
Cuplikan Kotlin pada menit 17:23 di "Arsitektur dan eksekusi agen multi-langkah"
/**
* Retrieves the itinerary events (ID, title, location) for a trip.
* Note: Call getEventDetails(eventId) to retrieve ticket prices or notes.
*/
@AppFunctionDeclaration(isDescribedByKDoc = true)
@AppFunctionAccessLevel(level = ACCESS_LEVEL_SELF, isCompatEnforcementEnabled = true)
suspend fun getItinerary(tripId: String): List<EventSummary> { ... }

/**
* Retrieves details for a specific event, including admission ticket prices.
*/
@AppFunctionDeclaration(isDescribedByKDoc = true)
@AppFunctionAccessLevel(level = ACCESS_LEVEL_SELF, isCompatEnforcementEnabled = true)
suspend fun getEventDetails(eventId: String): EventDetails { ... }
Cuplikan Kotlin pada menit 18:23 di "Arsitektur dan eksekusi agen multi-langkah"
val agent = Agent.builder()
 .setName("Assistant")
 .setInstructions("You are a helpful travel assistant. Active tripId: $tripId")
 .enableAppFunctions()
 .setMaxTurns(5) // Guardrail against infinite tool loops
 .build()
val runner = AgentRunner(agent = agent)
// Automatically loops through all 3 tool calls in a single user turn!
runner.runSingleTurnAsync(prompt).collect { event ->
 when (event) {
   is AgentEvent.FunctionCall -> showToolRunning(event.name)
   is AgentEvent.FunctionResponse -> showToolCompleted(event.name)
   is AgentEvent.TextMessage -> responseMessage += event.text
 }
}
Cuplikan Kotlin pada 22:13 di "Mengelola sesi percakapan multi-giliran"
// 1. Get or create an isolated session for the current trip
val session = runner.getOrCreateSession(tripId)

// 2. Run a turn (history is preserved automatically across turns)
session.runAsync(prompt).collect { event ->
  when (event) {
    is AgentEvent.FunctionCall -> showToolRunning(event)
    is AgentEvent.FunctionResponse -> showToolCompleted(event)
    is AgentEvent.TextMessage -> responseMessage += event.text
  }
}

// 3. Clear history when the user taps "New conversation"
session.delete()
Cuplikan Kotlin pada menit 25:02 di "Advanced agentic workflows and tool integration"
// Turn 1: Execute function directly without a second model call
val turn1 = content(Content.Role.USER) {
  text("Change the background to a sunset")
}
val response1 = generativeModel.generateContent(
  generateContentRequest(turn1) { setTools(tools) }
)
executeFunctionCalls(response1)

// Turn 2: Send only user prompts to save context tokens
val customHistory = listOf(
  turn1,
  content(Content.Role.USER) { text("Oh no, I meant a beach") }
)
val response2 = generativeModel.generateContent(
  GenerateContentRequest.Builder(customHistory).setTools(tools).build()
)