Wenn Sie die Antworten der Prompt API zur Weiterverarbeitung in bestimmte Formate wie JSON parsen müssen, verwenden Sie die Structured Output API.
Mit der Structured Output API definieren Sie die Zielausgabestruktur mithilfe von Kotlin-Klassen und ‑Annotationen. Die Prompt API gibt dann eine Antwort in Form Ihres Kotlin-Objekts zurück.
Das Generieren strukturierter Ausgaben ist besonders nützlich für Aufgaben wie die folgenden:
- Entitätsextraktion: Extrahieren strukturierter Felder (z. B. Ereignisname, Datum, Ort) aus unstrukturiertem Text.
- Klassifizierung: Eingabetext in vordefinierte Kategorien einteilen.
- Datenserialisierung: Umwandlung unstrukturierter Nutzereingaben in ein Format, das für die Speicherung in Datenbanken oder API-Aufrufe geeignet ist.
Vorbereitung
Verwenden Sie die isStructuredOutputFeatureAvailable() API, um zu prüfen, ob die Structured Output API auf dem Gerät verfügbar ist. Die API gibt true zurück, wenn die Structured Output API auf dem Gerät verfügbar ist, und false, wenn nicht.
suspend fun isStructuredOutputFeatureAvailable(): Boolean
Für die Structured Output API gelten außerdem die folgenden Anforderungen:
- Android-API-Level 26 oder höher (
minSdk26) - KSP-Plug-in-Version 2.3.6 oder höher
Beschränkungen
Die Structured Output API unterliegt den folgenden Einschränkungen:
- Funktioniert nur in Kotlin.
- ProGuard kann die Verarbeitung Ihrer annotierten Klasse beeinträchtigen. Fügen Sie Ihre annotierte Klasse Ihren keep-Regeln hinzu, um sie von ProGuard auszuschließen, wenn Sie beispielsweise Parsing-Fehler erhalten:
# Keep classes used by structured output for deserialization for release builds.
-keep class com.google.mlkit.genai.demo.kotlin.Plant { *; }
Projekt konfigurieren
So legen Sie los:
Fügen Sie die ML Kit Prompt API als Abhängigkeit in der Datei
build.gradle.kts(oderbuild.gradle) auf App-Ebene hinzu, falls noch nicht geschehen.Fügen Sie das KSP-Plug-in der Datei
build.gradle.ktsauf Projektebene hinzu. Verwenden Sie eine KSP-Plug-in-Version, die mit Ihrer Kotlin-Version kompatibel ist. Wir empfehlen KSP-Version 2.3.6 oder höher.dependencies { ... classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:2.3.6" }Fügen Sie die strukturierten Compiler-Abhängigkeiten der Datei
build.gradle.ktsauf App-Ebene hinzu:dependencies { ... ksp("com.google.mlkit:genai-schema-compiler:1.0.0-alpha1") }
Ausgabestruktur definieren
Definieren Sie die Struktur der Daten, die das Modell zurückgeben soll, mithilfe von Kotlin-Datenklassen. Es gibt zwei Hauptanmerkungen zum Definieren der Ausgabestruktur:
- Verwenden Sie die Annotation
@Generable, um die Klasse als Ziel für strukturierte Ausgabe zu definieren. - Verwenden Sie die
@Guide-Anmerkungen für die Klassenattribute, um Beschreibungen und Einschränkungen anzugeben, die die Ausgabe des Modells beeinflussen.
Im folgenden Beispiel wird eine Struktur zum Extrahieren von Pflanzeninformationen definiert:
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
)
Unterstützte Typen und Einschränkungen
Die folgenden Typen werden in einer mit @Generable annotierten Klasse unterstützt, zusammen mit den entsprechenden @Guide-Einschränkungen:
| Typ | Beschreibung | Unterstützte @Guide-Einschränkungen |
|---|---|---|
String |
Für Text. | description, enumValues |
Double/Float |
Für Gleitkommazahlen. | description, minimum, maximum |
Int/Long |
Für ganze Zahlen. | description, minimum, maximum |
Boolean |
Für Wahr/Falsch-Werte. | description |
List<T> |
Für Listen der unterstützten Typen oder verschachtelte @Generable-Klassen.
|
description, minItems, maxItems |
List<String> |
Für Listen mit String-Werten. |
description, enumValues, minItems,
maxItems |
Klasse @Generable |
Für verschachtelte strukturierte Objekte. | description |
Strukturierte Inhalte generieren
Wenn Sie eine strukturierte Ausgabe anfordern möchten, verwenden Sie die Hilfsfunktion generateTypedContentRequest, um Ihren Standardprompt zu umschließen und die Zielausgabeklasse anzugeben.
// 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}")
}
}
}
Abschlussgründe und Fehler behandeln
Wenn Sie die Structured Output API verwenden, sollten Sie potenzielle Ausnahmen, die von der API ausgelöst werden, abfangen und die finishReason-Eigenschaft in den Antwortkandidaten prüfen, wenn die geparste Antwort null ist.
Werte für „finishReason“
Das Attribut finishReason kann einen der folgenden Werte haben:
TypedFinishReason.STOP: Das Modell hat die Generierung erfolgreich abgeschlossen und die Ausgabe entspricht dem Schema.TypedFinishReason.MAX_TOKENS: Das Modell wurde beendet, weil das Tokenlimit erreicht wurde. Die Ausgabe ist möglicherweise unvollständig.TypedFinishReason.PARSE_CLASS_ERROR: Das Modell hat die Generierung abgeschlossen, aber das resultierende JSON konnte nicht in die Ziel-Kotlin-Klasse geparst werden.TypedFinishReason.STRUCTURE_NOT_ANNOTATED: Der Zielklasse oder ihren verschachtelten Klassen fehlt die erforderliche Annotation@Generable.TypedFinishReason.STRUCTURE_VALUES_INVALID: Die generierten Werte haben die in den@Guide-Annotationen definierten Einschränkungen verletzt (z. B. Wert außerhalb des zulässigen Bereichs, Listengröße außerhalb der zulässigen Grenzen).TypedFinishReason.OTHER: Die Generierung wurde aus anderen Gründen beendet.
Ausnahmen
Die Structured Output API kann GenAiException mit den folgenden Fehlercodes auslösen:
GenAiException.STRUCTURED_OUTPUT_INVALID_CLASS(-104): Die Struktur der annotierten Klasse ist ungültig oder enthält nicht unterstützte Typen. Dies ist in der Regel ein Konfigurationsfehler, der während der Entwicklung auftritt. Prüfen Sie die Definition Ihrer@Generable-Datenklasse, um sicherzustellen, dass alle Attributtypen unterstützt werden und keine zirkulären Abhängigkeiten vorhanden sind.GenAiException.STRUCTURED_OUTPUT_INVALID_VALUE(-105): Die vom Modell generierten Werte sind ungültig oder die Überprüfung der Einschränkungen ist fehlgeschlagen. Dies ist ein Laufzeitfehler. Wenn dieser Fehler häufig auftritt, können Sie Folgendes versuchen:- Sie können die Anweisungen in Ihrem Prompt verfeinern, um das Modell strenger zu steuern.
- Lockerung der Einschränkungen (z. B. Mindest-, Höchst- oder Listengrößenbeschränkungen) in Ihren
@Guide-Anmerkungen, wenn sie für die Fähigkeiten des Modells zu restriktiv sind. - Implementieren Sie in Ihrer App eine Fallback-Strategie, z. B. durch Wiederholen der Anfrage oder Anzeigen eines Standardstatus.
Tokens zählen
Um zu prüfen, ob Ihr strukturierter Prompt das Limit für Eingabetokens einhält, berechnen Sie die Anzahl der Tokens mit der Methode countTokens().
Da bei Anfragen mit strukturierter Ausgabe das Modell über die Schemastruktur informiert werden muss, ist das Zählen von Tokens nur für den Rohprompttext (mit einer GenerateContentRequest-Instanz) nicht genau. Um eine genaue Anzahl von Tokens zu erhalten, müssen Sie die vollständige GenerateTypedContentRequest-Instanz, einschließlich der Zielklasse und der Schemakonfigurationen, an die Methode countTokens() übergeben:
suspend fun <T : Any> countTokens(request: GenerateTypedContentRequest<T>): CountTokensResponse