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.
NexiGo N60 1080P Webcam with Microphone, Adjustable FOV, Zoom, Software Control & Privacy Cover, USB HD Computer Web Camera, Plug and Play, for Zoom/Skype/Teams, Conferencing and Video Calling
$29.99 (as of January 23, 2025 11:35 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Why Machines Learn: The Elegant Math Behind Modern AI
$25.80 (as of January 23, 2025 11:35 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Python Crash Course, 3rd Edition: A Hands-On, Project-Based Introduction to Programming
$28.99 (as of January 23, 2025 11:35 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)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:
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 benull
if not provided.owner
is also an optional string that can benull
if not provided.- The
action_items
array holds multipleActionItem
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:
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:
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.