OpenAI Structured Outputs and Zod and zod-to-json-schema

As developers, we often face the challenge of ensuring that AI-generated responses adhere to specific formats. Whether you’re extracting structured data from unstructured inputs or generating outputs that fit a precise schema, having control over the response structure is crucial. This is where OpenAI’s Structured Outputs feature comes into play, offering the ability to enforce JSON Schemas on model outputs.

Thank me by sharing on Twitter 🙏

Combining this with the powerful Zod validation library and the zod-to-json-schema converter in TypeScript, we can create strong, type-safe schemas that ensure the consistency and reliability of our API responses. In this post, I’ll guide you through how to leverage Structured Outputs with Zod to build robust AI-driven applications.

Understanding Structured Outputs in the OpenAI API

Before diving into the implementation, it’s important to understand what Structured Outputs are and why they are so valuable. Structured Outputs allow developers to specify a JSON Schema that the AI model must follow when generating responses. This ensures that the output is predictable, well-structured, and ready to be integrated directly into your application without the need for additional processing.

This feature is especially useful in scenarios where you need to extract specific data points, such as when parsing meeting notes for action items, or when dynamically generating UI components based on user input. By using Structured Outputs, you can ensure that the AI’s responses fit seamlessly into your existing systems.

Defining a Zod Schema

To utilize Structured Outputs effectively, you first need to define the structure of the data you expect. Zod is a great choice for this, as it allows you to create schemas that are both type-safe and easy to convert into JSON Schema format.

For example, suppose you want to extract action items from meeting notes. An action item typically consists of a description, an optional due date, and an optional owner. Here’s how you can define this schema using Zod:

TypeScript
import { z } from 'zod';

const ActionItemSchema = z.object({
  description: z.string().describe("Description of the action item."),
  due_date: z.string().nullable().describe("Due date for the action item, can be null if not specified."),
  owner: z.string().nullable().describe("Owner responsible for the action item, can be null if not specified.")
});

const ActionItemsSchema = z.object({
  action_items: z.array(ActionItemSchema).describe("List of action items from the meeting.")
});

In this schema:

  • description is a required string that provides details about the action item.
  • due_date is an optional string that can be null if not provided.
  • owner is also an optional string that can be null if not provided.
  • The action_items array holds multiple ActionItem objects, ensuring that the structure is consistent across all items.

Converting Zod Schema to JSON Schema

Once your Zod schema is defined, the next step is to convert it into a JSON Schema that the OpenAI API can utilize. This is where the zod-to-json-schema package comes in handy. It provides an easy way to transform your Zod schemas into JSON schemas, which can then be enforced by the OpenAI API.

Here’s how to perform the conversion:

TypeScript
import { zodToJsonSchema } from 'zod-to-json-schema';

const jsonSchema = zodToJsonSchema(ActionItemsSchema, "action_items_schema");

console.log(JSON.stringify(jsonSchema, null, 2));

The zodToJsonSchema function takes your Zod schema and converts it into a JSON Schema format. This JSON Schema is what you’ll pass to the OpenAI API, ensuring that the responses you receive will strictly adhere to the structure you’ve defined.

Integrating the JSON Schema with the OpenAI API

With the JSON Schema in hand, you’re ready to integrate it into your OpenAI API requests. By passing this schema as part of your request, you can ensure that the AI model’s responses conform exactly to the structure you’ve specified.

Here’s how to make a request to the OpenAI API using the generated JSON Schema:

TypeScript
import OpenAI from 'openai';

const client = new OpenAI();

const completion = await client.chat.completions.create({
  model: 'gpt-4o-2024-08-06',
  messages: [
    { role: 'system', content: 'You are a helpful assistant.' },
    { role: 'user', content: 'Extract action items, due dates, and owners from meeting notes.' }
  ],
  response_format: {
    type: 'json_schema',
    json_schema: jsonSchema
  }
});

console.log(completion.choices[0].message);

In this example:

  • The model gpt-4o-2024-08-06 is used, which supports Structured Outputs.
  • The messages array contains the system prompt and the user’s query.
  • The response_format parameter includes the JSON Schema we generated, ensuring that the API response matches the structure we’ve defined.

Conclusion

Using Structured Outputs in the OpenAI API, combined with Zod and zod-to-json-schema, provides a powerful way to ensure that AI-generated responses conform to your application’s specific requirements. By defining your schemas in Zod, converting them to JSON Schema, and integrating them with the OpenAI API, you can build applications that are both reliable and maintainable.

This approach streamlines the process of handling AI outputs, making it easier to incorporate them into complex systems where consistency and structure are key. As AI technology continues to evolve, these tools will be invaluable in creating sophisticated, AI-driven applications that meet the high standards of modern development.

Share this:

Leave a Reply