Membuat output terstruktur

Jika Anda perlu mengurai respons dari Prompt API ke dalam format tertentu, seperti JSON, untuk diproses lebih lanjut, gunakan Structured Output API.

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

Membuat output terstruktur sangat berguna untuk tugas seperti berikut:

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

Prasyarat

Untuk memverifikasi bahwa Structured Output API tersedia di perangkat, gunakan isStructuredOutputFeatureAvailable() API. API 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 beranotasi Anda. Tambahkan class beranotasi ke aturan keep untuk mengecualikannya dari ProGuard jika Anda mengalami error penguraian, 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 ML Kit Prompt API sebagai dependensi di file build.gradle.kts (atau build.gradle) tingkat aplikasi Anda, jika belum.

  2. Tambahkan plugin KSP ke file build.gradle.kts tingkat project Anda. Gunakan plugin KSP versi 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 tingkat aplikasi Anda:

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

Tentukan struktur output

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

  • Gunakan anotasi @Generable untuk menentukan class sebagai target 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 beranotasi @Generable, beserta 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

Buat konten terstruktur

Untuk meminta output terstruktur, gunakan fungsi helper generateTypedContentRequest untuk menggabungkan perintah standar Anda 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,
    // Instructs ML Kit to include the generated schema structure in the prompt
    // sent to AICore. This should always be set to `true` unless the model
    // already knows what output format to use.
    includeSchemaInPrompt = true
)

// 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 penyelesaian 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 diuraikan adalah null.

Nilai finishReason

Properti finishReason dapat mengambil salah satu nilai berikut:

  • TypedFinishReason.STOP: Model berhasil menyelesaikan pembuatan dan output cocok dengan skema.
  • TypedFinishReason.MAX_TOKENS: Model berhenti karena mencapai batas token. Output mungkin tidak lengkap.
  • TypedFinishReason.PARSE_CLASS_ERROR: Model menyelesaikan pembuatan, tetapi JSON yang dihasilkan tidak dapat diuraikan 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 berhenti karena alasan lain.

Pengecualian

Structured Output API mungkin menampilkan GenAiException dengan kode error berikut:

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

Menghitung token

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

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

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