다음을 통해 공유


구조적 출력

구조적 출력을 통해 모델은 추론 API 호출의 일부로 제공하는 JSON 스키마 정의를 따르게 됩니다. 이는 유효한 JSON이 생성되지만 제공된 스키마를 엄격하게 준수할 수 없는 이전 JSON 모드 기능과는 대조적입니다. 구조적 출력은 함수 호출, 구조적 데이터 추출 및 복잡한 다단계 워크플로 빌드에 권장됩니다.

참고 항목

지원되는 모델

  • o1 버전: 2024-12-17
  • gpt-4o-mini 버전: 2024-07-18
  • gpt-4o 버전: 2024-08-06

API 지원

구조적 출력에 대한 지원은 API 버전 2024-08-01-preview에 처음 추가되었습니다. 최신 미리 보기 API 및 최신 GA API 2024-10-21에서 사용할 수 있습니다.

시작

Pydantic을 사용하여 Python에서 개체 스키마를 정의할 수 있습니다. 실행 중인 OpenAIPydantic 라이브러리의 버전에 따라 최신 버전으로 업그레이드해야 할 수 있습니다. 이러한 예제는 openai 1.42.0pydantic 2.8.2대해 테스트되었습니다.

pip install openai pydantic --upgrade

인증에 Microsoft Entra ID를 사용하는 경우 Microsoft Entra ID 인증을 사용하여 Azure OpenAI 서비스를 구성하는 방법을 참조하세요.

from pydantic import BaseModel
from openai import AzureOpenAI
from azure.identity import DefaultAzureCredential, get_bearer_token_provider

token_provider = get_bearer_token_provider(
    DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default"
)

client = AzureOpenAI(
  azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"), 
  azure_ad_token_provider=token_provider,
  api_version="2024-10-21"
)


class CalendarEvent(BaseModel):
    name: str
    date: str
    participants: list[str]

completion = client.beta.chat.completions.parse(
    model="MODEL_DEPLOYMENT_NAME", # replace with the model deployment name of your gpt-4o 2024-08-06 deployment
    messages=[
        {"role": "system", "content": "Extract the event information."},
        {"role": "user", "content": "Alice and Bob are going to a science fair on Friday."},
    ],
    response_format=CalendarEvent,
)

event = completion.choices[0].message.parsed

print(event)
print(completion.model_dump_json(indent=2))

출력

name='Science Fair' date='Friday' participants=['Alice', 'Bob']
{
  "id": "chatcmpl-A1EUP2fAmL4SeB1lVMinwM7I2vcqG",
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "logprobs": null,
      "message": {
        "content": "{\n  \"name\": \"Science Fair\",\n  \"date\": \"Friday\",\n  \"participants\": [\"Alice\", \"Bob\"]\n}",
        "refusal": null,
        "role": "assistant",
        "function_call": null,
        "tool_calls": [],
        "parsed": {
          "name": "Science Fair",
          "date": "Friday",
          "participants": [
            "Alice",
            "Bob"
          ]
        }
      }
    }
  ],
  "created": 1724857389,
  "model": "gpt-4o-2024-08-06",
  "object": "chat.completion",
  "service_tier": null,
  "system_fingerprint": "fp_1c2eaec9fe",
  "usage": {
    "completion_tokens": 27,
    "prompt_tokens": 32,
    "total_tokens": 59
  }
}

구조적 출력을 사용한 함수 호출

함수 호출을 위한 구조적 출력은 strict: true를 제공하여 단일 매개 변수를 통해 사용하도록 설정할 수 있습니다.

참고 항목

구조적 출력은 병렬 함수 호출에서는 지원되지 않습니다. 구조적 출력을 사용하는 경우 parallel_tool_callsfalse로 설정합니다.

from enum import Enum
from typing import Union
from pydantic import BaseModel
import openai
from openai import AzureOpenAI

client = AzureOpenAI(
  azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"), 
  api_key=os.getenv("AZURE_OPENAI_API_KEY"),  
  api_version="2024-10-21"
)


class GetDeliveryDate(BaseModel):
    order_id: str

tools = [openai.pydantic_function_tool(GetDeliveryDate)]

messages = []
messages.append({"role": "system", "content": "You are a helpful customer support assistant. Use the supplied tools to assist the user."})
messages.append({"role": "user", "content": "Hi, can you tell me the delivery date for my order #12345?"}) 

response = client.chat.completions.create(
    model="MODEL_DEPLOYMENT_NAME", # replace with the model deployment name of your gpt-4o 2024-08-06 deployment
    messages=messages,
    tools=tools
)

print(response.choices[0].message.tool_calls[0].function)
print(response.model_dump_json(indent=2))

지원되는 스키마 및 제한 사항

Azure OpenAI 구조적 출력은 OpenAI와 동일한 JSON 스키마 하위 집합을 지원합니다.

지원되는 유형

  • 문자열
  • 숫자
  • Boolean
  • 정수
  • Object
  • Array
  • 열거형
  • anyOf

참고 항목

루트 개체는 anyOf 형식일 수 없습니다.

모든 필드는 필수 항목임

모든 필드 또는 함수 매개 변수는 필수로 포함되어야 합니다. 아래 예제에서는 locationunit가 모두 "required": ["location", "unit"] 아래에 지정되어 있습니다.

{
    "name": "get_weather",
    "description": "Fetches the weather in the given location",
    "strict": true,
    "parameters": {
        "type": "object",
        "properties": {
            "location": {
                "type": "string",
                "description": "The location to get the weather for"
            },
            "unit": {
                "type": "string",
                "description": "The unit to return the temperature in",
                "enum": ["F", "C"]
            }
        },
        "additionalProperties": false,
        "required": ["location", "unit"]
    }

필요한 경우 null과 함께 공용 구조체 형식을 사용하여 선택적 매개 변수를 에뮬레이트할 수 있습니다. 이 예제에서는 "type": ["string", "null"], 줄을 사용하여 이 작업을 수행합니다.

{
    "name": "get_weather",
    "description": "Fetches the weather in the given location",
    "strict": true,
    "parameters": {
        "type": "object",
        "properties": {
            "location": {
                "type": "string",
                "description": "The location to get the weather for"
            },
            "unit": {
                "type": ["string", "null"],
                "description": "The unit to return the temperature in",
                "enum": ["F", "C"]
            }
        },
        "additionalProperties": false,
        "required": [
            "location", "unit"
        ]
    }
}

중첩 깊이

스키마에는 최대 100개의 개체 속성과 최대 5개의 중첩 수준이 있을 수 있습니다.

additionalProperties: false는 항상 개체에서 설정해야 합니다.

이 속성은 개체가 JSON 스키마에 정의되지 않은 추가 키 값 쌍을 가질 수 있는지 여부를 제어합니다. 구조적 출력을 사용하려면 이 값을 false로 설정해야 합니다.

키 순서 지정

구조적 출력은 제공된 스키마와 동일한 순서로 지정됩니다. 출력 순서를 변경하려면 추론 요청의 일부로 보내는 스키마의 순서를 수정합니다.

지원되지 않는 형식별 키워드

Type 지원되지 않는 키워드
문자열 minlength
maxLength
pattern
format
숫자 minimum
maximum
multipleOf
개체 patternProperties
unevaluatedProperties
propertyNames
minProperties
maxProperties
배열 unevaluatedItems
contains
minContains
maxContains
minItems
maxItems
uniqueItems

anyOf를 사용하는 중첩된 스키마는 전체 JSON 스키마 하위 집합을 준수해야 합니다.

지원되는 anyOf 스키마의 예는 다음과 같습니다.

{
	"type": "object",
	"properties": {
		"item": {
			"anyOf": [
				{
					"type": "object",
					"description": "The user object to insert into the database",
					"properties": {
						"name": {
							"type": "string",
							"description": "The name of the user"
						},
						"age": {
							"type": "number",
							"description": "The age of the user"
						}
					},
					"additionalProperties": false,
					"required": [
						"name",
						"age"
					]
				},
				{
					"type": "object",
					"description": "The address object to insert into the database",
					"properties": {
						"number": {
							"type": "string",
							"description": "The number of the address. Eg. for 123 main st, this would be 123"
						},
						"street": {
							"type": "string",
							"description": "The street name. Eg. for 123 main st, this would be main st"
						},
						"city": {
							"type": "string",
							"description": "The city of the address"
						}
					},
					"additionalProperties": false,
					"required": [
						"number",
						"street",
						"city"
					]
				}
			]
		}
	},
	"additionalProperties": false,
	"required": [
		"item"
	]
}

정의가 지원됨

지원되는 예제:

{
	"type": "object",
	"properties": {
		"steps": {
			"type": "array",
			"items": {
				"$ref": "#/$defs/step"
			}
		},
		"final_answer": {
			"type": "string"
		}
	},
	"$defs": {
		"step": {
			"type": "object",
			"properties": {
				"explanation": {
					"type": "string"
				},
				"output": {
					"type": "string"
				}
			},
			"required": [
				"explanation",
				"output"
			],
			"additionalProperties": false
		}
	},
	"required": [
		"steps",
		"final_answer"
	],
	"additionalProperties": false
}

재귀 스키마가 지원됨

루트 재귀에 #을 사용하는 예제:

{
        "name": "ui",
        "description": "Dynamically generated UI",
        "strict": true,
        "schema": {
            "type": "object",
            "properties": {
                "type": {
                    "type": "string",
                    "description": "The type of the UI component",
                    "enum": ["div", "button", "header", "section", "field", "form"]
                },
                "label": {
                    "type": "string",
                    "description": "The label of the UI component, used for buttons or form fields"
                },
                "children": {
                    "type": "array",
                    "description": "Nested UI components",
                    "items": {
                        "$ref": "#"
                    }
                },
                "attributes": {
                    "type": "array",
                    "description": "Arbitrary attributes for the UI component, suitable for any element",
                    "items": {
                        "type": "object",
                        "properties": {
                            "name": {
                                "type": "string",
                                "description": "The name of the attribute, for example onClick or className"
                            },
                            "value": {
                                "type": "string",
                                "description": "The value of the attribute"
                            }
                        },
                      "additionalProperties": false,
                      "required": ["name", "value"]
                    }
                }
            },
            "required": ["type", "label", "children", "attributes"],
            "additionalProperties": false
        }
    }

명시적 재귀의 예:

{
	"type": "object",
	"properties": {
		"linked_list": {
			"$ref": "#/$defs/linked_list_node"
		}
	},
	"$defs": {
		"linked_list_node": {
			"type": "object",
			"properties": {
				"value": {
					"type": "number"
				},
				"next": {
					"anyOf": [
						{
							"$ref": "#/$defs/linked_list_node"
						},
						{
							"type": "null"
						}
					]
				}
			},
			"additionalProperties": false,
			"required": [
				"next",
				"value"
			]
		}
	},
	"additionalProperties": false,
	"required": [
		"linked_list"
	]
}