weiqingy commented on code in PR #930:
URL: https://github.com/apache/flink-agents/pull/930#discussion_r3708238262
##########
python/flink_agents/integrations/chat_models/azure/azure_openai_chat_model.py:
##########
@@ -40,6 +47,70 @@
{"model", "model_of_azure_deployment", "temperature", "max_tokens",
"logprobs"}
)
+# Models with documented json_schema strict Structured Outputs support. Source
of truth:
+#
https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/structured-outputs
+#
+# Matching is exact, never by prefix: Azure exposes a deployment's model name
and model
+# version as separate properties, so a name carries no version to discriminate
on. The
+# documented list includes gpt-4o only at versions 2024-08-06 and 2024-11-20
while
+# version 2024-05-13 is unsupported, so a bare "gpt-4o" is ambiguous and is
deliberately
+# absent from the set below. An unrecognized name reports not-capable and
degrades to
+# the prompt fallback rather than failing at the provider.
+#
+# The source list prints "gpt-5.1-codex mini" with a space; it is transcribed
hyphenated
+# here because Azure model identifiers do not contain spaces.
+_NATIVE_STRUCTURED_OUTPUT_MODELS = frozenset(
+ {
+ "gpt-5.1-codex",
Review Comment:
Good catch, and it was broader than the three you named.
Fixed in 62c6a1d5. The set is now the intersection of the structured-outputs
list with the models Azure serves on Chat Completions. The "Chat Completions
API" row on the reasoning page also marks `gpt-5-pro`, `codex-mini` and
`o3-pro` unsupported, so six come out and thirteen remain.
Both rejection tests now pin all six by name, so re-adding one gets caught.
##########
python/flink_agents/integrations/chat_models/azure/azure_openai_chat_model.py:
##########
@@ -114,6 +185,41 @@ def client(self) -> AzureOpenAI:
)
return self._client
+ @override
+ def supports_native_structured_output(self, effective_model: str | None)
-> bool:
+ """Whether Azure documents json_schema strict support for
``effective_model``.
+
+ ``effective_model`` is the model backing an Azure deployment, not the
deployment
+ name. See the module-level allowlist for the source of truth and for
why the
+ match is exact. An unrecognized model reports ``False`` so it degrades
to the
+ prompt-engineering fallback rather than failing at the provider.
+
+ Reads no instance state, so it stays answerable on an instance that
was never
+ initialized, where any field access would raise.
+ """
+ if not effective_model:
+ return False
+ return effective_model in _NATIVE_STRUCTURED_OUTPUT_MODELS
+
+ def _api_version_supports_structured_output(self) -> bool:
+ """Whether the configured api-version reaches the structured-output
floor.
+
+ Azure documents ``2024-08-01-preview`` as the first api-version
supporting
+ structured outputs, and whether an older version rejects
``response_format`` or
+ silently ignores it is not documented. The request therefore never
carries
+ ``response_format`` below the floor, which is safe under either
behavior.
+
+ The comparison assumes the documented api-version form, a zero-padded
+ ``YYYY-MM-DD`` date optionally suffixed ``-preview``; over that form
comparing
+ the leading date lexicographically is exact. The GA ``v1`` literal
sorts above
+ the floor, which matches Azure documenting ``v1`` as supporting
structured
+ outputs. This is not a validator: a value of any other shape is not
classified
+ reliably, and the service rejects an api-version it does not recognize.
+ """
+ if not self.api_version:
+ return False
+ return self.api_version[:10] >= _MIN_STRUCTURED_OUTPUT_API_VERSION
Review Comment:
Agreed, `v1` was passing on string ordering alone.
Fixed in 62c6a1d5. The gate now classifies only the dated form Azure
documents, so `v1` and any other non-dated value report not-capable and keep
the prompt fallback. I changed the gate rather than just the test, since
otherwise the code would still admit `v1`. Both suites assert that now, with
`latest` as a second case. The documented examples use `2024-10-21`, so nothing
regresses.
One asymmetry worth flagging: in openai-java, `azure_url_path_mode=UNIFIED`
or an endpoint ending in `/openai/v1` does reach the unified endpoint, so `v1`
is reachable there in a way it is not from Python's `AzureOpenAI`. Not-capable
is still the right answer, it just costs a prompt fallback rather than being
impossible. The Java javadoc says so; the Python docstring does not, since
there is no equivalent option.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]