Define JSON schemas using BaseModel, ArrayOf, EnumOf, and UnionOf helpers for structured responses
The OpenAI Ruby SDK provides helper classes to define JSON schemas for structured outputs and function calling. These helpers make it easy to create type-safe, validated responses from the API.
class CalendarEvent < OpenAI::BaseModel # Location can be either a String or a Location object required :location, OpenAI::UnionOf[String, Location], nil?: trueendclass Response < OpenAI::BaseModel # Value can be string, integer, or array of strings required :value, OpenAI::UnionOf[String, Integer, OpenAI::ArrayOf[String]]end
Here’s a full example showing how to define and use structured outputs:
require "openai"# Define the schemaclass Location < OpenAI::BaseModel required :address, String required :city, String, doc: "City name" required :postal_code, String, nil?: trueendclass Participant < OpenAI::BaseModel required :first_name, String required :last_name, String, nil?: true required :status, OpenAI::EnumOf[:confirmed, :unconfirmed, :tentative]endclass CalendarEvent < OpenAI::BaseModel required :name, String required :date, String required :participants, OpenAI::ArrayOf[Participant] required :optional_participants, OpenAI::ArrayOf[Participant, doc: "who might not show up"], nil?: true required :is_virtual, OpenAI::Boolean required :location, OpenAI::UnionOf[String, Location], nil?: true, doc: "Event location"end# Use with Responses APIclient = OpenAI::Client.newresponse = client.responses.create( model: "gpt-4o-2024-08-06", input: [ {role: :system, content: "Extract the event information."}, { role: :user, content: <<~CONTENT Alice Shah and Lena are going to a science fair on Friday at 123 Main St. in San Diego. They have also invited Jasper Vellani and Talia Groves - Jasper has not responded and Talia said she is thinking about it. CONTENT } ], text: CalendarEvent)response .output .flat_map { _1.content } .grep_v(OpenAI::Models::Responses::ResponseOutputRefusal) .each do |content| # parsed is an instance of CalendarEvent pp(content.parsed) end
You can also use structured outputs with the Chat Completions API:
chat_completion = client.chat.completions.create( model: "gpt-4o-2024-08-06", messages: [ {role: :system, content: "Extract the event information."}, { role: :user, content: "Alice and Bob are meeting on Friday." } ], response_format: CalendarEvent)chat_completion .choices .reject { _1.message.refusal } .each do |choice| # parsed is an instance of CalendarEvent pp(choice.message.parsed) end
class GetWeather < OpenAI::BaseModel required :location, String, doc: "City and country e.g. Bogotá, Colombia"endclient = OpenAI::Client.newresponse = client.responses.create( model: "gpt-4o-2024-08-06", input: [ { role: :user, content: "What's the weather like in Paris today?" } ], tools: [GetWeather])response .output .each do |output| # parsed is an instance of GetWeather pp(output.parsed) end