Constrained Generation with Kotlin Annotations
Setting the jsonSchemaConstraint
field in GenerationOptions
will enable constrained generation. While it is possible to
directly set the constraint with raw JSON Schema strings, we recommend to create the constraints with the Generatable
annotation.
Generatable
annotation
package ai.liquid.leap.structuredoutput
annotation class Generatable(val description: String)
annotation class Guide(val description: String)
Only Kotlin data classes can be annotated with Generatable
, and all the fields of the data class should be declared in the parameter of the constructor. Guide
annotation can be used to add further descriptions to the fields.
For example, here is a generatable data class for holding information of a city:
@Generatable(description="Facts about a city")
data class CityFact(
@Guide(description="Name of the city")
val name: String,
@Guide(description="State/province of the city")
val state: String,
@Guide(description="Country name")
val country: String,
@Guide(description="Place of interests in the city")
val placeOfInterests: List<String>,
)
Apply Generatable data class in GenerationOptions
Then we can use setResponseFormatType()
in GenerationOptions
to set up the constraint.
val options = GenerationOptions.build {
// Set the response format to follow `CityFact`
setResponseFormatType(CityFact::class)
// Example of other parameters
minP = 0.0f
temperature = 0.7f
}
conversation.generateResponse("Show the city facts about Tokyo", options)
If you want to add the JSON Schema into the prompt to help the generation, you can get the raw JSONSchema with JSONSchemaGenerator
:
val jsonSchema = JSONSchemaGenerator.getJSONSchema(CityFact::class)
conversation.generateResponse(
"Show the city facts about Tokyo following this JSON Schema: $jsonSchema",
options
)
With these settings, the model will generate a JSON string following the schema as its output.
If the JSON Schema cannot be created from the provided data class, a LeapGeneratableSchematizationException
will be thrown.
Deserialize Generatable data class
Finally, you can use GeneratableFactory.createFromJSONObject()
to deserialize the JSON string generated by the model into the generatable data class:
import ai.liquid.leap.structuredoutput.GeneratableFactory
conversation.generateResponse(
"Show the city facts about Tokyo.",
options
).onEach {
if (it is MessageResponse.Complete) {
val message = it.fullMessage
val jsonContent = (message.content.first() as ChatMessageContent.Text).text
// Deserialize the content as a `CityFact` object.
val cityFact: CityFact = GeneratableFactory.createFromJSONObject(
JSONObject(jsonContent),
)
}
}.collect()
If the JSON string generated by the model is not valid for creating instances of the generatable data class, a LeapGeneratableDeserializationException
will be thrown.
Supported data types
Not all Kotlin data types are supported in Leap Android SDK constrained generation. Here is the list of supported JSON Schema types:
- String (
String
in Kotlin) - Integer (
Int
andLong
in Kotlin) - Number (
Float
andDouble
in Kotlin) - Boolean (
Boolean
in Kotlin) - Enum (Enum class in Kotlin. The plain name string will be used as values)
- Object (Any data classes annotated with [Generatable])
- Array (
List
andMutableList
of any other supported data types, and arrays of integer, float numbers and boolean in Kotlin)
Only if the data types of the fields of object types and the items of array types are supported, these composition data types can be supported.