Repository Public
1# Structured model outputs23> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.45JSON is one of the most widely used formats in the world for applications to exchange data.67Structured Outputs is a feature that ensures the model will always generate responses that adhere to your supplied [JSON Schema](https://json-schema.org/overview/what-is-jsonschema), so you don't need to worry about the model omitting a required key, or hallucinating an invalid enum value.89Some benefits of Structured Outputs include:10111. **Reliable type-safety:** No need to validate or retry incorrectly formatted responses121. **Explicit refusals:** Safety-based model refusals are now programmatically detectable131. **Simpler prompting:** No need for strongly worded prompts to achieve consistent formatting1415In addition to supporting JSON Schema in the REST API, the OpenAI libraries for [Python](https://github.com/openai/openai-python/blob/main/helpers.md#structured-outputs-parsing-helpers) and [JavaScript](https://github.com/openai/openai-node/blob/master/helpers.md#structured-outputs-parsing-helpers) also let you define object schemas using [`pydantic.BaseModel`](https://docs.pydantic.dev/latest/) and [`z.object`](https://zod.dev/) respectively. Below, you can see how to extract information from unstructured text that conforms to a schema defined in code.1617The Ruby SDK supports schemas defined with Sorbet `T::Struct` and returns typed parsed results.18192021Getting a structured response2223```javascript24import OpenAI from "openai";25import { zodTextFormat } from "openai/helpers/zod";26import { z } from "zod";2728const openai = new OpenAI();2930const CalendarEvent = z.object({31 name: z.string(),32 date: z.string(),33 participants: z.array(z.string()),34});3536const response = await openai.responses.parse({37 model: "gpt-6-astra",38 input: [39 { role: "system", content: "Extract the event information." },40 {41 role: "user",42 content: "Alice and Bob are going to a science fair on Friday.",43 },44 ],45 text: {46 format: zodTextFormat(CalendarEvent, "event"),47 },48});4950const event = response.output_parsed;51```5253```python54from openai import OpenAI55from pydantic import BaseModel5657client = OpenAI()585960class CalendarEvent(BaseModel):61 name: str62 date: str63 participants: list[str]646566response = client.responses.parse(67 model="gpt-6-astra",68 input=[69 {"role": "system", "content": "Extract the event information."},70 {71 "role": "user",72 "content": "Alice and Bob are going to a science fair on Friday.",73 },74 ],75 text_format=CalendarEvent,76)7778event = response.output_parsed79```8081```go82package main8384import (85 "context"86 "fmt"8788 "github.com/openai/openai-go/v3"89 "github.com/openai/openai-go/v3/responses"90)9192func main() {93 client := openai.NewClient()94 schema := map[string]any{95 "type": "object",96 "properties": map[string]any{97 "name": map[string]any{"type": "string"},98 "date": map[string]any{"type": "string"},99 "participants": map[string]any{"type": "array", "items": map[string]any{"type": "string"}},100 },101 "required": []string{"name", "date", "participants"},102 "additionalProperties": false,103 }104105 response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{106 Model: "gpt-6-astra",107 Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{108 responses.ResponseInputItemParamOfMessage(109 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("Extract the event information.")},110 responses.EasyInputMessageRoleSystem,111 ),112 responses.ResponseInputItemParamOfMessage(113 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("Alice and Bob are going to a science fair on Friday.")},114 responses.EasyInputMessageRoleUser,115 ),116 }},117 Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{118 OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "event", Schema: schema, Strict: openai.Bool(true)},119 }},120 })121 if err != nil {122 panic(err)123 }124125 fmt.Println(response.OutputText())126}127```128129```java130import com.openai.client.OpenAIClient;131import com.openai.client.okhttp.OpenAIOkHttpClient;132import com.openai.core.JsonValue;133import com.openai.models.responses.EasyInputMessage;134import com.openai.models.responses.ResponseCreateParams;135import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;136import com.openai.models.responses.ResponseInputItem;137import com.openai.models.responses.ResponseTextConfig;138import java.util.List;139import java.util.Map;140141Map<String, Object> schema =142 Map.of(143 "type",144 "object",145 "properties",146 Map.of(147 "name", Map.of("type", "string"),148 "date", Map.of("type", "string"),149 "participants", Map.of("type", "array", "items", Map.of("type", "string"))),150 "required",151 List.of("name", "date", "participants"),152 "additionalProperties",153 false);154155ResponseCreateParams params =156 ResponseCreateParams.builder()157 .model("gpt-6-astra")158 .inputOfResponse(159 List.of(160 ResponseInputItem.ofEasyInputMessage(161 EasyInputMessage.builder()162 .role(EasyInputMessage.Role.SYSTEM)163 .content("Extract the event information.")164 .build()),165 ResponseInputItem.ofEasyInputMessage(166 EasyInputMessage.builder()167 .role(EasyInputMessage.Role.USER)168 .content("Alice and Bob are going to a science fair on Friday.")169 .build())))170 .text(171 ResponseTextConfig.builder()172 .format(173 ResponseFormatTextJsonSchemaConfig.builder()174 .name("event")175 .strict(true)176 .schema(177 JsonValue.from(schema)178 .convert(ResponseFormatTextJsonSchemaConfig.Schema.class))179 .build())180 .build())181 .build();182183client.responses().create(params).output().stream()184 .flatMap(item -> item.message().stream())185 .flatMap(message -> message.content().stream())186 .flatMap(content -> content.outputText().stream())187 .forEach(text -> System.out.println(text.text()));188```189190```csharp191using OpenAI.Responses;192#pragma warning disable OPENAI001193194string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;195ResponsesClient client = new(key);196197BinaryData schema = BinaryData.FromString(198 """199 {200 "type": "object",201 "properties": {202 "name": { "type": "string" },203 "date": { "type": "string" },204 "participants": {205 "type": "array",206 "items": { "type": "string" }207 }208 },209 "required": ["name", "date", "participants"],210 "additionalProperties": false211 }212 """213);214CreateResponseOptions options = new()215{216 Model = "gpt-6-astra",217 TextOptions = new ResponseTextOptions218 {219 TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(220 "event",221 schema,222 jsonSchemaIsStrict: true223 ),224 },225};226options.InputItems.Add(227 ResponseItem.CreateSystemMessageItem("Extract the event information.")228);229options.InputItems.Add(230 ResponseItem.CreateUserMessageItem(231 "Alice and Bob are going to a science fair on Friday."232 )233);234235ResponseResult response = await client.CreateResponseAsync(options);236237Console.WriteLine(response.GetOutputText());238```239240```ruby241# gem install openai sorbet-runtime242require "openai"243require "openai/helpers/sorbet"244245class CalendarEvent < T::Struct246 const :name, String247 const :date, String248 const :participants, T::Array[String]249end250251client = OpenAI::Client.new252schema = OpenAI::StructuredOutput.from_sorbet(CalendarEvent)253254response = client.responses.create(255 model: "gpt-6-astra",256 input: [257 {258 role: :system,259 content: "Extract the event information."260 },261 {262 role: :user,263 content: "Alice and Bob are going to a science fair on Friday."264 }265 ],266 text: schema267)268269raise "Response ended with status: #{response.status}" unless response.status == OpenAI::Responses::ResponseStatus::COMPLETED270271message = response.output.grep(OpenAI::Responses::ResponseOutputMessage).fetch(0)272output_text = message.content.grep(OpenAI::Responses::ResponseOutputText).first273raise "No structured output returned (the model may have refused)" unless output_text274275event = T.cast(output_text.parsed, CalendarEvent)276puts(event.name, event.date, event.participants.join(", "))277```278279280281### Supported models282283Structured Outputs is available in our [latest large language models](https://developers.openai.com/api/docs/models), starting with GPT-4o. For new projects, start with [`gpt-6-astra`](https://developers.openai.com/api/docs/models/gpt-6-astra). Older models like `gpt-4-turbo` and earlier may use [JSON mode](#json-mode) instead.284285286287288 289290When to use Structured Outputs via function calling vs via 291 292text.format293294295296297Structured Outputs is available in two forms in the OpenAI API:2982991. When using [function calling](https://developers.openai.com/api/docs/guides/function-calling)3002. When using a `json_schema` response format301302Function calling is useful when you are building an application that bridges the models and functionality of your application.303304For example, you can give the model access to functions that query a database in order to build an AI assistant that can help users with their orders, or functions that can interact with the UI.305306Conversely, Structured Outputs via `response_format` are more suitable when you want to indicate a structured schema for use when the model responds to the user, rather than when the model calls a tool.307308For example, if you are building a math tutoring application, you might want the assistant to respond to your user using a specific JSON Schema so that you can generate a UI that displays different parts of the model's output in distinct ways.309310In practice:311312313314315 - If you are connecting the model to tools, functions, data, etc. in your316 system, then you should use function calling - If you want to structure the317 model's output when it responds to the user, then you should use a structured318 `text.format`319320321322323324 The remainder of this guide will focus on non-function calling use cases in325 the Responses API. To learn more about how to use Structured Outputs with326 function calling, check out the 327 [Function Calling](https://developers.openai.com/api/docs/guides/function-calling#strict-mode) 328 guide.329330331### Structured Outputs vs JSON mode332333Structured Outputs is the evolution of [JSON mode](#json-mode). While both ensure valid JSON is produced, only Structured Outputs ensure schema adherence. Both Structured Outputs and JSON mode are supported in the Responses API, Chat Completions API, Assistants API, Fine-tuning API and Batch API.334335We recommend always using Structured Outputs instead of JSON mode when possible.336337However, Structured Outputs with `response_format: {type: "json_schema", ...}` is only supported with the `gpt-4o-mini`, `gpt-4o-mini-2024-07-18`, and `gpt-4o-2024-08-06` model snapshots and later.338339340341342| | Structured Outputs | JSON Mode |343|--------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------|344| **Outputs valid JSON** | Yes | Yes |345| **Adheres to schema** | Yes (see [supported schemas](#supported-schemas)) | No |346| **Compatible models** | `gpt-4o-mini`, `gpt-4o-2024-08-06`, and later | `gpt-3.5-turbo`, `gpt-4-*`, `gpt-4o-*`, and compatible GPT-5 models |347| **Enabling** | `text: { format: { type: "json_schema", "strict": true, "schema": ... } }` | `text: { format: { type: "json_object" } }` |348349350## Examples351352353354Chain of thought355356 357358### Chain of thought359360You can ask the model to output an answer in a structured, step-by-step way, to guide the user through the solution.361362363364365 Structured Outputs for chain-of-thought math tutoring366367```javascript368import OpenAI from "openai";369import { zodTextFormat } from "openai/helpers/zod";370import { z } from "zod";371372const openai = new OpenAI();373374const Step = z.object({375 explanation: z.string(),376 output: z.string(),377});378379const MathReasoning = z.object({380 steps: z.array(Step),381 final_answer: z.string(),382});383384const response = await openai.responses.parse({385 model: "gpt-6-astra",386 input: [387 {388 role: "system",389 content:390 "You are a helpful math tutor. Guide the user through the solution step by step.",391 },392 { role: "user", content: "how can I solve 8x + 7 = -23" },393 ],394 text: {395 format: zodTextFormat(MathReasoning, "math_reasoning"),396 },397});398399const math_reasoning = response.output_parsed;400```401402```python403from openai import OpenAI404from pydantic import BaseModel405406client = OpenAI()407408409class Step(BaseModel):410 explanation: str411 output: str412413414class MathReasoning(BaseModel):415 steps: list[Step]416 final_answer: str417418419response = client.responses.parse(420 model="gpt-6-astra",421 input=[422 {423 "role": "system",424 "content": "You are a helpful math tutor. Guide the user through the solution step by step.",425 },426 {"role": "user", "content": "how can I solve 8x + 7 = -23"},427 ],428 text_format=MathReasoning,429)430431math_reasoning = response.output_parsed432```433434```go435package main436437import (438 "context"439 "fmt"440441 "github.com/openai/openai-go/v3"442 "github.com/openai/openai-go/v3/responses"443)444445func main() {446 client := openai.NewClient()447 step := map[string]any{448 "type": "object",449 "properties": map[string]any{450 "explanation": map[string]any{"type": "string"},451 "output": map[string]any{"type": "string"},452 },453 "required": []string{"explanation", "output"},454 "additionalProperties": false,455 }456 schema := map[string]any{457 "type": "object",458 "properties": map[string]any{459 "steps": map[string]any{"type": "array", "items": step},460 "final_answer": map[string]any{"type": "string"},461 },462 "required": []string{"steps", "final_answer"},463 "additionalProperties": false,464 }465466 response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{467 Model: "gpt-6-astra",468 Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{469 responses.ResponseInputItemParamOfMessage(470 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are a helpful math tutor. Guide the user through the solution step by step.")},471 responses.EasyInputMessageRoleSystem,472 ),473 responses.ResponseInputItemParamOfMessage(474 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("how can I solve 8x + 7 = -23")},475 responses.EasyInputMessageRoleUser,476 ),477 }},478 Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{479 OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "math_reasoning", Schema: schema, Strict: openai.Bool(true)},480 }},481 })482 if err != nil {483 panic(err)484 }485486 fmt.Println(response.OutputText())487}488```489490```java491import com.openai.client.OpenAIClient;492import com.openai.client.okhttp.OpenAIOkHttpClient;493import com.openai.core.JsonValue;494import com.openai.models.responses.EasyInputMessage;495import com.openai.models.responses.ResponseCreateParams;496import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;497import com.openai.models.responses.ResponseInputItem;498import com.openai.models.responses.ResponseTextConfig;499import java.util.List;500import java.util.Map;501502Map<String, Object> schema =503 Map.of(504 "type",505 "object",506 "properties",507 Map.of(508 "steps",509 Map.of(510 "type",511 "array",512 "items",513 Map.of(514 "type",515 "object",516 "properties",517 Map.of(518 "explanation", Map.of("type", "string"),519 "output", Map.of("type", "string")),520 "required",521 List.of("explanation", "output"),522 "additionalProperties",523 false)),524 "final_answer", Map.of("type", "string")),525 "required",526 List.of("steps", "final_answer"),527 "additionalProperties",528 false);529530ResponseCreateParams params =531 ResponseCreateParams.builder()532 .model("gpt-6-astra")533 .inputOfResponse(534 List.of(535 ResponseInputItem.ofEasyInputMessage(536 EasyInputMessage.builder()537 .role(EasyInputMessage.Role.SYSTEM)538 .content(539 "You are a helpful math tutor. Guide the user through the solution step by step.")540 .build()),541 ResponseInputItem.ofEasyInputMessage(542 EasyInputMessage.builder()543 .role(EasyInputMessage.Role.USER)544 .content("How can I solve 8x + 7 = -23?")545 .build())))546 .text(547 ResponseTextConfig.builder()548 .format(549 ResponseFormatTextJsonSchemaConfig.builder()550 .name("math_reasoning")551 .strict(true)552 .schema(553 JsonValue.from(schema)554 .convert(ResponseFormatTextJsonSchemaConfig.Schema.class))555 .build())556 .build())557 .build();558559client.responses().create(params).output().stream()560 .flatMap(item -> item.message().stream())561 .flatMap(message -> message.content().stream())562 .flatMap(content -> content.outputText().stream())563 .forEach(text -> System.out.println(text.text()));564```565566```csharp567using System.Text.Json;568using OpenAI.Responses;569#pragma warning disable OPENAI001570571string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;572ResponsesClient client = new(key);573574BinaryData schema = BinaryData.FromString(575 """576 {577 "type": "object",578 "properties": {579 "steps": {580 "type": "array",581 "items": {582 "type": "object",583 "properties": {584 "explanation": { "type": "string" },585 "output": { "type": "string" }586 },587 "required": ["explanation", "output"],588 "additionalProperties": false589 }590 },591 "final_answer": { "type": "string" }592 },593 "required": ["steps", "final_answer"],594 "additionalProperties": false595 }596 """597);598CreateResponseOptions options = new()599{600 Model = "gpt-6-astra",601 TextOptions = new ResponseTextOptions602 {603 TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(604 "math_response",605 schema,606 jsonSchemaIsStrict: true607 ),608 },609};610options.InputItems.Add(ResponseItem.CreateSystemMessageItem("You are a helpful math tutor. Guide the user through the solution step by step."));611options.InputItems.Add(ResponseItem.CreateUserMessageItem("How can I solve 8x + 7 = -23?"));612613ResponseResult response = await client.CreateResponseAsync(options);614using JsonDocument parsed = JsonDocument.Parse(response.GetOutputText());615Console.WriteLine(parsed.RootElement);616```617618```ruby619require "openai"620621client = OpenAI::Client.new622step_schema = {623 type: :object,624 properties: {625 explanation: { type: :string },626 output: { type: :string }627 },628 required: %w[explanation output],629 additionalProperties: false630}631math_schema = {632 type: :object,633 properties: {634 steps: {635 type: :array,636 items: step_schema637 },638 final_answer: { type: :string }639 },640 required: %w[steps final_answer],641 additionalProperties: false642}643644response = client.responses.create(645 model: "gpt-6-astra",646 input: [647 {648 role: :system,649 content: "You are a helpful math tutor. Guide the user through the solution step by step."650 },651 {652 role: :user,653 content: "How can I solve 8x + 7 = -23?"654 }655 ],656 text: {657 format: {658 type: :json_schema,659 name: "math_reasoning",660 strict: true,661 schema: math_schema662 }663 }664)665666puts(response.output_text)667```668669```bash670curl https://api.openai.com/v1/responses \671 -H "Authorization: Bearer $OPENAI_API_KEY" \672 -H "Content-Type: application/json" \673 -d '{674 "model": "gpt-6-astra",675 "input": [676 {677 "role": "system",678 "content": "You are a helpful math tutor. Guide the user through the solution step by step."679 },680 {681 "role": "user",682 "content": "how can I solve 8x + 7 = -23"683 }684 ],685 "text": {686 "format": {687 "type": "json_schema",688 "name": "math_reasoning",689 "schema": {690 "type": "object",691 "properties": {692 "steps": {693 "type": "array",694 "items": {695 "type": "object",696 "properties": {697 "explanation": { "type": "string" },698 "output": { "type": "string" }699 },700 "required": ["explanation", "output"],701 "additionalProperties": false702 }703 },704 "final_answer": { "type": "string" }705 },706 "required": ["steps", "final_answer"],707 "additionalProperties": false708 },709 "strict": true710 }711 }712 }'713```714715716717#### Example response718719```json720{721 "steps": [722 {723 "explanation": "Start with the equation 8x + 7 = -23.",724 "output": "8x + 7 = -23"725 },726 {727 "explanation": "Subtract 7 from both sides to isolate the term with the variable.",728 "output": "8x = -23 - 7"729 },730 {731 "explanation": "Simplify the right side of the equation.",732 "output": "8x = -30"733 },734 {735 "explanation": "Divide both sides by 8 to solve for x.",736 "output": "x = -30 / 8"737 },738 {739 "explanation": "Simplify the fraction.",740 "output": "x = -15 / 4"741 }742 ],743 "final_answer": "x = -15 / 4"744}745```746747748 749750 751752 753Structured data extraction754755 756757### Structured data extraction758759You can define structured fields to extract from unstructured input data, such as research papers.760761762763 Extracting data from research papers using Structured Outputs764765```javascript766import OpenAI from "openai";767import { zodTextFormat } from "openai/helpers/zod";768import { z } from "zod";769770const openai = new OpenAI();771772const ResearchPaperExtraction = z.object({773 title: z.string(),774 authors: z.array(z.string()),775 abstract: z.string(),776 keywords: z.array(z.string()),777});778779const response = await openai.responses.parse({780 model: "gpt-6-astra",781 input: [782 {783 role: "system",784 content:785 "You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure.",786 },787 { role: "user", content: "..." },788 ],789 text: {790 format: zodTextFormat(ResearchPaperExtraction, "research_paper_extraction"),791 },792});793794const research_paper = response.output_parsed;795```796797```python798from openai import OpenAI799from pydantic import BaseModel800801client = OpenAI()802803804class ResearchPaperExtraction(BaseModel):805 title: str806 authors: list[str]807 abstract: str808 keywords: list[str]809810811response = client.responses.parse(812 model="gpt-6-astra",813 input=[814 {815 "role": "system",816 "content": "You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure.",817 },818 {819 "role": "user",820 "content": (821 "Attention Is All You Need by Ashish Vaswani, Noam Shazeer, "822 "Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, "823 "Łukasz Kaiser, and Illia Polosukhin. We propose the "824 "Transformer, a sequence transduction architecture based "825 "entirely on attention. Keywords: transformers, attention, "826 "sequence transduction."827 ),828 },829 ],830 text_format=ResearchPaperExtraction,831)832833research_paper = response.output_parsed834```835836```go837package main838839import (840 "context"841 "fmt"842843 "github.com/openai/openai-go/v3"844 "github.com/openai/openai-go/v3/responses"845)846847const researchPaperText = "Attention Is All You Need by Ashish Vaswani, Noam Shazeer, " +848 "Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, " +849 "Łukasz Kaiser, and Illia Polosukhin. We propose the Transformer, " +850 "a sequence transduction architecture based entirely on attention. " +851 "Keywords: transformers, attention, sequence transduction."852853func main() {854 client := openai.NewClient()855 schema := map[string]any{856 "type": "object",857 "properties": map[string]any{858 "title": map[string]any{"type": "string"},859 "authors": map[string]any{"type": "array", "items": map[string]any{"type": "string"}},860 "abstract": map[string]any{"type": "string"},861 "keywords": map[string]any{"type": "array", "items": map[string]any{"type": "string"}},862 },863 "required": []string{"title", "authors", "abstract", "keywords"},864 "additionalProperties": false,865 }866867 response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{868 Model: "gpt-6-astra",869 Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{870 responses.ResponseInputItemParamOfMessage(871 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure.")},872 responses.EasyInputMessageRoleSystem,873 ),874 responses.ResponseInputItemParamOfMessage(875 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText(researchPaperText)},876 responses.EasyInputMessageRoleUser,877 ),878 }},879 Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{880 OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "research_paper_extraction", Schema: schema, Strict: openai.Bool(true)},881 }},882 })883 if err != nil {884 panic(err)885 }886887 fmt.Println(response.OutputText())888}889```890891```java892import com.openai.client.OpenAIClient;893import com.openai.client.okhttp.OpenAIOkHttpClient;894import com.openai.core.JsonValue;895import com.openai.models.responses.EasyInputMessage;896import com.openai.models.responses.ResponseCreateParams;897import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;898import com.openai.models.responses.ResponseInputItem;899import com.openai.models.responses.ResponseTextConfig;900import java.util.List;901import java.util.Map;902903Map<String, Object> schema =904 Map.of(905 "type",906 "object",907 "properties",908 Map.of(909 "title", Map.of("type", "string"),910 "authors", Map.of("type", "array", "items", Map.of("type", "string")),911 "abstract", Map.of("type", "string"),912 "keywords", Map.of("type", "array", "items", Map.of("type", "string"))),913 "required",914 List.of("title", "authors", "abstract", "keywords"),915 "additionalProperties",916 false);917918ResponseCreateParams params =919 ResponseCreateParams.builder()920 .model("gpt-6-astra")921 .inputOfResponse(922 List.of(923 ResponseInputItem.ofEasyInputMessage(924 EasyInputMessage.builder()925 .role(EasyInputMessage.Role.SYSTEM)926 .content(927 "You are an expert at structured data extraction. You will be given"928 + " unstructured text from a research paper and should convert"929 + " it into the given structure.")930 .build()),931 ResponseInputItem.ofEasyInputMessage(932 EasyInputMessage.builder()933 .role(EasyInputMessage.Role.USER)934 .content(935 "Attention Is All You Need by Ashish Vaswani, Noam Shazeer,"936 + " Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez,"937 + " Łukasz Kaiser, and Illia Polosukhin. We propose the"938 + " Transformer, a"939 + " sequence transduction architecture based entirely on"940 + " attention. Keywords: transformers, attention, sequence"941 + " transduction.")942 .build())))943 .text(944 ResponseTextConfig.builder()945 .format(946 ResponseFormatTextJsonSchemaConfig.builder()947 .name("research_paper_extraction")948 .strict(true)949 .schema(950 JsonValue.from(schema)951 .convert(ResponseFormatTextJsonSchemaConfig.Schema.class))952 .build())953 .build())954 .build();955956client.responses().create(params).output().stream()957 .flatMap(item -> item.message().stream())958 .flatMap(message -> message.content().stream())959 .flatMap(content -> content.outputText().stream())960 .forEach(text -> System.out.println(text.text()));961```962963```csharp964using System.Text.Json;965using OpenAI.Responses;966#pragma warning disable OPENAI001967968string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;969ResponsesClient client = new(key);970971BinaryData schema = BinaryData.FromString(972 """973 {974 "type": "object",975 "properties": {976 "title": { "type": "string" },977 "authors": { "type": "array", "items": { "type": "string" } },978 "abstract": { "type": "string" },979 "keywords": { "type": "array", "items": { "type": "string" } }980 },981 "required": ["title", "authors", "abstract", "keywords"],982 "additionalProperties": false983 }984 """985);986CreateResponseOptions options = new()987{988 Model = "gpt-6-astra",989 TextOptions = new ResponseTextOptions990 {991 TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(992 "research_paper",993 schema,994 jsonSchemaIsStrict: true995 ),996 },997};998options.InputItems.Add(ResponseItem.CreateSystemMessageItem("Extract the title, authors, abstract, and keywords from the research paper."));999options.InputItems.Add(1000 ResponseItem.CreateUserMessageItem(1001 """1002 Attention Is All You Need by Ashish Vaswani, Noam Shazeer,1003 Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez,1004 Łukasz Kaiser, and Illia Polosukhin. We propose the1005 Transformer, a sequence transduction architecture based1006 entirely on attention. Keywords: transformers, attention,1007 sequence transduction.1008 """1009 )1010);10111012ResponseResult response = await client.CreateResponseAsync(options);1013using JsonDocument parsed = JsonDocument.Parse(response.GetOutputText());1014Console.WriteLine(parsed.RootElement);1015```10161017```ruby1018require "openai"10191020client = OpenAI::Client.new1021research_paper = <<~TEXT1022 Attention Is All You Need by Ashish Vaswani, Noam Shazeer, Niki Parmar,1023 Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, Łukasz Kaiser, and Illia1024 Polosukhin. We propose the Transformer, a sequence transduction architecture1025 based entirely on attention. Keywords: transformers, attention, sequence1026 transduction.1027TEXT1028paper_schema = {1029 type: :object,1030 properties: {1031 title: { type: :string },1032 authors: {1033 type: :array,1034 items: { type: :string }1035 },1036 abstract: { type: :string },1037 keywords: {1038 type: :array,1039 items: { type: :string }1040 }1041 },1042 required: %w[title authors abstract keywords],1043 additionalProperties: false1044}10451046response = client.responses.create(1047 model: "gpt-6-astra",1048 input: [1049 {1050 role: :system,1051 content: "Extract structured data from the supplied research paper text."1052 },1053 {1054 role: :user,1055 content: research_paper1056 }1057 ],1058 text: {1059 format: {1060 type: :json_schema,1061 name: "research_paper_extraction",1062 strict: true,1063 schema: paper_schema1064 }1065 }1066)10671068puts(response.output_text)1069```10701071```bash1072curl https://api.openai.com/v1/responses \1073 -H "Authorization: Bearer $OPENAI_API_KEY" \1074 -H "Content-Type: application/json" \1075 -d '{1076 "model": "gpt-6-astra",1077 "input": [1078 {1079 "role": "system",1080 "content": "You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure."1081 },1082 {1083 "role": "user",1084 "content": "..."1085 }1086 ],1087 "text": {1088 "format": {1089 "type": "json_schema",1090 "name": "research_paper_extraction",1091 "schema": {1092 "type": "object",1093 "properties": {1094 "title": { "type": "string" },1095 "authors": {1096 "type": "array",1097 "items": { "type": "string" }1098 },1099 "abstract": { "type": "string" },1100 "keywords": {1101 "type": "array",1102 "items": { "type": "string" }1103 }1104 },1105 "required": ["title", "authors", "abstract", "keywords"],1106 "additionalProperties": false1107 },1108 "strict": true1109 }1110 }1111 }'1112```1113111411151116#### Example response11171118```json1119{1120 "title": "Application of Quantum Algorithms in Interstellar Navigation: A New Frontier",1121 "authors": ["Dr. Stella Voyager", "Dr. Nova Star", "Dr. Lyra Hunter"],1122 "abstract": "This paper investigates the utilization of quantum algorithms to improve interstellar navigation systems. By leveraging quantum superposition and entanglement, our proposed navigation system can calculate optimal travel paths through space-time anomalies more efficiently than classical methods. Experimental simulations suggest a significant reduction in travel time and fuel consumption for interstellar missions.",1123 "keywords": [1124 "Quantum algorithms",1125 "interstellar navigation",1126 "space-time anomalies",1127 "quantum superposition",1128 "quantum entanglement",1129 "space travel"1130 ]1131}1132```113311341135 11361137 11381139 1140UI generation11411142 11431144### UI Generation11451146You can generate valid HTML by representing it as recursive data structures with constraints, like enums.11471148114911501151 Generating HTML using Structured Outputs11521153```javascript1154import OpenAI from "openai";1155import { zodTextFormat } from "openai/helpers/zod";1156import { z } from "zod";11571158const openai = new OpenAI();11591160const UI = z.lazy(() =>1161 z.object({1162 type: z.enum(["div", "button", "header", "section", "field", "form"]),1163 label: z.string(),1164 children: z.array(UI),1165 attributes: z.array(1166 z.object({1167 name: z.string(),1168 value: z.string(),1169 })1170 ),1171 })1172);11731174const response = await openai.responses.parse({1175 model: "gpt-6-astra",1176 input: [1177 {1178 role: "system",1179 content: "You are a UI generator AI. Convert the user input into a UI.",1180 },1181 {1182 role: "user",1183 content: "Make a User Profile Form",1184 },1185 ],1186 text: {1187 format: zodTextFormat(UI, "ui"),1188 },1189});11901191const ui = response.output_parsed;1192```11931194```python1195from enum import Enum11961197from openai import OpenAI1198from pydantic import BaseModel11991200client = OpenAI()120112021203class UIType(str, Enum):1204 div = "div"1205 button = "button"1206 header = "header"1207 section = "section"1208 field = "field"1209 form = "form"121012111212class Attribute(BaseModel):1213 name: str1214 value: str121512161217class UI(BaseModel):1218 type: UIType1219 label: str1220 children: list["UI"]1221 attributes: list[Attribute]122212231224UI.model_rebuild() # This is required to enable recursive types122512261227class Response(BaseModel):1228 ui: UI122912301231response = client.responses.parse(1232 model="gpt-6-astra",1233 input=[1234 {1235 "role": "system",1236 "content": "You are a UI generator AI. Convert the user input into a UI.",1237 },1238 {"role": "user", "content": "Make a User Profile Form"},1239 ],1240 text_format=Response,1241)12421243ui = response.output_parsed1244```12451246```go1247package main12481249import (1250 "context"1251 "fmt"12521253 "github.com/openai/openai-go/v3"1254 "github.com/openai/openai-go/v3/responses"1255)12561257func main() {1258 client := openai.NewClient()1259 schema := map[string]any{1260 "type": "object",1261 "properties": map[string]any{1262 "type": map[string]any{"type": "string", "enum": []string{"div", "button", "header", "section", "field", "form"}},1263 "label": map[string]any{"type": "string"},1264 "children": map[string]any{"type": "array", "items": map[string]any{"$ref": "#"}},1265 "attributes": map[string]any{"type": "array", "items": map[string]any{"type": "object", "properties": map[string]any{"name": map[string]any{"type": "string"}, "value": map[string]any{"type": "string"}}, "required": []string{"name", "value"}, "additionalProperties": false}},1266 },1267 "required": []string{"type", "label", "children", "attributes"},1268 "additionalProperties": false,1269 }12701271 response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{1272 Model: "gpt-6-astra",1273 Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{1274 responses.ResponseInputItemParamOfMessage(1275 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are a UI generator AI. Convert the user input into a UI.")},1276 responses.EasyInputMessageRoleSystem,1277 ),1278 responses.ResponseInputItemParamOfMessage(1279 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("Make a User Profile Form")},1280 responses.EasyInputMessageRoleUser,1281 ),1282 }},1283 Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{1284 OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "ui", Description: openai.String("Dynamically generated UI"), Schema: schema, Strict: openai.Bool(true)},1285 }},1286 })1287 if err != nil {1288 panic(err)1289 }12901291 fmt.Println(response.OutputText())1292}1293```12941295```java1296import com.openai.client.OpenAIClient;1297import com.openai.client.okhttp.OpenAIOkHttpClient;1298import com.openai.core.JsonValue;1299import com.openai.models.responses.EasyInputMessage;1300import com.openai.models.responses.ResponseCreateParams;1301import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;1302import com.openai.models.responses.ResponseInputItem;1303import com.openai.models.responses.ResponseTextConfig;1304import java.util.List;1305import java.util.Map;13061307ResponseCreateParams params =1308 ResponseCreateParams.builder()1309 .model("gpt-6-astra")1310 .inputOfResponse(1311 List.of(1312 ResponseInputItem.ofEasyInputMessage(1313 EasyInputMessage.builder()1314 .role(EasyInputMessage.Role.SYSTEM)1315 .content("Convert the user request into a UI definition.")1316 .build()),1317 ResponseInputItem.ofEasyInputMessage(1318 EasyInputMessage.builder()1319 .role(EasyInputMessage.Role.USER)1320 .content("Make a user profile form.")1321 .build())))1322 .text(1323 ResponseTextConfig.builder()1324 .format(1325 ResponseFormatTextJsonSchemaConfig.builder()1326 .name("ui")1327 .description("A dynamically generated UI")1328 .strict(true)1329 .schema(1330 ResponseFormatTextJsonSchemaConfig.Schema.builder()1331 .putAdditionalProperty("type", JsonValue.from("object"))1332 .putAdditionalProperty(1333 "properties",1334 JsonValue.from(1335 Map.of(1336 "type",1337 Map.of(1338 "type",1339 "string",1340 "enum",1341 List.of(1342 "div", "button", "header", "section",1343 "field", "form")),1344 "label", Map.of("type", "string"),1345 "children",1346 Map.of(1347 "type",1348 "array",1349 "items",1350 Map.of("$ref", "#")),1351 "attributes",1352 Map.of(1353 "type",1354 "array",1355 "items",1356 Map.of(1357 "type",1358 "object",1359 "properties",1360 Map.of(1361 "name", Map.of("type", "string"),1362 "value", Map.of("type", "string")),1363 "required",1364 List.of("name", "value"),1365 "additionalProperties",1366 false)))))1367 .putAdditionalProperty(1368 "required",1369 JsonValue.from(1370 List.of("type", "label", "children", "attributes")))1371 .putAdditionalProperty(1372 "additionalProperties", JsonValue.from(false))1373 .build())1374 .build())1375 .build())1376 .build();13771378client.responses().create(params).output().stream()1379 .flatMap(item -> item.message().stream())1380 .flatMap(message -> message.content().stream())1381 .flatMap(content -> content.outputText().stream())1382 .forEach(text -> System.out.println(text.text()));1383```13841385```csharp1386using System.Text.Json;1387using OpenAI.Responses;1388#pragma warning disable OPENAI00113891390string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;1391ResponsesClient client = new(key);13921393BinaryData schema = BinaryData.FromString(1394 """1395 {1396 "type": "object",1397 "properties": {1398 "ui": { "$ref": "#/$defs/component" }1399 },1400 "required": ["ui"],1401 "additionalProperties": false,1402 "$defs": {1403 "component": {1404 "type": "object",1405 "properties": {1406 "type": { "type": "string", "enum": ["div", "button", "header", "section", "field", "form"] },1407 "label": { "type": "string" },1408 "children": { "type": "array", "items": { "$ref": "#/$defs/component" } },1409 "attributes": {1410 "type": "array",1411 "items": {1412 "type": "object",1413 "properties": { "name": { "type": "string" }, "value": { "type": "string" } },1414 "required": ["name", "value"],1415 "additionalProperties": false1416 }1417 }1418 },1419 "required": ["type", "label", "children", "attributes"],1420 "additionalProperties": false1421 }1422 }1423 }1424 """1425);1426CreateResponseOptions options = new()1427{1428 Model = "gpt-6-astra",1429 TextOptions = new ResponseTextOptions1430 {1431 TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(1432 "ui",1433 schema,1434 jsonSchemaIsStrict: true1435 ),1436 },1437};1438options.InputItems.Add(ResponseItem.CreateSystemMessageItem("You are a UI generator. Convert the user request into a component tree."));1439options.InputItems.Add(ResponseItem.CreateUserMessageItem("Make a User Profile Form"));14401441ResponseResult response = await client.CreateResponseAsync(options);1442using JsonDocument parsed = JsonDocument.Parse(response.GetOutputText());1443Console.WriteLine(parsed.RootElement);1444```14451446```ruby1447require "openai"14481449client = OpenAI::Client.new1450ui_schema = {1451 type: :object,1452 properties: {1453 type: {1454 type: :string,1455 enum: %w[div button header section field form]1456 },1457 label: { type: :string },1458 children: {1459 type: :array,1460 items: { "$ref" => "#" }1461 },1462 attributes: {1463 type: :array,1464 items: {1465 type: :object,1466 properties: {1467 name: { type: :string },1468 value: { type: :string }1469 },1470 required: %w[name value],1471 additionalProperties: false1472 }1473 }1474 },1475 required: %w[type label children attributes],1476 additionalProperties: false1477}14781479response = client.responses.create(1480 model: "gpt-6-astra",1481 input: [1482 {1483 role: :system,1484 content: "Convert the user request into a UI definition."1485 },1486 {1487 role: :user,1488 content: "Make a user profile form."1489 }1490 ],1491 text: {1492 format: {1493 type: :json_schema,1494 name: "ui",1495 description: "A dynamically generated UI",1496 strict: true,1497 schema: ui_schema1498 }1499 }1500)15011502puts(response.output_text)1503```15041505```bash1506curl https://api.openai.com/v1/responses \1507 -H "Authorization: Bearer $OPENAI_API_KEY" \1508 -H "Content-Type: application/json" \1509 -d '{1510 "model": "gpt-6-astra",1511 "input": [1512 {1513 "role": "system",1514 "content": "You are a UI generator AI. Convert the user input into a UI."1515 },1516 {1517 "role": "user",1518 "content": "Make a User Profile Form"1519 }1520 ],1521 "text": {1522 "format": {1523 "type": "json_schema",1524 "name": "ui",1525 "description": "Dynamically generated UI",1526 "schema": {1527 "type": "object",1528 "properties": {1529 "type": {1530 "type": "string",1531 "description": "The type of the UI component",1532 "enum": ["div", "button", "header", "section", "field", "form"]1533 },1534 "label": {1535 "type": "string",1536 "description": "The label of the UI component, used for buttons or form fields"1537 },1538 "children": {1539 "type": "array",1540 "description": "Nested UI components",1541 "items": {"$ref": "#"}1542 },1543 "attributes": {1544 "type": "array",1545 "description": "Arbitrary attributes for the UI component, suitable for any element",1546 "items": {1547 "type": "object",1548 "properties": {1549 "name": {1550 "type": "string",1551 "description": "The name of the attribute, for example onClick or className"1552 },1553 "value": {1554 "type": "string",1555 "description": "The value of the attribute"1556 }1557 },1558 "required": ["name", "value"],1559 "additionalProperties": false1560 }1561 }1562 },1563 "required": ["type", "label", "children", "attributes"],1564 "additionalProperties": false1565 },1566 "strict": true1567 }1568 }1569 }'1570```1571157215731574#### Example response15751576```json1577{1578 "type": "form",1579 "label": "User Profile Form",1580 "children": [1581 {1582 "type": "div",1583 "label": "",1584 "children": [1585 {1586 "type": "field",1587 "label": "First Name",1588 "children": [],1589 "attributes": [1590 {1591 "name": "type",1592 "value": "text"1593 },1594 {1595 "name": "name",1596 "value": "firstName"1597 },1598 {1599 "name": "placeholder",1600 "value": "Enter your first name"1601 }1602 ]1603 },1604 {1605 "type": "field",1606 "label": "Last Name",1607 "children": [],1608 "attributes": [1609 {1610 "name": "type",1611 "value": "text"1612 },1613 {1614 "name": "name",1615 "value": "lastName"1616 },1617 {1618 "name": "placeholder",1619 "value": "Enter your last name"1620 }1621 ]1622 }1623 ],1624 "attributes": []1625 },1626 {1627 "type": "button",1628 "label": "Submit",1629 "children": [],1630 "attributes": [1631 {1632 "name": "type",1633 "value": "submit"1634 }1635 ]1636 }1637 ],1638 "attributes": [1639 {1640 "name": "method",1641 "value": "post"1642 },1643 {1644 "name": "action",1645 "value": "/submit-profile"1646 }1647 ]1648}1649```165016511652 16531654 16551656 1657Moderation16581659 16601661### Moderation16621663You can classify inputs on multiple categories, which is a common way of doing moderation.16641665166616671668 Moderation using Structured Outputs16691670```javascript1671import OpenAI from "openai";1672import { zodTextFormat } from "openai/helpers/zod";1673import { z } from "zod";16741675const openai = new OpenAI();16761677const ContentCompliance = z.object({1678 is_violating: z.boolean(),1679 category: z.enum(["violence", "sexual", "self_harm"]).nullable(),1680 explanation_if_violating: z.string().nullable(),1681});16821683const response = await openai.responses.parse({1684 model: "gpt-6-astra",1685 input: [1686 {1687 role: "system",1688 content:1689 "Determine if the user input violates specific guidelines and explain if they do.",1690 },1691 {1692 role: "user",1693 content: "How do I prepare for a job interview?",1694 },1695 ],1696 text: {1697 format: zodTextFormat(ContentCompliance, "content_compliance"),1698 },1699});17001701const compliance = response.output_parsed;1702```17031704```python1705from enum import Enum17061707from openai import OpenAI1708from pydantic import BaseModel17091710client = OpenAI()171117121713class Category(str, Enum):1714 violence = "violence"1715 sexual = "sexual"1716 self_harm = "self_harm"171717181719class ContentCompliance(BaseModel):1720 is_violating: bool1721 category: Category | None1722 explanation_if_violating: str | None172317241725response = client.responses.parse(1726 model="gpt-6-astra",1727 input=[1728 {1729 "role": "system",1730 "content": "Determine if the user input violates specific guidelines and explain if they do.",1731 },1732 {"role": "user", "content": "How do I prepare for a job interview?"},1733 ],1734 text_format=ContentCompliance,1735)17361737compliance = response.output_parsed1738```17391740```go1741package main17421743import (1744 "context"1745 "fmt"17461747 "github.com/openai/openai-go/v3"1748 "github.com/openai/openai-go/v3/responses"1749)17501751func main() {1752 client := openai.NewClient()1753 schema := contentComplianceSchema()1754 response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{1755 Model: "gpt-6-astra",1756 Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{1757 responses.ResponseInputItemParamOfMessage("Determine if the user input violates specific guidelines and explain if they do.", responses.EasyInputMessageRoleSystem),1758 responses.ResponseInputItemParamOfMessage("How do I prepare for a job interview?", responses.EasyInputMessageRoleUser),1759 }},1760 Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{1761 OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{1762 Name: "content_compliance", Description: openai.String("Determines if content is violating specific moderation rules"), Schema: schema, Strict: openai.Bool(true),1763 },1764 }},1765 })1766 if err != nil {1767 panic(err)1768 }1769 fmt.Println(response.OutputText())1770}17711772func contentComplianceSchema() map[string]any {1773 return map[string]any{1774 "type": "object",1775 "properties": map[string]any{1776 "is_violating": map[string]any{"type": "boolean", "description": "Indicates if the content is violating guidelines"},1777 "category": map[string]any{"type": []string{"string", "null"}, "description": "Type of violation, if the content is violating guidelines. Null otherwise.", "enum": []any{"violence", "sexual", "self_harm", nil}},1778 "explanation_if_violating": map[string]any{"type": []string{"string", "null"}, "description": "Explanation of why the content is violating"},1779 },1780 "required": []string{"is_violating", "category", "explanation_if_violating"},1781 "additionalProperties": false,1782 }1783}1784```17851786```java1787import com.openai.client.OpenAIClient;1788import com.openai.client.okhttp.OpenAIOkHttpClient;1789import com.openai.core.JsonValue;1790import com.openai.models.responses.EasyInputMessage;1791import com.openai.models.responses.ResponseCreateParams;1792import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;1793import com.openai.models.responses.ResponseInputItem;1794import com.openai.models.responses.ResponseTextConfig;1795import java.util.Arrays;1796import java.util.List;1797import java.util.Map;17981799Map<String, Object> schema =1800 Map.of(1801 "type",1802 "object",1803 "properties",1804 Map.of(1805 "is_violating",1806 Map.of(1807 "type", "boolean",1808 "description", "Whether the content violates the guidelines"),1809 "category",1810 Map.of(1811 "type", List.of("string", "null"),1812 "enum", Arrays.asList("violence", "sexual", "self_harm", null),1813 "description", "The violation category, or null when content is allowed"),1814 "explanation_if_violating",1815 Map.of(1816 "type",1817 List.of("string", "null"),1818 "description",1819 "Why the content violates the guidelines, or null")),1820 "required",1821 List.of("is_violating", "category", "explanation_if_violating"),1822 "additionalProperties",1823 false);18241825ResponseCreateParams params =1826 ResponseCreateParams.builder()1827 .model("gpt-6-astra")1828 .inputOfResponse(1829 List.of(1830 ResponseInputItem.ofEasyInputMessage(1831 EasyInputMessage.builder()1832 .role(EasyInputMessage.Role.SYSTEM)1833 .content(1834 "Determine whether the user input violates the guidelines and explain any violation.")1835 .build()),1836 ResponseInputItem.ofEasyInputMessage(1837 EasyInputMessage.builder()1838 .role(EasyInputMessage.Role.USER)1839 .content("How do I prepare for a job interview?")1840 .build())))1841 .text(1842 ResponseTextConfig.builder()1843 .format(1844 ResponseFormatTextJsonSchemaConfig.builder()1845 .name("content_compliance")1846 .description("Determines whether content violates moderation rules")1847 .strict(true)1848 .schema(1849 JsonValue.from(schema)1850 .convert(ResponseFormatTextJsonSchemaConfig.Schema.class))1851 .build())1852 .build())1853 .build();18541855client.responses().create(params).output().stream()1856 .flatMap(item -> item.message().stream())1857 .flatMap(message -> message.content().stream())1858 .flatMap(content -> content.outputText().stream())1859 .forEach(text -> System.out.println(text.text()));1860```18611862```csharp1863using System.Text.Json;1864using OpenAI.Responses;1865#pragma warning disable OPENAI00118661867string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;1868ResponsesClient client = new(key);18691870BinaryData schema = BinaryData.FromString(1871 """1872 {1873 "type": "object",1874 "properties": {1875 "is_violating": { "type": "boolean" },1876 "category": {1877 "type": ["string", "null"],1878 "enum": ["violence", "sexual", "self_harm", null]1879 },1880 "explanation_if_violating": { "type": ["string", "null"] }1881 },1882 "required": ["is_violating", "category", "explanation_if_violating"],1883 "additionalProperties": false1884 }1885 """1886);1887CreateResponseOptions options = new()1888{1889 Model = "gpt-6-astra",1890 TextOptions = new ResponseTextOptions1891 {1892 TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(1893 "content_compliance",1894 schema,1895 jsonSchemaIsStrict: true1896 ),1897 },1898};1899options.InputItems.Add(ResponseItem.CreateSystemMessageItem("Determine whether the user input violates content guidelines."));1900options.InputItems.Add(ResponseItem.CreateUserMessageItem("How do I prepare for a job interview?"));19011902ResponseResult response = await client.CreateResponseAsync(options);1903using JsonDocument parsed = JsonDocument.Parse(response.GetOutputText());1904Console.WriteLine(parsed.RootElement);1905```19061907```ruby1908require "openai"19091910client = OpenAI::Client.new1911compliance_schema = {1912 type: :object,1913 properties: {1914 is_violating: {1915 type: :boolean,1916 description: "Whether the content violates the guidelines"1917 },1918 category: {1919 type: %i[string null],1920 enum: ["violence", "sexual", "self_harm", nil],1921 description: "The violation category, or null when the content is allowed"1922 },1923 explanation_if_violating: {1924 type: %i[string null],1925 description: "Why the content violates the guidelines, or null"1926 }1927 },1928 required: %w[is_violating category explanation_if_violating],1929 additionalProperties: false1930}19311932response = client.responses.create(1933 model: "gpt-6-astra",1934 input: [1935 {1936 role: :system,1937 content: "Determine whether the user input violates the guidelines and explain any violation."1938 },1939 {1940 role: :user,1941 content: "How do I prepare for a job interview?"1942 }1943 ],1944 text: {1945 format: {1946 type: :json_schema,1947 name: "content_compliance",1948 description: "Determines whether content violates moderation rules",1949 strict: true,1950 schema: compliance_schema1951 }1952 }1953)19541955puts(response.output_text)1956```19571958```bash1959curl https://api.openai.com/v1/responses \1960 -H "Authorization: Bearer $OPENAI_API_KEY" \1961 -H "Content-Type: application/json" \1962 -d '{1963 "model": "gpt-6-astra",1964 "input": [1965 {1966 "role": "system",1967 "content": "Determine if the user input violates specific guidelines and explain if they do."1968 },1969 {1970 "role": "user",1971 "content": "How do I prepare for a job interview?"1972 }1973 ],1974 "text": {1975 "format": {1976 "type": "json_schema",1977 "name": "content_compliance",1978 "description": "Determines if content is violating specific moderation rules",1979 "schema": {1980 "type": "object",1981 "properties": {1982 "is_violating": {1983 "type": "boolean",1984 "description": "Indicates if the content is violating guidelines"1985 },1986 "category": {1987 "type": ["string", "null"],1988 "description": "Type of violation, if the content is violating guidelines. Null otherwise.",1989 "enum": ["violence", "sexual", "self_harm"]1990 },1991 "explanation_if_violating": {1992 "type": ["string", "null"],1993 "description": "Explanation of why the content is violating"1994 }1995 },1996 "required": ["is_violating", "category", "explanation_if_violating"],1997 "additionalProperties": false1998 },1999 "strict": true2000 }2001 }2002 }'2003```2004200520062007#### Example response20082009```json2010{2011 "is_violating": false,2012 "category": null,2013 "explanation_if_violating": null2014}2015```201620172018201920202021202220232024How to use Structured Outputs with 2025text.format20262027202820292030## Step 1: Define your schema2031203220332034First you must design the JSON Schema that the model should be constrained to follow. See the [examples](https://developers.openai.com/api/docs/guides/structured-outputs#examples) at the top of this guide for reference.20352036While Structured Outputs supports much of JSON Schema, some features are unavailable either for performance or technical reasons. See [here](https://developers.openai.com/api/docs/guides/structured-outputs#supported-schemas) for more details.20372038#### Tips for your JSON Schema20392040To maximize the quality of model generations, we recommend the following:20412042- Name keys clearly and intuitively2043- Create clear titles and descriptions for important keys in your structure2044- Create and use evals to determine the structure that works best for your use case20452046204720482049205020512052## Step 2: Supply your schema in the API call205320542055205620572058To use Structured Outputs, simply specify20592060206120622063```json2064text: { format: { type: "json_schema", "strict": true, "schema": … } }2065```206620672068For example:20692070207120722073```javascript2074const response = await openai.responses.create({2075 model: "gpt-6-astra",2076 input: [2077 {2078 role: "system",2079 content:2080 "You are a helpful math tutor. Guide the user through the solution step by step.",2081 },2082 { role: "user", content: "how can I solve 8x + 7 = -23" },2083 ],2084 text: {2085 format: {2086 type: "json_schema",2087 name: "math_response",2088 schema: {2089 type: "object",2090 properties: {2091 steps: {2092 type: "array",2093 items: {2094 type: "object",2095 properties: {2096 explanation: { type: "string" },2097 output: { type: "string" },2098 },2099 required: ["explanation", "output"],2100 additionalProperties: false,2101 },2102 },2103 final_answer: { type: "string" },2104 },2105 required: ["steps", "final_answer"],2106 additionalProperties: false,2107 },2108 strict: true,2109 },2110 },2111});21122113console.log(response.output_text);2114```21152116```python2117response = client.responses.create(2118 model="gpt-6-astra",2119 input=[2120 {2121 "role": "system",2122 "content": "You are a helpful math tutor. Guide the user through the solution step by step.",2123 },2124 {"role": "user", "content": "how can I solve 8x + 7 = -23"},2125 ],2126 text={2127 "format": {2128 "type": "json_schema",2129 "name": "math_response",2130 "schema": {2131 "type": "object",2132 "properties": {2133 "steps": {2134 "type": "array",2135 "items": {2136 "type": "object",2137 "properties": {2138 "explanation": {"type": "string"},2139 "output": {"type": "string"},2140 },2141 "required": ["explanation", "output"],2142 "additionalProperties": False,2143 },2144 },2145 "final_answer": {"type": "string"},2146 },2147 "required": ["steps", "final_answer"],2148 "additionalProperties": False,2149 },2150 "strict": True,2151 },2152 },2153)21542155print(response.output_text)2156```21572158```go2159package main21602161import (2162 "context"2163 "fmt"21642165 "github.com/openai/openai-go/v3"2166 "github.com/openai/openai-go/v3/responses"2167)21682169func main() {2170 client := openai.NewClient()2171 response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{2172 Model: "gpt-6-astra",2173 Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{2174 responses.ResponseInputItemParamOfMessage(2175 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are a helpful math tutor. Guide the user through the solution step by step.")},2176 responses.EasyInputMessageRoleSystem,2177 ),2178 responses.ResponseInputItemParamOfMessage(2179 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("how can I solve 8x + 7 = -23")},2180 responses.EasyInputMessageRoleUser,2181 ),2182 }},2183 Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{2184 OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "math_response", Schema: mathSchema(), Strict: openai.Bool(true)},2185 }},2186 })2187 if err != nil {2188 panic(err)2189 }2190 fmt.Println(response.OutputText())2191}21922193func mathSchema() map[string]any {2194 return map[string]any{2195 "type": "object",2196 "properties": map[string]any{2197 "steps": map[string]any{"type": "array", "items": map[string]any{"type": "object", "properties": map[string]any{"explanation": map[string]any{"type": "string"}, "output": map[string]any{"type": "string"}}, "required": []string{"explanation", "output"}, "additionalProperties": false}},2198 "final_answer": map[string]any{"type": "string"},2199 },2200 "required": []string{"steps", "final_answer"},2201 "additionalProperties": false,2202 }2203}2204```22052206```java2207import com.openai.client.OpenAIClient;2208import com.openai.client.okhttp.OpenAIOkHttpClient;2209import com.openai.core.JsonValue;2210import com.openai.models.responses.EasyInputMessage;2211import com.openai.models.responses.ResponseCreateParams;2212import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;2213import com.openai.models.responses.ResponseInputItem;2214import com.openai.models.responses.ResponseTextConfig;2215import java.util.List;2216import java.util.Map;22172218Map<String, Object> schema =2219 Map.of(2220 "type",2221 "object",2222 "properties",2223 Map.of(2224 "steps",2225 Map.of(2226 "type",2227 "array",2228 "items",2229 Map.of(2230 "type",2231 "object",2232 "properties",2233 Map.of(2234 "explanation", Map.of("type", "string"),2235 "output", Map.of("type", "string")),2236 "required",2237 List.of("explanation", "output"),2238 "additionalProperties",2239 false)),2240 "final_answer", Map.of("type", "string")),2241 "required",2242 List.of("steps", "final_answer"),2243 "additionalProperties",2244 false);22452246ResponseCreateParams params =2247 ResponseCreateParams.builder()2248 .model("gpt-6-astra")2249 .inputOfResponse(2250 List.of(2251 ResponseInputItem.ofEasyInputMessage(2252 EasyInputMessage.builder()2253 .role(EasyInputMessage.Role.SYSTEM)2254 .content(2255 "You are a helpful math tutor. Guide the user through the solution step by step.")2256 .build()),2257 ResponseInputItem.ofEasyInputMessage(2258 EasyInputMessage.builder()2259 .role(EasyInputMessage.Role.USER)2260 .content("How can I solve 8x + 7 = -23?")2261 .build())))2262 .text(2263 ResponseTextConfig.builder()2264 .format(2265 ResponseFormatTextJsonSchemaConfig.builder()2266 .name("math_response")2267 .strict(true)2268 .schema(2269 JsonValue.from(schema)2270 .convert(ResponseFormatTextJsonSchemaConfig.Schema.class))2271 .build())2272 .build())2273 .build();22742275client.responses().create(params).output().stream()2276 .flatMap(item -> item.message().stream())2277 .flatMap(message -> message.content().stream())2278 .flatMap(content -> content.outputText().stream())2279 .forEach(text -> System.out.println(text.text()));2280```22812282```csharp2283using System.Text.Json;2284using OpenAI.Responses;2285#pragma warning disable OPENAI00122862287string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;2288ResponsesClient client = new(key);22892290BinaryData schema = BinaryData.FromString(2291 """2292 {2293 "type": "object",2294 "properties": {2295 "steps": {2296 "type": "array",2297 "items": {2298 "type": "object",2299 "properties": {2300 "explanation": { "type": "string" },2301 "output": { "type": "string" }2302 },2303 "required": ["explanation", "output"],2304 "additionalProperties": false2305 }2306 },2307 "final_answer": { "type": "string" }2308 },2309 "required": ["steps", "final_answer"],2310 "additionalProperties": false2311 }2312 """2313);2314CreateResponseOptions options = new()2315{2316 Model = "gpt-6-astra",2317 TextOptions = new ResponseTextOptions2318 {2319 TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(2320 "math_response",2321 schema,2322 jsonSchemaIsStrict: true2323 ),2324 },2325};2326options.InputItems.Add(ResponseItem.CreateSystemMessageItem("You are a helpful math tutor. Guide the user through the solution step by step."));2327options.InputItems.Add(ResponseItem.CreateUserMessageItem("How can I solve 8x + 7 = -23?"));23282329ResponseResult response = await client.CreateResponseAsync(options);2330using JsonDocument parsed = JsonDocument.Parse(response.GetOutputText());2331Console.WriteLine(parsed.RootElement);2332```23332334```ruby2335require "openai"23362337client = OpenAI::Client.new2338math_schema = {2339 type: :object,2340 properties: {2341 steps: {2342 type: :array,2343 items: {2344 type: :object,2345 properties: {2346 explanation: { type: :string },2347 output: { type: :string }2348 },2349 required: %w[explanation output],2350 additionalProperties: false2351 }2352 },2353 final_answer: { type: :string }2354 },2355 required: %w[steps final_answer],2356 additionalProperties: false2357}23582359response = client.responses.create(2360 model: "gpt-6-astra",2361 input: [2362 {2363 role: :system,2364 content: "You are a helpful math tutor. Guide the user through the solution step by step."2365 },2366 {2367 role: :user,2368 content: "How can I solve 8x + 7 = -23?"2369 }2370 ],2371 text: {2372 format: {2373 type: :json_schema,2374 name: "math_response",2375 strict: true,2376 schema: math_schema2377 }2378 }2379)23802381puts(response.output_text)2382```23832384```bash2385curl https://api.openai.com/v1/responses \2386 -H "Authorization: Bearer $OPENAI_API_KEY" \2387 -H "Content-Type: application/json" \2388 -d '{2389 "model": "gpt-6-astra",2390 "input": [2391 {2392 "role": "system",2393 "content": "You are a helpful math tutor. Guide the user through the solution step by step."2394 },2395 {2396 "role": "user",2397 "content": "how can I solve 8x + 7 = -23"2398 }2399 ],2400 "text": {2401 "format": {2402 "type": "json_schema",2403 "name": "math_response",2404 "schema": {2405 "type": "object",2406 "properties": {2407 "steps": {2408 "type": "array",2409 "items": {2410 "type": "object",2411 "properties": {2412 "explanation": { "type": "string" },2413 "output": { "type": "string" }2414 },2415 "required": ["explanation", "output"],2416 "additionalProperties": false2417 }2418 },2419 "final_answer": { "type": "string" }2420 },2421 "required": ["steps", "final_answer"],2422 "additionalProperties": false2423 },2424 "strict": true2425 }2426 }2427 }'2428```2429243024312432**Note:** the first request you make with any schema will have additional latency as our API processes the schema, but subsequent requests with the same schema will not have additional latency.24332434243524362437243824392440## Step 3: Handle edge cases244124422443244424452446In some cases, the model might not generate a valid response that matches the provided JSON schema.24472448This can happen in the case of a refusal, if the model refuses to answer for safety reasons, or if for example you reach a max tokens limit and the response is incomplete.24492450245124522453```javascript2454try {2455 const response = await openai.responses.create({2456 model: "gpt-6-astra",2457 input: [2458 {2459 role: "system",2460 content:2461 "You are a helpful math tutor. Guide the user through the solution step by step.",2462 },2463 {2464 role: "user",2465 content: "how can I solve 8x + 7 = -23",2466 },2467 ],2468 max_output_tokens: 50,2469 text: {2470 format: {2471 type: "json_schema",2472 name: "math_response",2473 schema: {2474 type: "object",2475 properties: {2476 steps: {2477 type: "array",2478 items: {2479 type: "object",2480 properties: {2481 explanation: {2482 type: "string",2483 },2484 output: {2485 type: "string",2486 },2487 },2488 required: ["explanation", "output"],2489 additionalProperties: false,2490 },2491 },2492 final_answer: {2493 type: "string",2494 },2495 },2496 required: ["steps", "final_answer"],2497 additionalProperties: false,2498 },2499 strict: true,2500 },2501 },2502 });25032504 if (2505 response.status === "incomplete" &&2506 response.incomplete_details.reason === "max_output_tokens"2507 ) {2508 // Handle the case where the model did not return a complete response2509 throw new Error("Incomplete response");2510 }25112512 const message = response.output.find((item) => item.type === "message");2513 const math_response = message?.content[0];25142515 if (!math_response) {2516 throw new Error("No response content");2517 }25182519 if (math_response.type === "refusal") {2520 // handle refusal2521 console.log(math_response.refusal);2522 } else if (math_response.type === "output_text") {2523 console.log(math_response.text);2524 } else {2525 throw new Error("No response content");2526 }2527} catch (e) {2528 // Handle edge cases2529 console.error(e);2530}2531```25322533```python2534try:2535 response = client.responses.create(2536 model="gpt-6-astra",2537 input=[2538 {2539 "role": "system",2540 "content": "You are a helpful math tutor. Guide the user through the solution step by step.",2541 },2542 {"role": "user", "content": "how can I solve 8x + 7 = -23"},2543 ],2544 text={2545 "format": {2546 "type": "json_schema",2547 "name": "math_response",2548 "strict": True,2549 "schema": {2550 "type": "object",2551 "properties": {2552 "steps": {2553 "type": "array",2554 "items": {2555 "type": "object",2556 "properties": {2557 "explanation": {"type": "string"},2558 "output": {"type": "string"},2559 },2560 "required": ["explanation", "output"],2561 "additionalProperties": False,2562 },2563 },2564 "final_answer": {"type": "string"},2565 },2566 "required": ["steps", "final_answer"],2567 "additionalProperties": False,2568 },2569 },2570 },2571 max_output_tokens=50,2572 )25732574 if (2575 response.status == "incomplete"2576 and response.incomplete_details.reason == "max_output_tokens"2577 ):2578 raise Exception("Incomplete response")25792580 message = next((item for item in response.output if item.type == "message"), None)2581 math_response = message.content[0] if message and message.content else None25822583 if not math_response:2584 raise Exception("No response content")25852586 if math_response.type == "refusal":2587 print(math_response.refusal)2588 elif math_response.type == "output_text":2589 print(math_response.text)2590 else:2591 raise Exception("No response content")2592except Exception as e:2593 # handle errors like finish_reason, refusal, content_filter, etc.2594 print(e)2595```25962597```go2598package main25992600import (2601 "context"2602 "errors"2603 "fmt"26042605 "github.com/openai/openai-go/v3"2606 "github.com/openai/openai-go/v3/responses"2607)26082609func main() {2610 client := openai.NewClient()2611 response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{2612 Model: "gpt-6-astra",2613 Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{2614 responses.ResponseInputItemParamOfMessage(2615 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are a helpful math tutor. Guide the user through the solution step by step.")},2616 responses.EasyInputMessageRoleSystem,2617 ),2618 responses.ResponseInputItemParamOfMessage(2619 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("how can I solve 8x + 7 = -23")},2620 responses.EasyInputMessageRoleUser,2621 ),2622 }},2623 MaxOutputTokens: openai.Int(1024),2624 Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{2625 OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "math_response", Schema: mathSchema(), Strict: openai.Bool(true)},2626 }},2627 })2628 if err != nil {2629 panic(err)2630 }2631 if response.Status == "incomplete" {2632 panic(errors.New("incomplete response"))2633 }26342635 for _, output := range response.Output {2636 if output.Type != "message" {2637 continue2638 }2639 for _, content := range output.AsMessage().Content {2640 if content.Type == "refusal" {2641 fmt.Println(content.AsRefusal().Refusal)2642 return2643 }2644 if content.Type == "output_text" {2645 fmt.Println(content.AsOutputText().Text)2646 return2647 }2648 }2649 }2650 panic(errors.New("no response content"))2651}26522653func mathSchema() map[string]any {2654 return map[string]any{2655 "type": "object",2656 "properties": map[string]any{2657 "steps": map[string]any{"type": "array", "items": map[string]any{"type": "object", "properties": map[string]any{"explanation": map[string]any{"type": "string"}, "output": map[string]any{"type": "string"}}, "required": []string{"explanation", "output"}, "additionalProperties": false}},2658 "final_answer": map[string]any{"type": "string"},2659 },2660 "required": []string{"steps", "final_answer"},2661 "additionalProperties": false,2662 }2663}2664```26652666```java2667import com.openai.client.OpenAIClient;2668import com.openai.client.okhttp.OpenAIOkHttpClient;2669import com.openai.core.JsonValue;2670import com.openai.models.responses.EasyInputMessage;2671import com.openai.models.responses.ResponseCreateParams;2672import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;2673import com.openai.models.responses.ResponseInputItem;2674import com.openai.models.responses.ResponseStatus;2675import com.openai.models.responses.ResponseTextConfig;2676import java.util.List;2677import java.util.Map;26782679ResponseCreateParams params =2680 ResponseCreateParams.builder()2681 .model("gpt-6-astra")2682 .inputOfResponse(2683 List.of(2684 ResponseInputItem.ofEasyInputMessage(2685 EasyInputMessage.builder()2686 .role(EasyInputMessage.Role.SYSTEM)2687 .content(2688 "You are a helpful math tutor. Guide the user through the solution step by step.")2689 .build()),2690 ResponseInputItem.ofEasyInputMessage(2691 EasyInputMessage.builder()2692 .role(EasyInputMessage.Role.USER)2693 .content("How can I solve 8x + 7 = -23?")2694 .build())))2695 .text(2696 ResponseTextConfig.builder()2697 .format(2698 ResponseFormatTextJsonSchemaConfig.builder()2699 .name("math_response")2700 .strict(true)2701 .schema(2702 ResponseFormatTextJsonSchemaConfig.Schema.builder()2703 .putAdditionalProperty("type", JsonValue.from("object"))2704 .putAdditionalProperty(2705 "properties",2706 JsonValue.from(2707 Map.of(2708 "steps",2709 Map.of(2710 "type",2711 "array",2712 "items",2713 Map.of(2714 "type",2715 "object",2716 "properties",2717 Map.of(2718 "explanation",2719 Map.of("type", "string"),2720 "output",2721 Map.of("type", "string")),2722 "required",2723 List.of("explanation", "output"),2724 "additionalProperties",2725 false)),2726 "final_answer",2727 Map.of("type", "string"))))2728 .putAdditionalProperty(2729 "required",2730 JsonValue.from(List.of("steps", "final_answer")))2731 .putAdditionalProperty(2732 "additionalProperties", JsonValue.from(false))2733 .build())2734 .build())2735 .build())2736 .maxOutputTokens(1_024L)2737 .build();27382739var response = client.responses().create(params);2740if (response.status().filter(ResponseStatus.INCOMPLETE::equals).isPresent()) {2741 throw new IllegalStateException("Incomplete response");2742}27432744var content =2745 response.output().stream()2746 .flatMap(item -> item.message().stream())2747 .flatMap(message -> message.content().stream())2748 .findFirst()2749 .orElseThrow(() -> new IllegalStateException("No response content"));27502751if (content.refusal().isPresent()) {2752 System.out.println(content.refusal().orElseThrow().refusal());2753} else {2754 System.out.println(2755 content2756 .outputText()2757 .orElseThrow(() -> new IllegalStateException("No response content"))2758 .text());2759}2760```27612762```csharp2763using OpenAI.Responses;2764#pragma warning disable OPENAI00127652766string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;2767ResponsesClient client = new(key);27682769BinaryData schema = BinaryData.FromString(2770 """2771 {2772 "type": "object",2773 "properties": {2774 "steps": {2775 "type": "array",2776 "items": {2777 "type": "object",2778 "properties": {2779 "explanation": { "type": "string" },2780 "output": { "type": "string" }2781 },2782 "required": ["explanation", "output"],2783 "additionalProperties": false2784 }2785 },2786 "final_answer": { "type": "string" }2787 },2788 "required": ["steps", "final_answer"],2789 "additionalProperties": false2790 }2791 """2792);2793CreateResponseOptions options = new()2794{2795 Model = "gpt-6-astra",2796 MaxOutputTokenCount = 300,2797 TextOptions = new ResponseTextOptions2798 {2799 TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(2800 "math_response",2801 schema,2802 jsonSchemaIsStrict: true2803 ),2804 },2805};2806options.InputItems.Add(ResponseItem.CreateSystemMessageItem("You are a helpful math tutor. Guide the user through the solution step by step."));2807options.InputItems.Add(ResponseItem.CreateUserMessageItem("How can I solve 8x + 7 = -23?"));28082809ResponseResult response = await client.CreateResponseAsync(options);2810if (2811 response.Status == ResponseStatus.Incomplete2812 && response.IncompleteStatusDetails?.Reason == ResponseIncompleteStatusReason.MaxOutputTokens2813)2814{2815 throw new InvalidOperationException("The structured response was incomplete.");2816}2817if (2818 response.Status == ResponseStatus.Incomplete2819 && response.IncompleteStatusDetails?.Reason == ResponseIncompleteStatusReason.ContentFilter2820)2821{2822 throw new InvalidOperationException("The structured response was interrupted by the content filter.");2823}2824MessageResponseItem message = response.OutputItems.OfType<MessageResponseItem>().FirstOrDefault()2825 ?? throw new InvalidOperationException("The response did not include an output message.");2826ResponseContentPart content = message.Content.FirstOrDefault()2827 ?? throw new InvalidOperationException("The response did not include output content.");2828Console.WriteLine(2829 content.Kind == ResponseContentPartKind.Refusal ? content.Refusal : content.Text2830);2831```28322833```ruby2834require "openai"28352836client = OpenAI::Client.new2837step_schema = {2838 type: :object,2839 properties: {2840 explanation: { type: :string },2841 output: { type: :string }2842 },2843 required: %w[explanation output],2844 additionalProperties: false2845}2846math_schema = {2847 type: :object,2848 properties: {2849 steps: {2850 type: :array,2851 items: step_schema2852 },2853 final_answer: { type: :string }2854 },2855 required: %w[steps final_answer],2856 additionalProperties: false2857}28582859response = client.responses.create(2860 model: "gpt-6-astra",2861 input: [2862 {2863 role: :system,2864 content: "You are a helpful math tutor. Guide the user through the solution step by step."2865 },2866 {2867 role: :user,2868 content: "How can I solve 8x + 7 = -23?"2869 }2870 ],2871 max_output_tokens: 1_024,2872 text: {2873 format: {2874 type: :json_schema,2875 name: "math_response",2876 strict: true,2877 schema: math_schema2878 }2879 }2880)28812882if response.status == OpenAI::Responses::ResponseStatus::INCOMPLETE2883 raise "Incomplete response"2884end28852886message = response.output.find do |item|2887 item.is_a?(OpenAI::Models::Responses::ResponseOutputMessage)2888end2889unless message.is_a?(OpenAI::Models::Responses::ResponseOutputMessage)2890 raise "No response message"2891end28922893content = message.content.fetch(0)2894if content.is_a?(OpenAI::Models::Responses::ResponseOutputRefusal)2895 puts(content.refusal)2896else2897 puts(content.text)2898end2899```29002901290229032904290529062907Refusals with Structured Outputs2908290929102911When using Structured Outputs with user-generated input, OpenAI models may occasionally refuse to fulfill the request for safety reasons. Since a refusal does not necessarily follow the schema you have supplied in `response_format`, the API response will include a new field called `refusal` to indicate that the model refused to fulfill the request.29122913When the `refusal` property appears in your output object, you might present the refusal in your UI, or include conditional logic in code that consumes the response to handle the case of a refused request.29142915291629172918```javascript2919const Step = z.object({2920 explanation: z.string(),2921 output: z.string(),2922});29232924const MathReasoning = z.object({2925 steps: z.array(Step),2926 final_answer: z.string(),2927});29282929const response = await openai.responses.parse({2930 model: "gpt-6-astra",2931 input: [2932 {2933 role: "system",2934 content:2935 "You are a helpful math tutor. Guide the user through the solution step by step.",2936 },2937 { role: "user", content: "how can I solve 8x + 7 = -23" },2938 ],2939 text: {2940 format: zodTextFormat(MathReasoning, "math_response"),2941 },2942});29432944for (const output of response.output) {2945 if (output.type !== "message") {2946 continue;2947 }29482949 for (const item of output.content) {2950 if (item.type == "refusal") {2951 // If the model refuses to respond, you will get a refusal message2952 console.log(item.refusal);2953 continue;2954 }29552956 if (!item.parsed) {2957 throw new Error("Could not parse response");2958 }29592960 console.log(item.parsed);2961 }2962}2963```29642965```python2966class Step(BaseModel):2967 explanation: str2968 output: str296929702971class MathReasoning(BaseModel):2972 steps: list[Step]2973 final_answer: str297429752976response = client.responses.parse(2977 model="gpt-6-astra",2978 input=[2979 {2980 "role": "system",2981 "content": "You are a helpful math tutor. Guide the user through the solution step by step.",2982 },2983 {"role": "user", "content": "how can I solve 8x + 7 = -23"},2984 ],2985 text_format=MathReasoning,2986)29872988for output in response.output:2989 if output.type != "message":2990 continue29912992 for item in output.content:2993 if item.type == "refusal":2994 # If the model refuses to respond, you will get a refusal message2995 print(item.refusal)2996 continue29972998 if not item.parsed:2999 raise Exception("Could not parse response")30003001 print(item.parsed)3002```30033004```go3005package main30063007import (3008 "context"3009 "fmt"30103011 "github.com/openai/openai-go/v3"3012 "github.com/openai/openai-go/v3/responses"3013)30143015func main() {3016 client := openai.NewClient()3017 response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{3018 Model: "gpt-6-astra",3019 Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{3020 responses.ResponseInputItemParamOfMessage(3021 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are a helpful math tutor. Guide the user through the solution step by step.")},3022 responses.EasyInputMessageRoleSystem,3023 ),3024 responses.ResponseInputItemParamOfMessage(3025 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("how can I solve 8x + 7 = -23")},3026 responses.EasyInputMessageRoleUser,3027 ),3028 }},3029 Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{3030 OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "math_response", Schema: mathSchema(), Strict: openai.Bool(true)},3031 }},3032 })3033 if err != nil {3034 panic(err)3035 }30363037 for _, output := range response.Output {3038 if output.Type != "message" {3039 continue3040 }3041 for _, content := range output.AsMessage().Content {3042 if content.Type == "refusal" {3043 fmt.Println(content.AsRefusal().Refusal)3044 continue3045 }3046 fmt.Println(content.AsOutputText().Text)3047 }3048 }3049}30503051func mathSchema() map[string]any {3052 return map[string]any{3053 "type": "object",3054 "properties": map[string]any{3055 "steps": map[string]any{"type": "array", "items": map[string]any{"type": "object", "properties": map[string]any{"explanation": map[string]any{"type": "string"}, "output": map[string]any{"type": "string"}}, "required": []string{"explanation", "output"}, "additionalProperties": false}},3056 "final_answer": map[string]any{"type": "string"},3057 },3058 "required": []string{"steps", "final_answer"},3059 "additionalProperties": false,3060 }3061}3062```30633064```java3065import com.openai.client.OpenAIClient;3066import com.openai.client.okhttp.OpenAIOkHttpClient;3067import com.openai.core.JsonValue;3068import com.openai.models.responses.EasyInputMessage;3069import com.openai.models.responses.ResponseCreateParams;3070import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;3071import com.openai.models.responses.ResponseInputItem;3072import com.openai.models.responses.ResponseTextConfig;3073import java.util.List;3074import java.util.Map;30753076Map<String, Object> schema =3077 Map.of(3078 "type",3079 "object",3080 "properties",3081 Map.of(3082 "steps",3083 Map.of(3084 "type",3085 "array",3086 "items",3087 Map.of(3088 "type",3089 "object",3090 "properties",3091 Map.of(3092 "explanation", Map.of("type", "string"),3093 "output", Map.of("type", "string")),3094 "required",3095 List.of("explanation", "output"),3096 "additionalProperties",3097 false)),3098 "final_answer", Map.of("type", "string")),3099 "required",3100 List.of("steps", "final_answer"),3101 "additionalProperties",3102 false);31033104ResponseCreateParams params =3105 ResponseCreateParams.builder()3106 .model("gpt-6-astra")3107 .inputOfResponse(3108 List.of(3109 ResponseInputItem.ofEasyInputMessage(3110 EasyInputMessage.builder()3111 .role(EasyInputMessage.Role.SYSTEM)3112 .content(3113 "You are a helpful math tutor. Guide the user through the solution step by step.")3114 .build()),3115 ResponseInputItem.ofEasyInputMessage(3116 EasyInputMessage.builder()3117 .role(EasyInputMessage.Role.USER)3118 .content("How can I solve 8x + 7 = -23?")3119 .build())))3120 .text(3121 ResponseTextConfig.builder()3122 .format(3123 ResponseFormatTextJsonSchemaConfig.builder()3124 .name("math_reasoning")3125 .strict(true)3126 .schema(3127 JsonValue.from(schema)3128 .convert(ResponseFormatTextJsonSchemaConfig.Schema.class))3129 .build())3130 .build())3131 .build();31323133var response = client.responses().create(params);3134for (var output : response.output()) {3135 if (output.message().isEmpty()) continue;3136 for (var content : output.message().orElseThrow().content()) {3137 if (content.refusal().isPresent()) {3138 System.out.println(content.refusal().orElseThrow().refusal());3139 } else {3140 content.outputText().ifPresent(text -> System.out.println(text.text()));3141 }3142 }3143}3144```31453146```csharp3147using OpenAI.Responses;3148#pragma warning disable OPENAI00131493150string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;3151ResponsesClient client = new(key);31523153BinaryData schema = BinaryData.FromString(3154 """3155 {3156 "type": "object",3157 "properties": {3158 "steps": {3159 "type": "array",3160 "items": {3161 "type": "object",3162 "properties": {3163 "explanation": { "type": "string" },3164 "output": { "type": "string" }3165 },3166 "required": ["explanation", "output"],3167 "additionalProperties": false3168 }3169 },3170 "final_answer": { "type": "string" }3171 },3172 "required": ["steps", "final_answer"],3173 "additionalProperties": false3174 }3175 """3176);3177CreateResponseOptions options = new()3178{3179 Model = "gpt-6-astra",3180 TextOptions = new ResponseTextOptions3181 {3182 TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(3183 "math_response",3184 schema,3185 jsonSchemaIsStrict: true3186 ),3187 },3188};3189options.InputItems.Add(ResponseItem.CreateSystemMessageItem("You are a helpful math tutor. Guide the user through the solution step by step."));3190options.InputItems.Add(ResponseItem.CreateUserMessageItem("How can I solve 8x + 7 = -23?"));31913192ResponseResult response = await client.CreateResponseAsync(options);3193foreach (MessageResponseItem message in response.OutputItems.OfType<MessageResponseItem>())3194{3195 foreach (ResponseContentPart content in message.Content)3196 {3197 Console.WriteLine(3198 content.Kind == ResponseContentPartKind.Refusal ? content.Refusal : content.Text3199 );3200 }3201}3202```32033204```ruby3205require "openai"32063207client = OpenAI::Client.new3208math_schema = {3209 type: :object,3210 properties: {3211 steps: {3212 type: :array,3213 items: {3214 type: :object,3215 properties: {3216 explanation: { type: :string },3217 output: { type: :string }3218 },3219 required: %w[explanation output],3220 additionalProperties: false3221 }3222 },3223 final_answer: { type: :string }3224 },3225 required: %w[steps final_answer],3226 additionalProperties: false3227}32283229response = client.responses.create(3230 model: "gpt-6-astra",3231 input: [3232 {3233 role: :system,3234 content: "You are a helpful math tutor. Guide the user through the solution step by step."3235 },3236 {3237 role: :user,3238 content: "How can I solve 8x + 7 = -23?"3239 }3240 ],3241 text: {3242 format: {3243 type: :json_schema,3244 name: "math_response",3245 strict: true,3246 schema: math_schema3247 }3248 }3249)32503251response.output.each do |item|3252 next unless item.is_a?(OpenAI::Models::Responses::ResponseOutputMessage)32533254 item.content.each do |content|3255 case content3256 when OpenAI::Models::Responses::ResponseOutputRefusal3257 puts(content.refusal)3258 when OpenAI::Models::Responses::ResponseOutputText3259 puts(content.text)3260 end3261 end3262end3263```3264326532663267The API response from a refusal will look something like this:32683269327032713272```json3273{3274 "id": "resp_1234567890",3275 "object": "response",3276 "created_at": 1721596428,3277 "status": "completed",3278 "completed_at": 1721596429,3279 "error": null,3280 "incomplete_details": null,3281 "input": [],3282 "instructions": null,3283 "max_output_tokens": null,3284 "model": "gpt-4o-2024-08-06",3285 "output": [{3286 "id": "msg_1234567890",3287 "type": "message",3288 "role": "assistant",3289 "content": [3290 // highlight-start3291 {3292 "type": "refusal",3293 "refusal": "I'm sorry, I cannot assist with that request."3294 }3295 // highlight-end3296 ]3297 }],3298 "usage": {3299 "input_tokens": 81,3300 "output_tokens": 11,3301 "total_tokens": 92,3302 "output_tokens_details": {3303 "reasoning_tokens": 0,3304 }3305 },3306}3307```33083309331033113312Tips and best practices3313331433153316#### Handling user-generated input33173318If your application is using user-generated input, make sure your prompt includes instructions on how to handle situations where the input cannot result in a valid response.33193320The model will always try to adhere to the provided schema, which can result in hallucinations if the input is completely unrelated to the schema.33213322You could include language in your prompt to specify that you want to return empty parameters, or a specific sentence, if the model detects that the input is incompatible with the task.33233324#### Handling mistakes33253326Structured Outputs can still contain mistakes. If you see mistakes, try adjusting your instructions, providing examples in the system instructions, or splitting tasks into simpler subtasks. Refer to the [prompt engineering guide](https://developers.openai.com/api/docs/guides/prompt-engineering) for more guidance on how to tweak your inputs.33273328#### Avoid JSON schema divergence33293330To prevent your JSON Schema and corresponding types in your programming language from diverging, we strongly recommend using native SDK schema helpers where available.33313332If you prefer to specify the JSON schema directly, you could add CI rules that flag when either the JSON schema or underlying data objects are edited, or add a CI step that automatically generates the JSON Schema from type definitions (or vice-versa).33333334## Streaming3335333633373338You can use streaming to process model responses or function call arguments as they are being generated, and parse them as structured data.33393340That way, you don't have to wait for the entire response to complete before handling it.3341This is particularly useful if you would like to display JSON fields one by one, or handle function call arguments as soon as they are available.33423343We recommend relying on the SDKs to handle streaming with Structured Outputs.33443345334633473348```javascript3349import { OpenAI } from "openai";3350import { zodTextFormat } from "openai/helpers/zod";3351import { z } from "zod";33523353const EntitiesSchema = z.object({3354 attributes: z.array(z.string()),3355 colors: z.array(z.string()),3356 animals: z.array(z.string()),3357});33583359const openai = new OpenAI();3360const stream = openai.responses3361 .stream({3362 model: "gpt-6-astra",3363 input: [3364 { role: "user", content: "What's the weather like in Paris today?" },3365 ],3366 text: {3367 format: zodTextFormat(EntitiesSchema, "entities"),3368 },3369 })3370 .on("response.refusal.delta", (event) => {3371 process.stdout.write(event.delta);3372 })3373 .on("response.output_text.delta", (event) => {3374 process.stdout.write(event.delta);3375 })3376 .on("response.output_text.done", () => {3377 process.stdout.write("\n");3378 })3379 .on("error", (error) => {3380 console.error(error);3381 });33823383const result = await stream.finalResponse();33843385console.log(result);3386```33873388```python3389from openai import OpenAI3390from pydantic import BaseModel339133923393class EntitiesModel(BaseModel):3394 attributes: list[str]3395 colors: list[str]3396 animals: list[str]339733983399client = OpenAI()34003401with client.responses.stream(3402 model="gpt-6-astra",3403 input=[3404 {"role": "system", "content": "Extract entities from the input text"},3405 {3406 "role": "user",3407 "content": "The quick brown fox jumps over the lazy dog with piercing blue eyes",3408 },3409 ],3410 text_format=EntitiesModel,3411) as stream:3412 for event in stream:3413 if event.type == "response.refusal.delta":3414 print(event.delta, end="")3415 elif event.type == "response.output_text.delta":3416 print(event.delta, end="")3417 elif event.type == "response.error":3418 print(event.error, end="")3419 elif event.type == "response.completed":3420 print("Completed") # print(event.response.output)34213422 final_response = stream.get_final_response()3423 print(final_response)3424```34253426```java3427import com.openai.client.OpenAIClient;3428import com.openai.client.okhttp.OpenAIOkHttpClient;3429import com.openai.core.JsonValue;3430import com.openai.core.http.StreamResponse;3431import com.openai.models.responses.EasyInputMessage;3432import com.openai.models.responses.ResponseCreateParams;3433import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;3434import com.openai.models.responses.ResponseInputItem;3435import com.openai.models.responses.ResponseStreamEvent;3436import com.openai.models.responses.ResponseTextConfig;3437import java.util.List;3438import java.util.Map;34393440ResponseCreateParams params =3441 ResponseCreateParams.builder()3442 .model("gpt-6-astra")3443 .inputOfResponse(3444 List.of(3445 ResponseInputItem.ofEasyInputMessage(3446 EasyInputMessage.builder()3447 .role(EasyInputMessage.Role.SYSTEM)3448 .content("Extract entities from the input text")3449 .build()),3450 ResponseInputItem.ofEasyInputMessage(3451 EasyInputMessage.builder()3452 .role(EasyInputMessage.Role.USER)3453 .content(3454 "The quick brown fox jumps over the lazy dog with piercing blue eyes")3455 .build())))3456 .text(3457 ResponseTextConfig.builder()3458 .format(3459 ResponseFormatTextJsonSchemaConfig.builder()3460 .name("entities")3461 .strict(true)3462 .schema(3463 ResponseFormatTextJsonSchemaConfig.Schema.builder()3464 .putAdditionalProperty("type", JsonValue.from("object"))3465 .putAdditionalProperty(3466 "properties",3467 JsonValue.from(3468 Map.of(3469 "attributes",3470 Map.of(3471 "type",3472 "array",3473 "items",3474 Map.of("type", "string")),3475 "colors",3476 Map.of(3477 "type",3478 "array",3479 "items",3480 Map.of("type", "string")),3481 "animals",3482 Map.of(3483 "type",3484 "array",3485 "items",3486 Map.of("type", "string")))))3487 .putAdditionalProperty(3488 "required",3489 JsonValue.from(List.of("attributes", "colors", "animals")))3490 .putAdditionalProperty(3491 "additionalProperties", JsonValue.from(false))3492 .build())3493 .build())3494 .build())3495 .build();34963497try (StreamResponse<ResponseStreamEvent> stream = client.responses().createStreaming(params)) {3498 stream.stream()3499 .forEach(3500 event -> {3501 event.outputTextDelta().ifPresent(delta -> System.out.print(delta.delta()));3502 event.refusalDelta().ifPresent(refusal -> System.out.print(refusal.delta()));3503 event.error().ifPresent(error -> System.out.println(error.message()));3504 event3505 .completed()3506 .ifPresent(3507 completed -> {3508 System.out.println("Completed");3509 System.out.println(completed.response());3510 });3511 });3512}3513```35143515```ruby3516require "openai"35173518client = OpenAI::Client.new3519entities_schema = {3520 type: :object,3521 properties: {3522 attributes: {3523 type: :array,3524 items: { type: :string }3525 },3526 colors: {3527 type: :array,3528 items: { type: :string }3529 },3530 animals: {3531 type: :array,3532 items: { type: :string }3533 }3534 },3535 required: %w[attributes colors animals],3536 additionalProperties: false3537}35383539stream = client.responses.stream(3540 model: "gpt-6-astra",3541 input: [3542 {3543 role: :system,3544 content: "Extract entities from the input text."3545 },3546 {3547 role: :user,3548 content: "The quick brown fox jumps over the lazy dog with piercing blue eyes."3549 }3550 ],3551 text: {3552 format: {3553 type: :json_schema,3554 name: "entities",3555 strict: true,3556 schema: entities_schema3557 }3558 }3559)35603561stream.each do |event|3562 case event3563 when OpenAI::Models::Responses::ResponseRefusalDeltaEvent,3564 OpenAI::Models::Responses::ResponseTextDeltaEvent3565 print(event.delta)3566 when OpenAI::Models::Responses::ResponseErrorEvent3567 warn(event.message)3568 when OpenAI::Models::Responses::ResponseCompletedEvent3569 puts("\nCompleted")3570 end3571end3572```3573357435753576## Supported schemas3577357835793580Structured Outputs supports a subset of the [JSON Schema](https://json-schema.org/docs) language.35813582#### Supported types35833584The following types are supported for Structured Outputs:35853586- String3587- Number3588- Boolean3589- Integer3590- Object3591- Array3592- Enum3593- anyOf35943595#### Supported properties35963597In addition to specifying the type of a property, you can specify a selection of additional constraints:35983599**Supported `string` properties:**36003601- `pattern` — A regular expression that the string must match.3602- `format` — Predefined formats for strings. Currently supported:3603 - `date-time`3604 - `time`3605 - `date`3606 - `duration`3607 - `email`3608 - `hostname`3609 - `ipv4`3610 - `ipv6`3611 - `uuid`36123613**Supported `number` properties:**36143615- `multipleOf` — The number must be a multiple of this value.3616- `maximum` — The number must be less than or equal to this value.3617- `exclusiveMaximum` — The number must be less than this value.3618- `minimum` — The number must be greater than or equal to this value.3619- `exclusiveMinimum` — The number must be greater than this value.36203621**Supported `array` properties:**36223623- `minItems` — The array must have at least this many items.3624- `maxItems` — The array must have at most this many items.36253626Here are some examples on how you can use these type restrictions:3627362836293630String Restrictions36313632```json3633{3634 "name": "user_data",3635 "strict": true,3636 "schema": {3637 "type": "object",3638 "properties": {3639 "name": {3640 "type": "string",3641 "description": "The name of the user"3642 },3643 "username": {3644 "type": "string",3645 "description": "The username of the user. Must start with @",3646 // highlight-start3647 "pattern": "^@[a-zA-Z0-9_]+$"3648 // highlight-end3649 },3650 "email": {3651 "type": "string",3652 "description": "The email of the user",3653 // highlight-start3654 "format": "email"3655 // highlight-end3656 }3657 },3658 "additionalProperties": false,3659 "required": [3660 "name", "username", "email"3661 ]3662 }3663}3664```36653666 36673668 36693670 3671Number Restrictions36723673```json3674{3675 "name": "weather_data",3676 "strict": true,3677 "schema": {3678 "type": "object",3679 "properties": {3680 "location": {3681 "type": "string",3682 "description": "The location to get the weather for"3683 },3684 "unit": {3685 "type": ["string", "null"],3686 "description": "The unit to return the temperature in",3687 "enum": ["F", "C"]3688 },3689 "value": {3690 "type": "number",3691 "description": "The actual temperature value in the location",3692 // highlight-start3693 "minimum": -130,3694 "maximum": 1303695 // highlight-end3696 }3697 },3698 "additionalProperties": false,3699 "required": [3700 "location", "unit", "value"3701 ]3702 }3703}3704```3705370637073708Note these constraints are [not yet supported for fine-tuned3709 models](#some-type-specific-keywords-are-not-yet-supported).37103711#### Root objects must not be `anyOf` and must be an object37123713Note that the root level object of a schema must be an object, and not use `anyOf`. A pattern that appears in Zod (as one example) is using a discriminated union, which produces an `anyOf` at the top level. So code such as the following won't work:37143715```javascript3716import { z } from "zod";3717import { zodResponseFormat } from "openai/helpers/zod";37183719const BaseResponseSchema = z.object({3720 /* ... */3721});3722const UnsuccessfulResponseSchema = z.object({3723 /* ... */3724});37253726const finalSchema = z.discriminatedUnion("status", [3727 BaseResponseSchema,3728 UnsuccessfulResponseSchema,3729]);37303731// Invalid JSON Schema for Structured Outputs3732const json = zodResponseFormat(finalSchema, "final_schema");3733```373437353736#### All fields must be `required`37373738To use Structured Outputs, all fields or function parameters must be specified as `required`.37393740```json3741{3742 "name": "get_weather",3743 "description": "Fetches the weather in the given location",3744 "strict": true,3745 "parameters": {3746 "type": "object",3747 "properties": {3748 "location": {3749 "type": "string",3750 "description": "The location to get the weather for"3751 },3752 "unit": {3753 "type": "string",3754 "description": "The unit to return the temperature in",3755 "enum": ["F", "C"]3756 }3757 },3758 "additionalProperties": false,3759 // highlight-start3760 "required": ["location", "unit"]3761 // highlight-end3762 }3763}3764```376537663767Although all fields must be required (and the model will return a value for each parameter), it is possible to emulate an optional parameter by using a union type with `null`.37683769```json3770{3771 "name": "get_weather",3772 "description": "Fetches the weather in the given location",3773 "strict": true,3774 "parameters": {3775 "type": "object",3776 "properties": {3777 "location": {3778 "type": "string",3779 "description": "The location to get the weather for"3780 },3781 "unit": {3782 // highlight-start3783 "type": ["string", "null"],3784 // highlight-end3785 "description": "The unit to return the temperature in",3786 "enum": ["F", "C"]3787 }3788 },3789 "additionalProperties": false,3790 "required": [3791 "location", "unit"3792 ]3793 }3794}3795```379637973798#### Objects have limitations on nesting depth and size37993800A schema may have up to 5000 object properties total, with up to 10 levels of nesting.38013802#### Limitations on total string size38033804In a schema, total string length of all property names, definition names, enum values, and const values cannot exceed 120,000 characters.38053806#### Limitations on enum size38073808A schema may have up to 1000 enum values across all enum properties.38093810For a single enum property with string values, the total string length of all enum values cannot exceed 15,000 characters when there are more than 250 enum values.38113812#### `additionalProperties: false` must always be set in objects38133814`additionalProperties` controls whether it is allowable for an object to contain additional keys / values that were not defined in the JSON Schema.38153816Structured Outputs only supports generating specified keys / values, so we require developers to set `additionalProperties: false` to opt into Structured Outputs.38173818```json3819{3820 "name": "get_weather",3821 "description": "Fetches the weather in the given location",3822 "strict": true,3823 "schema": {3824 "type": "object",3825 "properties": {3826 "location": {3827 "type": "string",3828 "description": "The location to get the weather for"3829 },3830 "unit": {3831 "type": "string",3832 "description": "The unit to return the temperature in",3833 "enum": ["F", "C"]3834 }3835 },3836 // highlight-start3837 "additionalProperties": false,3838 // highlight-end3839 "required": [3840 "location", "unit"3841 ]3842 }3843}3844```384538463847#### Key ordering38483849When using Structured Outputs, outputs will be produced in the same order as the ordering of keys in the schema.38503851#### Some type-specific keywords are not yet supported38523853- **Composition:** `allOf`, `not`, `dependentRequired`, `dependentSchemas`, `if`, `then`, `else`38543855For fine-tuned models, we additionally do not support the following:38563857- **For strings:** `minLength`, `maxLength`, `pattern`, `format`3858- **For numbers:** `minimum`, `maximum`, `multipleOf`3859- **For objects:** `patternProperties`3860- **For arrays:** `minItems`, `maxItems`38613862If you turn on Structured Outputs by supplying `strict: true` and call the API with an unsupported JSON Schema, you will receive an error.38633864#### For `anyOf`, the nested schemas must each be a valid JSON Schema per this subset38653866Here's an example supported anyOf schema:38673868```json3869{3870 "type": "object",3871 "properties": {3872 "item": {3873 "anyOf": [3874 {3875 "type": "object",3876 "description": "The user object to insert into the database",3877 "properties": {3878 "name": {3879 "type": "string",3880 "description": "The name of the user"3881 },3882 "age": {3883 "type": "number",3884 "description": "The age of the user"3885 }3886 },3887 "additionalProperties": false,3888 "required": [3889 "name",3890 "age"3891 ]3892 },3893 {3894 "type": "object",3895 "description": "The address object to insert into the database",3896 "properties": {3897 "number": {3898 "type": "string",3899 "description": "The number of the address. Eg. for 123 main st, this would be 123"3900 },3901 "street": {3902 "type": "string",3903 "description": "The street name. Eg. for 123 main st, this would be main st"3904 },3905 "city": {3906 "type": "string",3907 "description": "The city of the address"3908 }3909 },3910 "additionalProperties": false,3911 "required": [3912 "number",3913 "street",3914 "city"3915 ]3916 }3917 ]3918 }3919 },3920 "additionalProperties": false,3921 "required": [3922 "item"3923 ]3924}3925```392639273928#### Definitions are supported39293930You can use definitions to define subschemas which are referenced throughout your schema. The following is a simple example.39313932```json3933{3934 "type": "object",3935 "properties": {3936 "steps": {3937 "type": "array",3938 "items": {3939 "$ref": "#/$defs/step"3940 }3941 },3942 "final_answer": {3943 "type": "string"3944 }3945 },3946 "$defs": {3947 "step": {3948 "type": "object",3949 "properties": {3950 "explanation": {3951 "type": "string"3952 },3953 "output": {3954 "type": "string"3955 }3956 },3957 "required": [3958 "explanation",3959 "output"3960 ],3961 "additionalProperties": false3962 }3963 },3964 "required": [3965 "steps",3966 "final_answer"3967 ],3968 "additionalProperties": false3969}3970```397139723973#### Recursive schemas are supported39743975Sample recursive schema using `#` to indicate root recursion.39763977```json3978{3979 "name": "ui",3980 "description": "Dynamically generated UI",3981 "strict": true,3982 "schema": {3983 "type": "object",3984 "properties": {3985 "type": {3986 "type": "string",3987 "description": "The type of the UI component",3988 "enum": ["div", "button", "header", "section", "field", "form"]3989 },3990 "label": {3991 "type": "string",3992 "description": "The label of the UI component, used for buttons or form fields"3993 },3994 "children": {3995 "type": "array",3996 "description": "Nested UI components",3997 "items": {3998 "$ref": "#"3999 }4000 },4001 "attributes": {4002 "type": "array",4003 "description": "Arbitrary attributes for the UI component, suitable for any element",4004 "items": {4005 "type": "object",4006 "properties": {4007 "name": {4008 "type": "string",4009 "description": "The name of the attribute, for example onClick or className"4010 },4011 "value": {4012 "type": "string",4013 "description": "The value of the attribute"4014 }4015 },4016 "additionalProperties": false,4017 "required": ["name", "value"]4018 }4019 }4020 },4021 "required": ["type", "label", "children", "attributes"],4022 "additionalProperties": false4023 }4024}4025```402640274028Sample recursive schema using explicit recursion:40294030```json4031{4032 "type": "object",4033 "properties": {4034 "linked_list": {4035 "$ref": "#/$defs/linked_list_node"4036 }4037 },4038 "$defs": {4039 "linked_list_node": {4040 "type": "object",4041 "properties": {4042 "value": {4043 "type": "number"4044 },4045 "next": {4046 "anyOf": [4047 {4048 "$ref": "#/$defs/linked_list_node"4049 },4050 {4051 "type": "null"4052 }4053 ]4054 }4055 },4056 "additionalProperties": false,4057 "required": [4058 "next",4059 "value"4060 ]4061 }4062 },4063 "additionalProperties": false,4064 "required": [4065 "linked_list"4066 ]4067}4068```4069407040714072## JSON mode40734074JSON mode is a more basic version of the Structured Outputs feature. While4075 JSON mode ensures that model output is valid JSON, Structured Outputs reliably4076 matches the model's output to the schema you specify. We recommend you use4077 Structured Outputs if it is supported for your use case.40784079When JSON mode is turned on, the model's output is ensured to be valid JSON, except for in some edge cases that you should detect and handle appropriately.40804081408240834084To turn on JSON mode with the Responses API you can set the `text.format` to `{ "type": "json_object" }`. If you are using function calling, JSON mode is always turned on.408540864087Important notes:40884089- When using JSON mode, you must always instruct the model to produce JSON via some message in the conversation, for example via your system message. If you don't include an explicit instruction to generate JSON, the model may generate an unending stream of whitespace and the request may run continually until it reaches the token limit. To help ensure you don't forget, the API will throw an error if the string "JSON" does not appear somewhere in the context.4090- JSON mode will not guarantee the output matches any specific schema, only that it is valid and parses without errors. You should use Structured Outputs to ensure it matches your schema, or if that is not possible, you should use a validation library and potentially retries to ensure that the output matches your desired schema.4091- Your application must detect and handle the edge cases that can result in the model output not being a complete JSON object (see below)4092409340944095### Handling edge cases409640974098409941004101```javascript4102const we_did_not_specify_stop_tokens = true;41034104try {4105 const response = await openai.responses.create({4106 model: "gpt-6-astra",4107 input: [4108 {4109 role: "system",4110 content: "You are a helpful assistant designed to output JSON.",4111 },4112 {4113 role: "user",4114 content:4115 "Who won the world series in 2020? Please respond in the format {winner: ...}",4116 },4117 ],4118 text: { format: { type: "json_object" } },4119 });41204121 const message = response.output.find((item) => item.type === "message");4122 const messageContent = message?.content[0];41234124 // Check if the conversation was too long for the context window, resulting in incomplete JSON4125 if (4126 response.status === "incomplete" &&4127 response.incomplete_details.reason === "max_output_tokens"4128 ) {4129 // your code should handle this error case4130 }41314132 // Check if the OpenAI safety system refused the request and generated a refusal instead4133 if (messageContent?.type === "refusal") {4134 // your code should handle this error case4135 // In this case, the .content field will contain the explanation (if any) that the model generated for why it is refusing4136 console.log(messageContent.refusal);4137 }41384139 // Check if the model's output included restricted content, so the generation of JSON was halted and may be partial4140 if (4141 response.status === "incomplete" &&4142 response.incomplete_details.reason === "content_filter"4143 ) {4144 // your code should handle this error case4145 }41464147 if (response.status === "completed") {4148 // In this case the model has either successfully finished generating the JSON object according to your schema, or the model generated one of the tokens you provided as a "stop token"41494150 if (we_did_not_specify_stop_tokens) {4151 // If you didn't specify any stop tokens, then the generation is complete and the content key will contain the serialized JSON object4152 // This will parse successfully and should now contain {"winner": "Los Angeles Dodgers"}4153 console.log(JSON.parse(response.output_text));4154 } else {4155 // Check if the response.output_text ends with one of your stop tokens and handle appropriately4156 }4157 }4158} catch (e) {4159 // Your code should handle errors here, for example a network error calling the API4160 console.error(e);4161}4162```41634164```python4165we_did_not_specify_stop_tokens = True41664167try:4168 response = client.responses.create(4169 model="gpt-6-astra",4170 input=[4171 {4172 "role": "system",4173 "content": "You are a helpful assistant designed to output JSON.",4174 },4175 {4176 "role": "user",4177 "content": 'Who won the World Series in 2020? Respond as {"winner": "team name"}.',4178 },4179 ],4180 text={"format": {"type": "json_object"}},4181 )41824183 message = next((item for item in response.output if item.type == "message"), None)4184 message_content = message.content[0] if message and message.content else None41854186 # Check if the conversation was too long for the context window, resulting in incomplete JSON4187 if (4188 response.status == "incomplete"4189 and response.incomplete_details.reason == "max_output_tokens"4190 ):4191 raise RuntimeError("The response was truncated before the JSON completed.")41924193 # Check if the OpenAI safety system refused the request and generated a refusal instead4194 if message_content and message_content.type == "refusal":4195 # your code should handle this error case4196 # In this case, the .content field will contain the explanation (if any) that the model generated for why it is refusing4197 print(message_content.refusal)41984199 # Check if the model's output included restricted content, so the generation of JSON was halted and may be partial4200 if (4201 response.status == "incomplete"4202 and response.incomplete_details.reason == "content_filter"4203 ):4204 raise RuntimeError("The response was interrupted by the content filter.")42054206 if response.status == "completed":4207 # In this case the model has either successfully finished generating the JSON object according to your schema, or the model generated one of the tokens you provided as a "stop token"42084209 if we_did_not_specify_stop_tokens:4210 # If you didn't specify any stop tokens, then the generation is complete and the content key will contain the serialized JSON object4211 # This will parse successfully and should now contain "{"winner": "Los Angeles Dodgers"}"4212 print(response.output_text)4213except Exception as e:4214 # Your code should handle errors here, for example a network error calling the API4215 print(e)4216```42174218```go4219package main42204221import (4222 "context"4223 "encoding/json"4224 "fmt"42254226 "github.com/openai/openai-go/v3"4227 "github.com/openai/openai-go/v3/responses"4228 "github.com/openai/openai-go/v3/shared"4229)42304231func main() {4232 client := openai.NewClient()4233 response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{4234 Model: "gpt-6-astra",4235 Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{4236 responses.ResponseInputItemParamOfMessage(4237 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are a helpful assistant designed to output JSON.")},4238 responses.EasyInputMessageRoleSystem,4239 ),4240 responses.ResponseInputItemParamOfMessage(4241 responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("Who won the world series in 2020? Please respond in the format {winner: ...}")},4242 responses.EasyInputMessageRoleUser,4243 ),4244 }},4245 Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{4246 OfJSONObject: &shared.ResponseFormatJSONObjectParam{},4247 }},4248 })4249 if err != nil {4250 panic(err)4251 }42524253 if response.Status == "incomplete" {4254 fmt.Println("The JSON response is incomplete.")4255 return4256 }4257 for _, output := range response.Output {4258 if output.Type != "message" {4259 continue4260 }4261 for _, content := range output.AsMessage().Content {4262 if content.Type == "refusal" {4263 fmt.Println(content.AsRefusal().Refusal)4264 return4265 }4266 }4267 }4268 if response.Status == "completed" {4269 var value map[string]any4270 if err := json.Unmarshal([]byte(response.OutputText()), &value); err != nil {4271 panic(err)4272 }4273 fmt.Println(value)4274 }4275}4276```42774278```java4279import com.openai.client.OpenAIClient;4280import com.openai.client.okhttp.OpenAIOkHttpClient;4281import com.openai.errors.OpenAIServiceException;4282import com.openai.models.ResponseFormatJsonObject;4283import com.openai.models.responses.EasyInputMessage;4284import com.openai.models.responses.ResponseCreateParams;4285import com.openai.models.responses.ResponseInputItem;4286import com.openai.models.responses.ResponseStatus;4287import com.openai.models.responses.ResponseTextConfig;4288import java.util.List;42894290ResponseCreateParams params =4291 ResponseCreateParams.builder()4292 .model("gpt-6-astra")4293 .inputOfResponse(4294 List.of(4295 ResponseInputItem.ofEasyInputMessage(4296 EasyInputMessage.builder()4297 .role(EasyInputMessage.Role.SYSTEM)4298 .content("You are a helpful assistant designed to output JSON.")4299 .build()),4300 ResponseInputItem.ofEasyInputMessage(4301 EasyInputMessage.builder()4302 .role(EasyInputMessage.Role.USER)4303 .content(4304 "Who won the World Series in 2020? Respond in the format {winner: ...}.")4305 .build())))4306 .text(4307 ResponseTextConfig.builder()4308 .format(ResponseFormatJsonObject.builder().build())4309 .build())4310 .build();43114312try {4313 var response = client.responses().create(params);4314 if (response.status().filter(ResponseStatus.INCOMPLETE::equals).isPresent()) {4315 String reason =4316 response4317 .incompleteDetails()4318 .flatMap(details -> details.reason())4319 .map(Object::toString)4320 .orElse("unknown");4321 System.out.println("The JSON response is incomplete. Reason: " + reason);4322 return;4323 }43244325 for (var output : response.output()) {4326 if (output.message().isEmpty()) continue;4327 for (var content : output.message().orElseThrow().content()) {4328 if (content.refusal().isPresent()) {4329 System.out.println(content.refusal().orElseThrow().refusal());4330 return;4331 }4332 if (response.status().filter(ResponseStatus.COMPLETED::equals).isPresent()) {4333 content.outputText().ifPresent(text -> System.out.println(text.text()));4334 }4335 }4336 }4337} catch (OpenAIServiceException error) {4338 System.out.println("Request failed: " + error.getMessage());4339}4340```43414342```csharp4343using OpenAI.Responses;4344#pragma warning disable OPENAI00143454346string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;4347ResponsesClient client = new(key);43484349CreateResponseOptions options = new()4350{4351 Model = "gpt-6-astra",4352 TextOptions = new ResponseTextOptions4353 {4354 TextFormat = ResponseTextFormat.CreateJsonObjectFormat(),4355 },4356};4357options.InputItems.Add(ResponseItem.CreateSystemMessageItem("You are a helpful assistant designed to output JSON."));4358options.InputItems.Add(ResponseItem.CreateUserMessageItem("Who won the World Series in 2020? Respond with the winner in JSON."));43594360ResponseResult response = await client.CreateResponseAsync(options);4361if (4362 response.Status == ResponseStatus.Incomplete4363 && response.IncompleteStatusDetails?.Reason == ResponseIncompleteStatusReason.MaxOutputTokens4364)4365{4366 Console.WriteLine("The response was truncated before the JSON completed.");4367}4368else if (4369 response.Status == ResponseStatus.Incomplete4370 && response.IncompleteStatusDetails?.Reason == ResponseIncompleteStatusReason.ContentFilter4371)4372{4373 Console.WriteLine("The response was interrupted by the content filter.");4374}4375else if (response.Status == ResponseStatus.Completed)4376{4377 MessageResponseItem message = response.OutputItems.OfType<MessageResponseItem>().FirstOrDefault()4378 ?? throw new InvalidOperationException("The response did not include an output message.");4379 ResponseContentPart content = message.Content.FirstOrDefault()4380 ?? throw new InvalidOperationException("The response did not include output content.");4381 Console.WriteLine(4382 content.Kind == ResponseContentPartKind.Refusal ? content.Refusal : content.Text4383 );4384}4385else4386{4387 throw new InvalidOperationException($"The response ended with status: {response.Status}");4388}4389```43904391```ruby4392require "json"4393require "openai"43944395client = OpenAI::Client.new4396response = client.responses.create(4397 model: "gpt-6-astra",4398 input: [4399 {4400 role: :system,4401 content: "You are a helpful assistant designed to output JSON."4402 },4403 {4404 role: :user,4405 content: "Who won the World Series in 2020? Respond in the format {winner: ...}."4406 }4407 ],4408 text: { format: { type: :json_object } }4409)44104411if response.status == OpenAI::Responses::ResponseStatus::INCOMPLETE4412 warn("The JSON response is incomplete.")4413else4414 refusal = response.output4415 .grep(OpenAI::Models::Responses::ResponseOutputMessage)4416 .flat_map(&:content)4417 .find { |content| content.is_a?(OpenAI::Models::Responses::ResponseOutputRefusal) }44184419 if refusal.is_a?(OpenAI::Models::Responses::ResponseOutputRefusal)4420 puts(refusal.refusal)4421 elsif response.status == OpenAI::Responses::ResponseStatus::COMPLETED4422 puts(JSON.pretty_generate(JSON.parse(response.output_text)))4423 end4424end4425```44264427442844294430443144324433## Resources44344435To learn more about Structured Outputs, we recommend browsing the following resources:44364437- Check out our [introductory cookbook](https://developers.openai.com/cookbook/examples/structured_outputs_intro) on Structured Outputs4438- Learn [how to build multi-agent systems](https://developers.openai.com/cookbook/examples/structured_outputs_multi_agent) with Structured Outputs