Yapılandırılmış çıkış oluşturma

Daha fazla işleme için Prompt API'den gelen yanıtları JSON gibi belirli biçimlerde ayrıştırmanız gerekiyorsa Structured Output API'yi kullanın.

Yapılandırılmış Çıkış API'si ile Kotlin sınıflarını ve ek açıklamalarını kullanarak hedef çıkış yapısını tanımlarsınız. Daha sonra Prompt API, Kotlin nesneniz şeklinde bir yanıt döndürür.

Yapılandırılmış çıkış oluşturma, özellikle aşağıdaki gibi görevler için yararlıdır:

  • Varlık çıkarma: Yapılandırılmamış metinden yapılandırılmış alanları (örneğin, etkinlik adı, tarih, konum) çıkarma.
  • Sınıflandırma: Giriş metnini önceden tanımlanmış kategorilere ayırma.
  • Veri serileştirme: Yapılandırılmamış kullanıcı girişini veritabanı depolama veya API çağrıları için uygun bir biçime dönüştürme.

Ön koşullar

Structured Output API'nin cihazda kullanılabilir olduğunu doğrulamak için isStructuredOutputFeatureAvailable() API'sini kullanın. API, cihazda Yapılandırılmış Çıkış API'si kullanılabiliyorsa true, aksi takdirde false değerini döndürür.

suspend fun isStructuredOutputFeatureAvailable(): Boolean

Yapılandırılmış Çıkış API'si için aşağıdaki koşullar da geçerlidir:

  • Android API düzeyi 26 veya daha yüksek (minSdk 26)
  • KSP eklentisi 2.3.6 veya sonraki bir sürüm

Sınırlamalar

Structured Output API'de aşağıdaki sınırlamalar vardır:

  • Yalnızca Kotlin'de çalışır.
  • ProGuard, ek açıklamalı sınıfınızın ayrıştırılmasına müdahale edebilir. Ayrıştırma sırasında hata alırsanız (örneğin) not eklenmiş sınıflarınızı koruma kurallarınıza ekleyerek ProGuard'dan hariç tutun:
# Keep classes used by structured output for deserialization for release builds.
-keep class com.google.mlkit.genai.demo.kotlin.Plant { *; }

Projeyi yapılandırma

Yapılandırılmış Çıkış API'sini kullanmaya başlamak için aşağıdaki adımları uygulayın:

  1. Henüz yapmadıysanız uygulama düzeyindeki build.gradle.kts (veya build.gradle) dosyanıza ML Kit Prompt API'yi bağımlılık olarak ekleyin.

  2. KSP eklentisini proje düzeyindeki build.gradle.kts dosyanıza ekleyin. Kotlin sürümünüzle uyumlu bir KSP eklenti sürümü kullanın. KSP 2.3.6 veya sonraki sürümlerini kullanmanızı öneririz.

    dependencies {
        ...
        classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:2.3.6"
    }
    
  3. Yapılandırılmış derleyici bağımlılıklarını uygulama düzeyindeki build.gradle.kts dosyanıza ekleyin:

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

Çıkış yapısını tanımlama

Modelin döndürmesini istediğiniz verilerin yapısını Kotlin veri sınıflarını kullanarak tanımlayın. Çıkış yapısını tanımlamak için kullanılan iki ana ek açıklama vardır:

  • Sınıfı yapılandırılmış çıkış için hedef olarak tanımlamak üzere @Generable ek açıklamasını kullanın.
  • Modelin çıkışına yön veren açıklamalar ve kısıtlamalar sağlamak için sınıf özelliklerindeki @Guide ek açıklamalarını kullanın.

Aşağıdaki örnekte, bitki bilgilerini ayıklamak için bir yapı tanımlanmaktadır:

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
)

Desteklenen türler ve kısıtlamalar

Aşağıdaki türler, @Generable ek açıklamalı bir sınıfta desteklenir ve ilgili @Guide kısıtlamaları geçerlidir:

Tür Açıklama Desteklenen @Guide kısıtlamaları
String Metinler için. description, enumValues
Double/Float Kayan noktalı sayılar için. description, minimum ve maximum
Int/Long Tam sayılar için. description, minimum ve maximum
Boolean Doğru/yanlış değerler için. description
List<T> Desteklenen türlerin veya iç içe yerleştirilmiş @Generable sınıfların listeleri için. description, minItems ve maxItems
List<String> String değerlerinin listeleri için. description, enumValues, minItems, maxItems
@Generable sınıf İç içe yerleştirilmiş yapılandırılmış nesneler için. description

Yapılandırılmış içerik oluşturma

Yapılandırılmış çıkış istemek için standart isteminizi sarmalamak ve hedef çıkış sınıfını belirtmek üzere generateTypedContentRequest yardımcı işlevini kullanın.

// 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}")
        }
    }
}

Tamamlama nedenlerini ve hatalarını işleme

Structured Output API'yi kullanırken API'nin oluşturduğu olası istisnaları işlemeli ve ayrıştırılan yanıt boşsa yanıt adaylarındaki finishReason özelliğini incelemelisiniz.

finishReason değerleri

finishReason özelliği aşağıdaki değerlerden birini alabilir:

  • TypedFinishReason.STOP: Model, oluşturma işlemini başarıyla tamamladı ve çıkış, şemayla eşleşiyor.
  • TypedFinishReason.MAX_TOKENS: Model, jeton sınırına ulaştığı için durduruldu. Çıktı eksik olabilir.
  • TypedFinishReason.PARSE_CLASS_ERROR: Model oluşturma işlemini tamamladı ancak sonuçtaki JSON, hedef Kotlin sınıfına ayrıştırılamadı.
  • TypedFinishReason.STRUCTURE_NOT_ANNOTATED: Hedef sınıf veya iç içe yerleştirilmiş sınıflarında gerekli @Generable ek açıklaması eksik.
  • TypedFinishReason.STRUCTURE_VALUES_INVALID: Oluşturulan değerler, @Guide ek açıklamalarında tanımlanan kısıtlamaları (ör. değer aralık dışında, liste boyutu sınırların dışında) ihlal etti.
  • TypedFinishReason.OTHER: Üretme işlemi başka nedenlerden dolayı durduruldu.

İstisnalar

Yapılandırılmış Çıkış API'si, aşağıdaki hata kodlarıyla GenAiException hatası verebilir:

  • GenAiException.STRUCTURED_OUTPUT_INVALID_CLASS (-104): Açıklama eklenmiş sınıfın yapısı geçersiz veya desteklenmeyen türler içeriyor. Bu genellikle geliştirme zamanında yapılan bir yapılandırma hatasıdır. Tüm özellik türlerinin desteklendiğinden ve döngüsel bağımlılık olmadığından emin olmak için @Generableveri sınıfı tanımınızı inceleyin.
  • GenAiException.STRUCTURED_OUTPUT_INVALID_VALUE (-105): Model tarafından oluşturulan değerler geçersiz veya kısıtlama doğrulaması başarısız. Bu bir çalışma zamanı hatasıdır. Bu hatayla sık karşılaşıyorsanız aşağıdaki çözümleri deneyin:
    • Modeli daha katı bir şekilde yönlendirmek için istem talimatlarınızı iyileştirme
    • Modelin özelliklerine göre çok kısıtlayıcıysa @Guide ek açıklamalarınızdaki kısıtlamaları (ör. minimum, maksimum veya liste boyutu sınırları) gevşetin.
    • Uygulamanızda, isteği yeniden deneme veya varsayılan bir durumu görüntüleme gibi bir yedek strateji uygulayın.

Parça sayma

Yapılandırılmış isteminizin giriş jetonu sınırında olup olmadığını kontrol etmek için countTokens() yöntemini kullanarak jeton sayısını hesaplayın.

Yapılandırılmış çıkış isteklerinde modele şema yapısı hakkında talimat verilmesi gerektiğinden, jetonların yalnızca ham istem metninde (GenerateContentRequest örneği kullanılarak) sayılması doğru değildir. Doğru bir jeton sayısı elde etmek için hedef sınıfınız ve şema yapılandırmalarınız da dahil olmak üzere GenerateTypedContentRequest örneğinin tamamını countTokens() yöntemine iletmeniz gerekir:

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