Specifying propertyOrdering
is the documented method of explicitly setting field order for structured outputs. This works as expected when using the google-genai
package, but does not appear to be respected when using the OpenAI compatible API at v1beta/openai
.
The response property order when using the v1beta/openapi
endpoint appears to be random.
This prevents reliable use of chain-of-thought prompting in structured outputs, where a reasoning or plan field is expected to be generated before a final output field.
Tested using gemini-2.0-flash
.
Reproducible Example
Environment:
Python 3.12.2
google==3.0.0
google-auth==2.40.2
google-genai==1.18.0
openai==1.82.1
pydantic==2.11.5
pydantic_core==2.33.2
from google import genai
from openai import OpenAI
from pydantic import BaseModel, Field, ConfigDict
GEMINI_API_KEY = "redacted"
N_TRIALS = 5
class OutputModel(BaseModel):
z: int = Field(..., description="The value of z")
y: int = Field(..., description="The value of y")
x: int = Field(..., description="The value of x")
model_config = ConfigDict(json_schema_extra={"propertyOrdering": ["z", "y", "x"]})
genai_client = genai.Client(api_key=GEMINI_API_KEY)
oai_client = OpenAI(
api_key=GEMINI_API_KEY,
base_url="https://generativelanguage.googleapis.com/v1beta/openai/",
)
for _ in range(N_TRIALS):
response = genai_client.models.generate_content(
model="gemini-2.0-flash",
contents="Output a json document with keys z, y, and x that are integers. Pick any 3 integers at random.",
config={
"response_mime_type": "application/json",
"response_schema": OutputModel,
},
)
if response.text.index('"z"') < response.text.index('"y"') < response.text.index('"x"'):
print("Property ordering is correct in Google GenAI response.")
else:
print("Property ordering is incorrect in Google GenAI response: " + repr(response.text))
for _ in range(N_TRIALS):
response = oai_client.beta.chat.completions.parse(
model="gemini-2.0-flash",
messages=[{"role": "user", "content": "Output a json document with keys z, y, and x that are integers. Pick any 3 integers at random."}],
response_format=OutputModel,
)
if (
response.choices[0].message.content.index('"z"')
< response.choices[0].message.content.index('"y"')
< response.choices[0].message.content.index('"x"')
):
print("Property ordering is correct in OpenAI Compatible response.")
else:
print(
"Property ordering is incorrect in OpenAI Compatible response: "
+ repr(response.choices[0].message.content)
)
Observed Output
Property ordering is correct in Google GenAI response.
Property ordering is correct in Google GenAI response.
Property ordering is correct in Google GenAI response.
Property ordering is correct in Google GenAI response.
Property ordering is correct in Google GenAI response.
Property ordering is incorrect in OpenAI Compatible response: '{\n "x": 5,\n "y": 10,\n "z": 15\n}'
Property ordering is incorrect in OpenAI Compatible response: '{\n "y": 5,\n "z": 10,\n "x": 15\n}'
Property ordering is incorrect in OpenAI Compatible response: '{\n "y": 5,\n "x": 10,\n "z": 15\n}'
Property ordering is correct in OpenAI Compatible response.
Property ordering is correct in OpenAI Compatible response.
I intercepted the request body to confirm that the OpenAI client was not removing the propertyOrdering
field on the JSON schema. The JSON schema appears to be consistent with the format in the Gemini API documentation linked above.
Raw Request Body
Endpoint: https://generativelanguage.googleapis.com/v1beta/openai/chat/completions
{
"messages": [
{
"role": "user",
"content": "Output a json document with keys z, y, and x that are integers. Pick any 3 integers at random."
}
],
"model": "gemini-2.0-flash",
"response_format": {
"type": "json_schema",
"json_schema": {
"schema": {
"properties": {
"z": {
"description": "The value of z",
"title": "Z",
"type": "integer"
},
"y": {
"description": "The value of y",
"title": "Y",
"type": "integer"
},
"x": {
"description": "The value of x",
"title": "X",
"type": "integer"
}
},
"propertyOrdering": [
"z",
"y",
"x"
],
"required": [
"z",
"y",
"x"
],
"title": "OutputModel",
"type": "object",
"additionalProperties": false
},
"name": "OutputModel",
"strict": true
}
},
"stream": false
}