Udostępnij za pośrednictwem


Dane wyjściowe ze strukturą

Dane wyjściowe ze strukturą tworzą model zgodnie z definicją schematu JSON, którą podajesz w ramach wywołania interfejsu API wnioskowania. Jest to w przeciwieństwie do starszej funkcji trybu JSON, która gwarantuje prawidłowy kod JSON zostanie wygenerowany, ale nie była w stanie zapewnić ścisłego przestrzegania podanego schematu. Dane wyjściowe ze strukturą są zalecane w przypadku wywoływania funkcji, wyodrębniania danych strukturalnych i tworzenia złożonych wieloetapowych przepływów pracy.

Uwaga

Obecnie ustrukturyzowane dane wyjściowe nie są obsługiwane za pomocą następujących funkcji:

Obsługiwane modele

  • o3-mini Wersja 2025-01-31
  • o1 Wersja: 2024-12-17
  • gpt-4o-mini Wersja: 2024-07-18
  • gpt-4o Wersja: 2024-08-06

Obsługa interfejsu API

Obsługa danych wyjściowych ze strukturą została po raz pierwszy dodana w wersji 2024-08-01-previewinterfejsu API . Jest ona dostępna w najnowszych interfejsach API w wersji zapoznawczej, a także w najnowszym interfejsie API ga: 2024-10-21.

Wprowadzenie

Można użyć Pydantic do definiowania schematów obiektów w języku Python. W zależności od używanej wersji interfejsu OpenAI i Pydantic bibliotek może być konieczne uaktualnienie do nowszej wersji. Te przykłady zostały przetestowane pod kątem openai 1.42.0 elementów i pydantic 2.8.2.

pip install openai pydantic --upgrade

Jeśli dopiero zaczynasz używać identyfikatora Entra firmy Microsoft do uwierzytelniania, zobacz Jak skonfigurować usługę Azure OpenAI przy użyciu uwierzytelniania identyfikatora Entra firmy Microsoft.

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))

Wyjście

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
  }
}

Wywoływanie funkcji za pomocą danych wyjściowych ze strukturą

Dane wyjściowe ze strukturą dla wywoływania funkcji można włączyć za pomocą jednego parametru, podając strict: truewartość .

Uwaga

Dane wyjściowe ze strukturą nie są obsługiwane w przypadku wywołań funkcji równoległych. W przypadku używania danych wyjściowych ze strukturą ustawioną na parallel_tool_callsfalsewartość .

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))

Wprowadzenie

Dodaj następujące pakiety do projektu, aby pracować z usługą Azure OpenAI:

dotnet add package Azure.AI.OpenAI --prerelease
dotnet add package Azure.Identity
dotnet add package Newtonsoft.Json.Schema

Jeśli dopiero zaczynasz używać identyfikatora Entra firmy Microsoft do uwierzytelniania, zobacz Jak skonfigurować usługę Azure OpenAI przy użyciu uwierzytelniania identyfikatora Entra firmy Microsoft.

using Azure.AI.OpenAI;
using Azure.Identity;
using Newtonsoft.Json.Schema.Generation;
using OpenAI.Chat;
using System.ClientModel;

// Create the clients
string endpoint = GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");

AzureOpenAIClient openAIClient = new(
    new Uri(endpoint),
    new DefaultAzureCredential());

var client = openAIClient.GetChatClient("gpt-4o");

// Create a chat with initial prompts
var chat = new List<ChatMessage>()
    {
         new SystemChatMessage("Extract the event information and projected weather."),
         new UserChatMessage("Alice and Bob are going to a science fair in Seattle on June 1st, 2025.")
    };

// Get the schema of the class for the structured response
JSchemaGenerator generator = new JSchemaGenerator();
var jsonSchema = generator.Generate(typeof(CalendarEvent)).ToString();

// Get a completion with structured output
var chatUpdates = client.CompleteChatStreamingAsync(
        chat,
        new ChatCompletionOptions()
        {
            ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
                        "calenderEvent",
                        BinaryData.FromString(jsonSchema))
        });

// Write the structured response
await foreach (var chatUpdate in chatUpdates)
{
    foreach (var contentPart in chatUpdate.ContentUpdate)
    {
        Console.Write(contentPart.Text);
    }
}

// The class for the structured response
public class CalendarEvent()
{
    public string Name { get; set; }
    public string Date { get; set; }
    public List<string> Participants { get; set; }
}

Wywoływanie funkcji za pomocą danych wyjściowych ze strukturą

Dane wyjściowe ze strukturą dla wywoływania funkcji można włączyć za pomocą jednego parametru, podając strict: truewartość .

using Azure.AI.OpenAI;
using Newtonsoft.Json.Schema.Generation;
using OpenAI.Chat;
using System.ClientModel;

// Create the clients
string endpoint = GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");

AzureOpenAIClient openAIClient = new(
    new Uri(endpoint),
    new DefaultAzureCredential());

var chatClient = openAIClient.GetChatClient("gpt-4o");

// Local function to be used by the assistant tooling
string GetTemperature(string location, string date)
{
    // Placeholder for Weather API
    if(location == "Seattle" && date == "2025-06-01")
    {
        return "75";
    }

    return "50";
}

// Create a tool to get the temperature
ChatTool GetTemperatureTool = ChatTool.CreateFunctionTool(
    functionName: nameof(GetTemperature),
    functionSchemaIsStrict: true,
    functionDescription: "Get the projected temperature by date and location.",
    functionParameters: BinaryData.FromBytes("""
        {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The location of the weather."
                },
                "date": {
                    "type": "string",
                    "description": "The date of the projected weather."
                }
            },
            "required": ["location", "date"],
            "additionalProperties": false  
        }
        """u8.ToArray())
);

// Create a chat with prompts
var chat = new List<ChatMessage>()
    {
         new SystemChatMessage("Extract the event information and projected weather."),
         new UserChatMessage("Alice and Bob are going to a science fair in Seattle on June 1st, 2025.")
    };

// Create a JSON schema for the CalendarEvent structured response
JSchemaGenerator generator = new JSchemaGenerator();
var jsonSchema = generator.Generate(typeof(CalendarEvent)).ToString();

// Get a chat completion from the AI model
var completion = chatClient.CompleteChat(
        chat,
        new ChatCompletionOptions()
        {
            ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
                "calenderEvent",
                BinaryData.FromString(jsonSchema)),
            Tools = { GetTemperatureTool }
        });

Console.WriteLine(completion.Value.ToolCalls[0].FunctionName);

// Structured response class
public class CalendarEvent()
{
    public string Name { get; set; }
    public string Date { get; set; }
    public string Temperature { get; set; }
    public List<string> Participants { get; set; }
}

Wprowadzenie

response_format jest ustawiona na json_schema wartość z zestawem strict: true .

curl -X POST  https://YOUR_RESOURCE_NAME.openai.azure.com/openai/deployments/YOUR_MODEL_DEPLOYMENT_NAME/chat/completions?api-version=2024-10-21 \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
    -d '{
        "messages": [
                {"role": "system", "content": "Extract the event information."},
                {"role": "user", "content": "Alice and Bob are going to a science fair on Friday."}
            ],
            "response_format": {
                "type": "json_schema",
                "json_schema": {
                    "name": "CalendarEventResponse",
                    "strict": true,
                    "schema": {
                        "type": "object",
                        "properties": {
                            "name": {
                              "type": "string"
                            },
                            "date": {
                                "type": "string"
                            },
                            "participants": {
                                "type": "array",
                                "items": {
                                    "type": "string"
                                }
                            }
                        },
                        "required": [
                            "name",
                            "date",
                            "participants"
                        ],
                        "additionalProperties": false
                    }
                }
          }
  }'

Wyjście:

{
  "id": "chatcmpl-A1HKsHAe2hH9MEooYslRn9UmEwsag",
  "object": "chat.completion",
  "created": 1724868330,
  "model": "gpt-4o-2024-08-06",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "{\n  \"name\": \"Science Fair\",\n  \"date\": \"Friday\",\n  \"participants\": [\"Alice\", \"Bob\"]\n}"
      },
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 33,
    "completion_tokens": 27,
    "total_tokens": 60
  },
  "system_fingerprint": "fp_1c2eaec9fe"
}

Wywoływanie funkcji za pomocą danych wyjściowych ze strukturą

curl -X POST  https://YOUR_RESOURCE_NAME.openai.azure.com/openai/deployments/YOUR_MODEL_DEPLOYMENT_NAME/chat/completions?api-version=2024-10-21 \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "messages": [
    {
      "role": "system",
      "content": "You are a helpful assistant. The current date is August 6, 2024. You help users query for the data they are looking for by calling the query function."
    },
    {
      "role": "user",
      "content": "look up all my orders in may of last year that were fulfilled but not delivered on time"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "query",
        "description": "Execute a query.",
        "strict": true,
        "parameters": {
          "type": "object",
          "properties": {
            "table_name": {
              "type": "string",
              "enum": ["orders"]
            },
            "columns": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "id",
                  "status",
                  "expected_delivery_date",
                  "delivered_at",
                  "shipped_at",
                  "ordered_at",
                  "canceled_at"
                ]
              }
            },
            "conditions": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "column": {
                    "type": "string"
                  },
                  "operator": {
                    "type": "string",
                    "enum": ["=", ">", "<", ">=", "<=", "!="]
                  },
                  "value": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "object",
                        "properties": {
                          "column_name": {
                            "type": "string"
                          }
                        },
                        "required": ["column_name"],
                        "additionalProperties": false
                      }
                    ]
                  }
                },
                "required": ["column", "operator", "value"],
                "additionalProperties": false
              }
            },
            "order_by": {
              "type": "string",
              "enum": ["asc", "desc"]
            }
          },
          "required": ["table_name", "columns", "conditions", "order_by"],
          "additionalProperties": false
        }
      }
    }
  ]
}'

Obsługiwane schematy i ograniczenia

Dane wyjściowe ze strukturą usługi Azure OpenAI obsługują ten sam podzestaw schematu JSON co interfejs OpenAI.

Obsługiwane typy

  • String
  • Liczba
  • Wartość logiczna
  • Integer
  • Objekt
  • Tablica
  • Wyliczenie
  • anyOf

Uwaga

Obiekty główne nie mogą być typem anyOf .

Wszystkie pola muszą być wymagane

Wszystkie pola lub parametry funkcji muszą być dołączone zgodnie z wymaganiami. W poniższym locationprzykładzie wartości i unit są określone w obszarze "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"]
    }

W razie potrzeby można emulować opcjonalny parametr przy użyciu typu unii z null. W tym przykładzie jest to osiągane za pomocą wiersza "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"
        ]
    }
}

Głębokość zagnieżdżania

Schemat może mieć maksymalnie 100 właściwości obiektu łącznie z maksymalnie pięcioma poziomami zagnieżdżania

additionalProperties: wartość false musi być zawsze ustawiana w obiektach

Ta właściwość określa, czy obiekt może mieć dodatkowe pary wartości klucza, które nie zostały zdefiniowane w schemacie JSON. Aby można było używać danych wyjściowych ze strukturą, należy ustawić tę wartość na false.

Kolejność kluczy

Dane wyjściowe ze strukturą są uporządkowane tak samo jak podany schemat. Aby zmienić kolejność danych wyjściowych, zmodyfikuj kolejność schematu wysyłanego w ramach żądania wnioskowania.

Nieobsługiwane słowa kluczowe specyficzne dla typu

Typ Nieobsługiwane słowo kluczowe
String minlength
maxLength
pattern
format
Liczba minimum
maksimum
multipleOf
Obiekty patternProperties
nieowartościowaneWłaściwości
propertyNames
minProperties
maxProperties
Tablice unevaluatedItems
Contains
minContains
maxContains
minItems
maxItems
uniqueItems

Schematy zagnieżdżone używające elementu anyOf muszą być zgodne z ogólnym podzbiorem schematu JSON

Przykładowy obsługiwany anyOf schemat:

{
    "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"
    ]
}

Obsługiwane są definicje

Obsługiwany przykład:

{
    "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
}

Schematy cykliczne są obsługiwane

Przykład użycia #dla rekursji głównej:

{
        "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
        }
    }

Przykład jawnej rekursji:

{
    "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"
    ]
}