Membuat output terstruktur

Jika Anda perlu mengurai respons dari Gemini Nano ke dalam format tertentu, seperti JSON, untuk pemrosesan lebih lanjut, gunakan Structured Output API dengan akses model langsung.

Dengan Structured Output API, Anda menentukan struktur output target menggunakan class dan anotasi Kotlin. Akses model langsung kemudian menampilkan respons dalam bentuk objek Kotlin Anda.

Membuat output terstruktur sangat berguna untuk tugas-tugas seperti berikut:

  • Ekstraksi entity: Mengekstrak kolom terstruktur (misalnya, nama, tanggal, lokasi acara) dari teks tidak terstruktur.
  • Klasifikasi: Mengategorikan teks input ke dalam kategori yang telah ditentukan.
  • Serialisasi data: Mengonversi input pengguna yang tidak terstruktur menjadi format yang sesuai untuk penyimpanan database atau panggilan API.

Prasyarat

Untuk memverifikasi bahwa Structured Output API tersedia di perangkat, gunakan API isStructuredOutputFeatureAvailable(). API akan menampilkan true jika Structured Output API tersedia di perangkat, dan false jika tidak.

suspend fun isStructuredOutputFeatureAvailable(): Boolean

Structured Output API juga memiliki persyaratan berikut:

  • Android API level 26 atau yang lebih tinggi (minSdk 26)
  • Plugin KSP versi 2.3.6 atau yang lebih tinggi

Batasan

Structured Output API memiliki batasan berikut:

  • Hanya berfungsi di Kotlin.
  • ProGuard mungkin mengganggu penguraian class yang dianotasi. Tambahkan class yang dianotasi ke aturan keep untuk mengecualikannya dari ProGuard jika Anda mendapatkan error saat mengurai, misalnya:
# Keep classes used by structured output for deserialization for release builds.
-keep class com.google.mlkit.genai.demo.kotlin.Plant { *; }

Konfigurasikan project

Untuk mulai menggunakan Structured Output API, ikuti langkah-langkah berikut:

  1. Tambahkan dependensi com.google.mlkit:genai-prompt di file build.gradle.kts (atau build.gradle) level aplikasi, jika Anda belum melakukannya.

  2. Tambahkan plugin KSP ke file build.gradle.kts level project. Gunakan versi plugin KSP yang kompatibel dengan versi Kotlin Anda; sebaiknya gunakan KSP versi 2.3.6 atau yang lebih tinggi.

    dependencies {
        ...
        classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:2.3.6"
    }
    
  3. Tambahkan dependensi compiler terstruktur ke file build.gradle.kts level aplikasi:

    dependencies {
        ...
        ksp("com.google.mlkit:genai-schema-compiler:1.0.0-alpha1")
    }
    

Menentukan struktur output

Tentukan struktur data yang Anda inginkan untuk ditampilkan oleh model menggunakan class data Kotlin. Ada dua anotasi utama untuk menentukan struktur output:

  • Gunakan anotasi @Generable untuk menentukan class sebagai target untuk output terstruktur.
  • Gunakan anotasi @Guide pada properti class untuk memberikan deskripsi dan batasan yang memandu output model.

Contoh berikut menentukan struktur untuk mengekstrak informasi tanaman:

import com.google.mlkit.genai.schema.annotations.Generable
import com.google.mlkit.genai.schema.annotations.Guide

@Generable
data class PlantList(
    @Guide(description = "The list of plants found", minItems = 1, maxItems = 5)
    val plants: List<Plant>
)

@Generable("Information about a plant species")
data class Plant(
    @Guide(description = "The common name of the plant")
    val commonName: String,
    
    @Guide(description = "The full latin scientific name of the plant")
    val scientificName: String,
    
    @Guide(
        description = "The maximum height of the plant in centimeters.",
        minimum = 1.0,
        maximum = 10000.0
    )
    val maxHeightCm: Int,
    
    @Guide(description = "Whether the plant is poisonous or not")
    val isPoisonous: Boolean?,
    
    @Guide(
        description = "The primary continent where this plant is native to",
        enumValues = ["Africa", "Antarctica", "Asia", "Australia", "Europe", "North America", "South America"]
    )
    val nativeContinent: String
)

Jenis dan batasan yang didukung

Jenis berikut didukung dalam class yang dianotasi @Generable, bersama dengan batasan @Guide masing-masing:

Jenis Deskripsi Batasan @Guide yang didukung
String Untuk teks. description, enumValues
Double / Float Untuk angka floating point. description, minimum, maximum
Int / Long Untuk bilangan bulat. description, minimum, maximum
Boolean Untuk nilai benar/salah. description
List<T> Untuk daftar jenis yang didukung atau class @Generable bertingkat. description, minItems, maxItems
List<String> Untuk daftar nilai String. description, enumValues, minItems, maxItems
Class @Generable Untuk objek terstruktur bertingkat. description

Membuat konten terstruktur

Untuk meminta output terstruktur, gunakan fungsi bantuan generateTypedContentRequest untuk menggabungkan perintah standar dan menentukan class output target.

// 1. Initialize your GenerativeModel as usual
val generativeModel = Generation.getClient()

// 2. Prepare the prompt text
val promptText = "List some common plants found in California."
val baseRequest = GenerateContentRequest.Builder(TextPart(promptText)).build()

// 3. Create the typed request, specifying the target class (e.g., PlantList)
val typedRequest = generateTypedContentRequest(
    generateContentRequest = baseRequest,
    outputClass = PlantList::class
)

// 4. Run the inference
try {
    val typedResponse = generativeModel.generateContent(typedRequest)
    
    // 5. Access the parsed object
    // The response candidates contain the parsed object of type T (PlantList in this case)
    val plantList: PlantList? = typedResponse.candidates.firstOrNull()?.response
    
    if (plantList != null) {
        // Process the structured data
        for (plant in plantList.plants) {
            Log.d("StructuredOutput", "Found plant: ${plant.commonName} (${plant.scientificName})")
        }
    } else {
        Log.e("StructuredOutput", "Failed to parse response into the desired structure.")
        
        // Inspect finish reason for details
        val finishReason = typedResponse.candidates.firstOrNull()?.finishReason
        Log.d("StructuredOutput", "Finish reason: $finishReason")
    }
} catch (e: GenAiException) {
    // Handle API errors
    when (e.errorCode) {
        GenAiException.STRUCTURED_OUTPUT_INVALID_CLASS -> {
            Log.e("StructuredOutput", "The class structure is not supported.")
        }
        GenAiException.STRUCTURED_OUTPUT_INVALID_VALUE -> {
            Log.e("StructuredOutput", "The model generated values that violate the schema constraints.")
        }
        else -> {
            Log.e("StructuredOutput", "API error: ${e.message}")
        }
    }
}

Menangani alasan penghentian dan error

Saat menggunakan Structured Output API, Anda harus menangani potensi pengecualian yang ditampilkan oleh API dan memeriksa properti finishReason dalam kandidat respons jika respons yang diurai bernilai null.

Nilai finishReason

Properti finishReason dapat menggunakan salah satu nilai berikut:

  • TypedFinishReason.STOP: Model berhasil menyelesaikan pembuatan dan output-nya cocok dengan skema.
  • TypedFinishReason.MAX_TOKENS: Model berhenti karena telah mencapai batas token. Output mungkin tidak lengkap.
  • TypedFinishReason.PARSE_CLASS_ERROR: Model menyelesaikan pembuatan, tetapi JSON yang dihasilkan tidak dapat diurai ke dalam class Kotlin target.
  • TypedFinishReason.STRUCTURE_NOT_ANNOTATED: Class target atau class bertingkatnya tidak memiliki anotasi @Generable yang diperlukan.
  • TypedFinishReason.STRUCTURE_VALUES_INVALID: Nilai yang dihasilkan melanggar batasan yang ditentukan dalam anotasi @Guide (misalnya nilai di luar rentang, ukuran daftar di luar batas).
  • TypedFinishReason.OTHER: Pembuatan dihentikan karena alasan lain.

Pengecualian

Structured Output API mungkin menampilkan GenAiException dengan kode error berikut:

  • GenAiException.STRUCTURED_OUTPUT_INVALID_CLASS (-104): Struktur class yang dianotasi tidak valid atau berisi jenis yang tidak didukung. Hal ini biasanya merupakan error konfigurasi waktu pengembangan. Tinjau definisi class data @Generable Anda untuk memeriksa apakah semua jenis properti didukung dan tidak ada dependensi sirkular.
  • GenAiException.STRUCTURED_OUTPUT_INVALID_VALUE (-105): Nilai yang dihasilkan oleh model tidak valid atau gagal dalam verifikasi batasan. Ini adalah error runtime. Jika Anda sering mengalami error ini, pertimbangkan solusi berikut:
    • Menyempurnakan petunjuk perintah untuk memandu model dengan lebih ketat.
    • Melonggarkan batasan (seperti batas minimum, maksimum, atau ukuran daftar) dalam anotasi @Guide Anda jika terlalu membatasi kemampuan model.
    • Menerapkan strategi penggantian di aplikasi Anda, seperti mencoba ulang permintaan atau menampilkan status default.

Menghitung token

Untuk memeriksa apakah perintah terstruktur Anda berada dalam batas token input, hitung jumlah token menggunakan metode countTokens().

Karena permintaan output terstruktur perlu menginstruksikan model tentang struktur skema, penghitungan token hanya pada teks perintah mentah (menggunakan instance GenerateContentRequest) tidak akan akurat. Untuk mendapatkan jumlah token yang akurat, Anda harus meneruskan instance GenerateTypedContentRequest lengkap, yang mencakup konfigurasi class dan skema target, ke metode countTokens():

suspend fun <T : Any> countTokens(request: GenerateTypedContentRequest<T>): CountTokensResponse