add structured output test#2817
Conversation
Wiz Scan Summary
To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension. |
There was a problem hiding this comment.
Code Review
This pull request downgrades Gradle and several dependency versions (including Kotlin and AGP) and introduces a new "Structured & Hybrid Output" demo feature. The demo showcases structured output generation using both KSP-generated schemas and manual JSON schemas across cloud, on-device, and hybrid modes. Feedback focuses on improving the robustness of JSON deserialization from LLM outputs: specifically, extracting JSON blocks more safely, ignoring unknown keys, and providing default values in the MovieReview data class to prevent serialization crashes.
| val cleanJson = rawTextString | ||
| .replace("```json", "") | ||
| .replace("```", "") | ||
| .trim() | ||
| parsedObject = Json.decodeFromString<MovieReview>(cleanJson) |
There was a problem hiding this comment.
LLM outputs are inherently unpredictable and can occasionally include conversational preamble, postamble, or markdown code blocks even when instructed to return JSON. Additionally, the model might return extra fields not defined in your schema. To prevent SerializationException crashes, configure the Json parser to ignore unknown keys and use a more robust extraction method to isolate the JSON block (between the first { and last }).
val jsonStartIndex = rawTextString.indexOf('{')
val jsonEndIndex = rawTextString.lastIndexOf('}')
val cleanJson = if (jsonStartIndex != -1 && jsonEndIndex != -1 && jsonStartIndex < jsonEndIndex) {
rawTextString.substring(jsonStartIndex, jsonEndIndex + 1)
} else {
rawTextString
}
val jsonParser = Json { ignoreUnknownKeys = true }
parsedObject = jsonParser.decodeFromString<MovieReview>(cleanJson)| data class MovieReview( | ||
| @Guide(description = "The official title of the movie or TV show") | ||
| val title: String, | ||
| @Guide(description = "A concise 1-sentence summary of the critique") | ||
| val summary: String, | ||
| @Guide(description = "The rating out of 5 stars (1 to 5)") | ||
| val rating: Int, | ||
| @Guide(description = "Key genre tags or themes") | ||
| val tags: List<String> | ||
| ) { |
There was a problem hiding this comment.
When deserializing structured outputs from LLMs, it is highly recommended to provide default values for all properties. LLMs (especially smaller or on-device models) can occasionally omit fields or return incomplete JSON structures. Providing default values ensures that the parser can fall back gracefully instead of throwing a SerializationException.
| data class MovieReview( | |
| @Guide(description = "The official title of the movie or TV show") | |
| val title: String, | |
| @Guide(description = "A concise 1-sentence summary of the critique") | |
| val summary: String, | |
| @Guide(description = "The rating out of 5 stars (1 to 5)") | |
| val rating: Int, | |
| @Guide(description = "Key genre tags or themes") | |
| val tags: List<String> | |
| ) { | |
| data class MovieReview( | |
| @Guide(description = "The official title of the movie or TV show") | |
| val title: String = "", | |
| @Guide(description = "A concise 1-sentence summary of the critique") | |
| val summary: String = "", | |
| @Guide(description = "The rating out of 5 stars (1 to 5)") | |
| val rating: Int = 0, | |
| @Guide(description = "Key genre tags or themes") | |
| val tags: List<String> = emptyList() | |
| ) { |
No description provided.