-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve structured outputs and tool calling experience #139
Comments
Ah, I see the confusion here. So the idea is that you can use The name For your use-case you'd do the following: Schema.builder()
.putAdditionalProperty("type", JsonValue.from("object"))
.putAdditionalProperty("properties", JsonValue.from(
Map.of(
"steps", Map.of("type", "array", "items", Map.of(
"type", "object",
"properties", Map.of(/* etc. */),
"required", List.of("explanation", "output"),
"additionalProperties", false
)),
"final_answer", Map.of("type", "string")
)
))
// Other properties...
.build() Aside: |
@TomerAberbach Yes that's actually what I discovered and did until we got a better solution. But having a proper Schema builder would avoid any error with it. Let me know if you want me to work on something as a PR. |
ResponseFormatJsonSchema.JsonSchema.Schema
is missing most fieldsResponseFormatJsonSchema.JsonSchema.Schema
doesn't have fixed fields
I'm not sure we want to have the entire JSON schema spec encoded in the builders, since it's pretty complicated/large. It might just be easier in the current state (as long as we document it) @kwhinnery-openai do you have any thoughts? To be clear, the currently generated builders are the result of the OpenAPI schema having an "unknown/arbitrary" type for this field (vs a JSON schema spec describing the JSON schema spec lol) |
This comment has been minimized.
This comment has been minimized.
Having first class support would be great. I'm moving some existing code from TypeScript to Kotlin and miss the js sdk. I would love to have either some more convenient helpers or support that interops with another library that we can use to parse the response like the other language SDKs (zod/pydantic for js/python respectively). The important thing to remember about the current implementation is specifying the I need to add/edit response schemas often so I ended up building a very simple builder based on @TomerAberbach's sample. It's definitely incomplete and could use some QoL but may save some time for anyone else who is waiting for this support. data class SchemaObjectSpec(
private val description: String? = null,
private val properties: MutableMap<String, Any?> = mutableMapOf(),
private val required: MutableList<String> = mutableListOf(),
) : SchemaSpec {
fun str(name: String, description: String) {
prop(name, SchemaStrSpec(description))
}
fun obj(name: String, spec: SchemaObjectSpec) {
prop(name, spec)
}
fun arr(
name: String,
description: String? = null,
childSpec: SchemaSpec,
) {
prop(name, SchemaArraySpec(description = description, child = childSpec))
}
fun arr(name: String, spec: SchemaArraySpec) {
prop(name, spec)
}
private fun prop(name: String, spec: SchemaSpec) {
properties[name] = spec.build()
required.add(name)
}
override fun build(): Map<String, Any?> {
return mapOf(
"type" to "object",
"description" to description,
"properties" to properties,
"additionalProperties" to JsonValue.from(false),
"required" to required,
)
}
}
interface SchemaSpec {
fun build(): Map<String, Any?>
}
data class SchemaArraySpec(
private val description: String? = null,
private val child: SchemaSpec,
) : SchemaSpec {
override fun build(): Map<String, Any?> {
return mapOf(
"type" to "array",
"description" to description,
"items" to child.build(),
)
}
}
data class SchemaStrSpec(
private val description: String? = null,
) : SchemaSpec {
override fun build(): Map<String, Any?> {
return mapOf<String, Any?>(
"type" to "string",
"description" to description,
)
}
} And you can use it like: val schema =
SchemaObjectSpec()
.apply {
str(
"someVariable",
"a description of a list variable")
arr(
"list_of_strs",
description =
"A description for an array",
childSpec = SchemaStrSpec())
arr(
"list_of_objects",
description =
"A description for the list of objects",
SchemaObjectSpec().apply {
str("foo", "description of foo")
str("bar", "description of bar")
})
}
.build()
val jsonSchema =
JsonSchema.builder()
.strict(true)
.name("name_of_schema")
.schema(JsonValue.from(schema))
.build()
val responseFormat =
ChatCompletionCreateParams.ResponseFormat.ofJsonSchema(
ResponseFormatJsonSchema.builder().jsonSchema(jsonSchema).build())
val params =
ChatCompletionCreateParams.builder()
.addMessage(message)
.model(ChatModel.GPT_4O)
.responseFormat(responseFormat)
.build()
val response = openAi.chat().completions().create(params) |
Yeah, so we ultimately want to provide a Python and TS like experience It would probably look like passing a Java class, perhaps with some annotations, and then we'd automatically convert it to a JSON schema for you No ETA yet, but we will definitely do something like this |
ResponseFormatJsonSchema.JsonSchema.Schema
doesn't have fixed fields
@TomerAberbach Tool calling has the same problem as structured outputs where you cannot specify the schema in Please let me know if you'd prefer I file a new ticket, or if the work would all be bundled together. I suspect the fix for both looks pretty similar. |
Yeah, I would say tooling calling fits under this same issue To clarify though, you can specify the schema in |
That's correct. It needs the same Thanks for all your help triaging these! |
As we can see on https://platform.openai.com/docs/guides/structured-outputs?context=without_parse (see How to use > Manual schema > Step 2), the payload looks something like this:
Currently, only
additionalProperties
is available at theschema
level (notype
,properties
,items
,required
, ...)Is this still WIP, or any plan about this? I'm also ok to open a PR to add it if it can help (and no one is already working on it)
The text was updated successfully, but these errors were encountered: