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

Gemini Nano'dan gelen yanıtları daha sonra işlemek üzere JSON gibi belirli biçimlere ayrıştırmanız gerekiyorsa doğrudan model erişimiyle Structured Output API'yi kullanın.

Structured Output API ile hedef çıkış yapısını Kotlin sınıflarını ve ek açıklamalarını kullanarak tanımlarsınız. Doğrudan model erişimi, Kotlin nesneniz biçiminde bir yanıt döndürür.

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

  • Varlık ayıklama: Yapılandırılmamış metinden yapılandırılmış alanları (ör. etkinlik adı, tarih, konum) ayıklama.
  • 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 alanı 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. Cihazda Structured Output API varsa API true değerini, yoksa false değerini döndürür.

suspend fun isStructuredOutputFeatureAvailable(): Boolean

Structured Output API'nin aşağıdaki şartları da vardır:

  • 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'nin 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ını engelleyebilir. Ayrıştırma sırasında hata alırsanız ek açıklamalı sınıfınızı saklama kurallarınıza ekleyerek ProGuard'dan hariç tutun. Örneğin:
# Keep classes used by structured output for deserialization for release builds.
-keep class com.google.mlkit.genai.demo.kotlin.Plant { *; }

Projeyi yapılandırma

Structured Output API'yi 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 com.google.mlkit:genai-prompt bağımlılığını ekleyin.

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

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

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

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

Kotlin veri sınıflarını kullanarak modelin döndürmesini istediğiniz verilerin yapısını tanımlayın. Çıkış yapısını tanımlamak için 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ışını yönlendiren 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

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

Tür Açıklama Desteklenen @Guide kısıtlamaları
String Metin 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ğerleri için. description
List<T> Desteklenen türlerin veya iç içe yerleştirilmiş @Generable sınıflarının listeleri için. description, minItems ve maxItems
List<String> String değer 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 generateTypedContentRequest yardımcı işlevini kullanarak standart isteminizi sarmalayın ve hedef çıkış sınıfını belirtin.

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

Sonlanma nedenlerini ve hataları işleme

Structured Output API'yi kullanırken API tarafından oluşturulan olası istisnaları işlemeniz ve ayrıştırılmış yanıt boşsa yanıt adaylarındaki finishReason özelliğini incelemeniz gerekir.

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 durdu. Çıktı eksik olabilir.
  • TypedFinishReason.PARSE_CLASS_ERROR: Model, oluşturma işlemini tamamladı ancak elde edilen JSON, hedef Kotlin sınıfına ayrıştırılamadı.
  • TypedFinishReason.STRUCTURE_NOT_ANNOTATED: Hedef sınıfta 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ı ihlal etti (ör. aralık dışı değer, sınır dışı liste boyutu).
  • TypedFinishReason.OTHER: Oluşturma işlemi başka nedenlerden dolayı durduruldu.

İstisnalar

Structured Output API, aşağıdaki hata kodlarıyla GenAiException hatası verebilir:

  • GenAiException.STRUCTURED_OUTPUT_INVALID_CLASS (-104): Ek açıklamalı sınıfın yapısı geçersiz veya desteklenmeyen türler içeriyor. Bu genellikle geliştirme aşamasındaki 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 @Generable veri 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ından geçemiyor. Bu bir çalışma zamanı hatasıdır. Bu hatayla sık sık karşılaşıyorsanız aşağıdaki çözümleri deneyin:
    • Modeli daha sıkı bir şekilde yönlendirmek için istem talimatlarınızı hassaslaştırma.
    • @Guide ek açıklamalarınızdaki kısıtlamalar (ör. minimum, maksimum veya liste boyutu sınırları) modelin kapasitesi için çok kısıtlayıcıysa bunları esnetme.
    • Uygulamanızda, isteği yeniden deneme veya varsayılan bir durum gösterme gibi bir yedek strateji uygulama

Parça sayma

Yapılandırılmış isteminizin giriş jetonu sınırını aşmadığından emin olmak için countTokens() yöntemini kullanarak jeton sayısını hesaplayın.

Yapılandırılmış çıkış isteklerinin, modele şema yapısı hakkında talimat vermesi gerektiğinden, yalnızca ham istem metnindeki (GenerateContentRequest örneği kullanarak) parçaları saymak 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ı içeren GenerateTypedContentRequest örneğinin tamamını countTokens() yöntemine iletmeniz gerekir:

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