Structured outputs ensure that the model’s response conforms exactly to your specified schema. This is essential for applications that need reliable, parseable data. The Responses API supports structured outputs for both text responses and function calling.
client = 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)
3
Access the parsed objects
The response automatically deserializes into your model instances:
response .output .flat_map { _1.content } .grep_v(OpenAI::Models::Responses::ResponseOutputRefusal) .each do |content| # content.parsed is an instance of CalendarEvent pp(content.parsed) end
Define tools as BaseModel classes and get type-safe function call arguments:
#!/usr/bin/env ruby# frozen_string_literal: truerequire_relative "../lib/openai"class GetWeather < OpenAI::BaseModel required :location, String, doc: "City and country e.g. Bogotá, Colombia"end# gets API Key from environment variable `OPENAI_API_KEY`client = 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
response .output .flat_map { _1.content } .grep_v(OpenAI::Models::Responses::ResponseOutputRefusal) .each do |content| # content.parsed is an instance of your BaseModel class pp(content.parsed) end
stream.each do |event| case event when OpenAI::Streaming::ResponseTextDoneEvent # event.parsed contains the complete parsed object pp(event.parsed) endend# Or get from the final responseresponse = stream.get_final_responseresponse.output.flat_map { _1.content }.each do |content| pp(content.parsed)end
response.output.each do |output| case output when OpenAI::Models::Responses::ResponseFunctionToolCall # output.parsed is an instance of your tool's BaseModel class pp(output.parsed) endend
Use descriptive field names: Make it easy for the model to understand what each field represents
Add documentation: Use the doc parameter for complex or ambiguous fields
Choose appropriate types: Use enums for constrained values, unions for flexible types
Handle refusals: Always filter out ResponseOutputRefusal when processing outputs
Validate complex structures: For deeply nested models, test with various inputs to ensure reliability
Structured outputs are guaranteed to match your schema exactly. The model cannot deviate from the specified structure, making this ideal for production applications that require reliable data formats.