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 (
minSdk26) - 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:
Henüz yapmadıysanız uygulama düzeyindeki
build.gradle.kts(veyabuild.gradle) dosyanıza ML Kit Prompt API'yi bağımlılık olarak ekleyin.KSP eklentisini proje düzeyindeki
build.gradle.ktsdosyanı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" }Yapılandırılmış derleyici bağımlılıklarını uygulama düzeyindeki
build.gradle.ktsdosyanı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
@Generableek 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
@Guideek 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@Generableek açıklaması eksik.TypedFinishReason.STRUCTURE_VALUES_INVALID: Oluşturulan değerler,@Guideek 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
@Guideek 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