Skip to content
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

Feat: Structured Outputs #225

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open

Feat: Structured Outputs #225

wants to merge 25 commits into from

Conversation

andgordio
Copy link

What

Adds support for Structured Outputs.

Why

From the official guides:

Structured Outputs is a feature that ensures the model will always generate responses that adhere to your supplied JSON Schema, so you don't need to worry about the model omitting a required key, or hallucinating an invalid enum value.

Affected Areas

  • Extends ChatQuery.ResponseFormat

@andgordio andgordio marked this pull request as draft August 29, 2024 18:48
@andgordio andgordio marked this pull request as ready for review August 30, 2024 21:16
andgordio and others added 3 commits October 8, 2024 08:43
Copy link

sonarqubecloud bot commented Oct 8, 2024

Copy link

@horsejockey horsejockey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me.

@sirily11
Copy link

I wonder how to include a description on each field? This might be helpful for schema generation similar to openai api spec.

@andgordio
Copy link
Author

andgordio commented Oct 29, 2024

I wonder how to include a description on each field? This might be helpful for schema generation similar to openai api spec.

@sirily11 I haven’t found a way to incorporate descriptions into the protocol without requiring an explicit schema design or relying on code generation tools. The proposed solution instead leverages descriptive property names and the context provided within the prompt itself. This approach has consistently worked well for my (admittedly limited) use cases.

While it’s a trade-off, I believe this approach is preferable to a more complex and maintenance-heavy solution that would require defining an explicit schema (including all nested objects). For example:

extension MovieInfo: StructuredOutput {
    static var structuredData: [StructuredOutputData<MovieInfo>] {
        [
            StructuredOutputData(
                keyPath: \.title,
                name: "title",
                description: "Description of the title property",
                type: String.self
            ),
            StructuredOutputData(
                keyPath: \.director,
                name: "director",
                description: "Description of the director property",
                type: String.self
            ),
            StructuredOutputData(
                keyPath: \.release,
                name: "release",
                description: "Description of the release property",
                type: Date.self
            ),
            StructuredOutputData(
                keyPath: \.cast,
                name: "cast",
                description: "Description of the cast property",
                type: Array<String>.self
            ),
        ]
    }
}

Here’s the proposed alternative API for comparison:

extension MovieInfo: StructuredOutput {
    static let example: Self = {
        .init(
            title: "Earth",
            director: "Alexander Dovzhenko",
            release: Calendar.current.date(from: DateComponents(year: 1930, month: 4, day: 1))!,
            cast: ["Stepan Shkurat", "Semyon Svashenko", "Yuliya Solntseva"]
        )
    }()
}

@sirily11
Copy link

sirily11 commented Nov 5, 2024

I wonder how to include a description on each field? This might be helpful for schema generation similar to openai api spec.

@sirily11 I haven’t found a way to incorporate descriptions into the protocol without requiring an explicit schema design or relying on code generation tools. The proposed solution instead leverages descriptive property names and the context provided within the prompt itself. This approach has consistently worked well for my (admittedly limited) use cases.

While it’s a trade-off, I believe this approach is preferable to a more complex and maintenance-heavy solution that would require defining an explicit schema (including all nested objects). For example:

extension MovieInfo: StructuredOutput {
    static var structuredData: [StructuredOutputData<MovieInfo>] {
        [
            StructuredOutputData(
                keyPath: \.title,
                name: "title",
                description: "Description of the title property",
                type: String.self
            ),
            StructuredOutputData(
                keyPath: \.director,
                name: "director",
                description: "Description of the director property",
                type: String.self
            ),
            StructuredOutputData(
                keyPath: \.release,
                name: "release",
                description: "Description of the release property",
                type: Date.self
            ),
            StructuredOutputData(
                keyPath: \.cast,
                name: "cast",
                description: "Description of the cast property",
                type: Array<String>.self
            ),
        ]
    }
}

Here’s the proposed alternative API for comparison:

extension MovieInfo: StructuredOutput {
    static let example: Self = {
        .init(
            title: "Earth",
            director: "Alexander Dovzhenko",
            release: Calendar.current.date(from: DateComponents(year: 1930, month: 4, day: 1))!,
            cast: ["Stepan Shkurat", "Semyon Svashenko", "Yuliya Solntseva"]
        )
    }()
}

I have an idea using swift macro. The schema defination could be simplified to

@Schema
class MyModel {

@Property(description: "Some description", example: "Hello world")
let name: String
}

This proposed API similar to Swift Data package which minimize the required code to write the schema as well as provides the similar API compares to the Python and JS official examples.

@Prince2k3
Copy link

When will this be merged? I am in need of this PR

@DanielhCarranza
Copy link

When will this be merged? I am in need of this PR

This repo moves too slow, you may need to fork it and apply the changes, otherwise you will wait until eternity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants