-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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 handling of JSON Schema in OpenAI API Response Context #819
Improve handling of JSON Schema in OpenAI API Response Context #819
Conversation
eiixy
commented
Aug 7, 2024
•
edited
Loading
edited
- add: jsonschema.Unmarshal
- add: jsonschema.Validate
- add: jsonschema.GenerateSchemaForType
- update: openai.ChatCompletionResponseFormatJSONSchema
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #819 +/- ##
==========================================
+ Coverage 98.46% 99.01% +0.55%
==========================================
Files 24 26 +2
Lines 1364 1418 +54
==========================================
+ Hits 1343 1404 +61
+ Misses 15 8 -7
Partials 6 6 ☔ View full report in Codecov by Sentry. |
jsonschema/json.go
Outdated
return string(bytes) | ||
} | ||
|
||
func Warp[T any](v T) SchemaWrapper[T] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eiixy heads up: I think you meant Wrap
instead of Warp
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or even better: GenerateSchemaForType
jsonschema/json.go
Outdated
} | ||
d.Required = requiredFields | ||
d.Properties = properties | ||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest we either return an error or panic here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the suggestion!
api_integration_test.go
Outdated
KebabCase string `json:"kebab_case" required:"true" description:"KebabCase"` | ||
SnakeCase string `json:"snake_case" required:"true" description:"SnakeCase"` | ||
} | ||
schema := jsonschema.Warp(MyStructuredResponse{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great stuff, I guess we should put a proper README example on how to use this. That should be one of the top examples for sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added an example use case from OpenAI documentation to the README. For reference, please see: https://platform.openai.com/docs/guides/structured-outputs/examples
jsonschema/json.go
Outdated
@@ -53,3 +58,90 @@ func (d Definition) MarshalJSON() ([]byte, error) { | |||
Alias: (Alias)(d), | |||
}) | |||
} | |||
|
|||
type SchemaWrapper[T any] struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pardon my ignorance: do we even need this type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SchemaWrapper
type is intended to bind the Definition
and type
together to ensure consistency during unmarshalling. This way, the schema’s type remains aligned with the initial definition, reducing the risk of errors or mismatches during data handling.
sw, err := jsonschema.Wrap(MyStructuredResponse{})
result, err := sw.Unmarshal(`{...}`)
or
var result MyStructuredResponse{}
schema, err := jsonschema.GenerateSchemaForType(result)
schema.Unmarshal(`{...}`, &result)
Great work, super excited for this! |
If this PR is not going to be finished soon, would it be possible to lift the small change to Also, I feel that using
|
@sashabaranov @gspeicher I have updated the PR status to "ready." Please review the latest changes and let me know if there are any further adjustments needed. Thank you for your suggestions and patience! |
@eiixy thanks for pulling this together quickly. My feedback is centered around
|
type Result struct {
Steps []struct {
Explanation string `json:"explanation"`
Output string `json:"output"`
} `json:"steps"`
FinalAnswer string `json:"final_answer"`
}
sw, err := jsonschema.Wrap(Result{})
if err != nil {
log.Fatalf("JSONSchema Wrap error: %v", err)
}
resp, err := client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
Model: openai.GPT4oMini,
Messages: []openai.ChatCompletionMessage{
{
Role: openai.ChatMessageRoleSystem,
Content: "You are a helpful math tutor. Guide the user through the solution step by step.",
},
{
Role: openai.ChatMessageRoleUser,
Content: "how can I solve 8x + 7 = -23",
},
},
ResponseFormat: &openai.ChatCompletionResponseFormat{
Type: openai.ChatCompletionResponseFormatTypeJSONSchema,
JSONSchema: &openai.ChatCompletionResponseFormatJSONSchema{
Name: "math_reasoning",
Schema: sw,
Strict: true,
},
},
})
if err != nil {
log.Fatalf("CreateChatCompletion error: %v", err)
}
result, err := sw.Unmarshal(resp.Choices[0].Message.Content)
if err != nil {
log.Fatalf("Unmarshal error: %v", err)
} |
Taking your example and converting it to use
would become:
Again, this is not my library so I defer to @sashabaranov but I personally don't see the point in including that alternative since the standard Having said that, I'm chomping at the bit to see this PR get merged and start using Structured Output so I'm not going to die on this hill. |
I've removed the |
_, ok := data.(string) | ||
return ok | ||
case Number: // float64 and int | ||
_, ok := data.(float64) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we also support float32 here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work, thank you!!