I want to use structured output with Azure OpenAI.
I tried the following code, based on the code given in https://openai.com/index/introducing-structured-outputs-in-the-api/:
from pydantic import BaseModel
from openai import AzureOpenAI
class Step(BaseModel):
explanation: str
output: str
class MathResponse(BaseModel):
steps: list[Step]
final_answer: str
client = AzureOpenAI(api_key='[redacted]',
api_version='2024-05-01-preview',
azure_endpoint='[redacted]')
completion = client.beta.chat.completions.parse(
model="gpt-4omini-2024-07-18-name",
messages=[
{"role": "system", "content": "You are a helpful math tutor."},
{"role": "user", "content": "solve 8x + 31 = 2"},
],
response_format=MathResponse,
)
message = completion.choices[0].message
if message.parsed:
print(message.parsed.steps)
print(message.parsed.final_answer)
else:
print(message.refusal)
I get the error:
openai.BadRequestError: Error code: 400:
{
"error": {
"message": "Invalid parameter: response_format must be one of json_object, text.",
"type": "invalid_request_error",
"param": "response_format",
"code": "None"
}
}
How to fix it?
I ran pip install -U openai
: I use openai==1.40.1
and Python 3.11.
I also tried https://cookbook.openai.com/examples/structured_outputs_intro using using Azure+ GPT-4o mini (2024-07-18), it didn't work either, same error message:
from openai import AzureOpenAI
# Replace these variables with your Azure OpenAI endpoint and API key
endpoint = "https://<your-resource-name>.openai.azure.com"
api_key = "<your-api-key>"
deployment_name = "<your-deployment-name>" # Replace with your deployment name
MODEL = deployment_name
# API endpoint for the completion request
api_url = f"{endpoint}/openai/deployments/{deployment_name}/chat/completions?api-version=2024-06-01"
client = AzureOpenAI(api_key='[redacted]',
api_version='2024-07-01-preview',
azure_endpoint='https://[redacted].openai.azure.com/')
math_tutor_prompt = '''
You are a helpful math tutor. You will be provided with a math problem,
and your goal will be to output a step by step solution, along with a final answer.
For each step, just provide the output as an equation use the explanation field to detail the reasoning.
'''
def get_math_solution(question):
response = client.chat.completions.create(
model=MODEL,
messages=[
{
"role": "system",
"content": math_tutor_prompt
},
{
"role": "user",
"content": question
}
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "math_reasoning",
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {"type": "string"},
"output": {"type": "string"}
},
"required": ["explanation", "output"],
"additionalProperties": False
}
},
"final_answer": {"type": "string"}
},
"required": ["steps", "final_answer"],
"additionalProperties": False
},
"strict": True
}
}
)
return response.choices[0].message
# Testing with an example question
question = "how can I solve 8x + 7 = -23"
result = get_math_solution(question)
print(result.content)
Using gpt-4o-2024-08-06
, which finally got deployed today (2024-09-03) on Azure, made it work. Code example from learn.microsoft.com:
from pydantic import BaseModel
from openai import AzureOpenAI
endpoint = "https://your-azure-openai-endpoint.com"
api_key = "your-azure-openai-key"
deployment_name = 'deployment name' # Replace with your gpt-4o 2024-08-06 deployment name
client = AzureOpenAI(api_key=api_key,
api_version='2024-08-01-preview',
azure_endpoint=endpoint)
class CalendarEvent(BaseModel):
name: str
date: str
participants: list[str]
completion = client.beta.chat.completions.parse(
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))
output:
name='Science Fair' date='Friday' participants=['Alice', 'Bob']
{
"id": "chatcmpl-A3XDRVolXpjeAAQIGddswI990weid",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"logprobs": null,
"message": {
"content": "{\"name\":\"Science Fair\",\"date\":\"Friday\",\"participants\":[\"Alice\",\"Bob\"]}",
"refusal": null,
"role": "assistant",
"function_call": null,
"tool_calls": [],
"parsed": {
"name": "Science Fair",
"date": "Friday",
"participants": [
"Alice",
"Bob"
]
}
},
"content_filter_results": {
"hate": {
"filtered": false,
"severity": "safe"
},
"self_harm": {
"filtered": false,
"severity": "safe"
},
"sexual": {
"filtered": false,
"severity": "safe"
},
"violence": {
"filtered": false,
"severity": "safe"
}
}
}
],
"created": 1725406029,
"model": "gpt-4o-2024-08-06",
"object": "chat.completion",
"service_tier": null,
"system_fingerprint": "fp_b2ffeb31ff",
"usage": {
"completion_tokens": 17,
"prompt_tokens": 32,
"total_tokens": 49
},
"prompt_filter_results": [
{
"prompt_index": 0,
"content_filter_results": {
"hate": {
"filtered": false,
"severity": "safe"
},
"self_harm": {
"filtered": false,
"severity": "safe"
},
"sexual": {
"filtered": false,
"severity": "safe"
},
"violence": {
"filtered": false,
"severity": "safe"
}
}
}
]
}
Tested with Python 3.11.7 and openai==1.43.0.