feat: Support structured output parsed from OpenAI

Added support for structured output (JSON mode) from the OpenAI API in `openai.py` and `azure_openai.py`.

When `response_format` is used to request structured data, the new logic checks for the `message.parsed` attribute. If it exists, it's serialized into a JSON string as the final content. If not, the code falls back to the existing `message.content` handling, ensuring backward compatibility.
This commit is contained in:
yangdx 2025-11-21 12:46:31 +08:00
parent c9e1c86e81
commit 9f69c5bf85
2 changed files with 57 additions and 37 deletions

View file

@ -113,9 +113,20 @@ async def azure_openai_complete_if_cache(
return inner() return inner()
else: else:
content = response.choices[0].message.content message = response.choices[0].message
if r"\u" in content:
# Handle parsed responses (structured output via response_format)
# When using beta.chat.completions.parse(), the response is in message.parsed
if hasattr(message, "parsed") and message.parsed is not None:
# Serialize the parsed structured response to JSON
content = message.parsed.model_dump_json()
logger.debug("Using parsed structured response from API")
else:
# Handle regular content responses
content = message.content
if content and r"\u" in content:
content = safe_unicode_decode(content.encode("utf-8")) content = safe_unicode_decode(content.encode("utf-8"))
return content return content

View file

@ -453,6 +453,15 @@ async def openai_complete_if_cache(
raise InvalidResponseError("Invalid response from OpenAI API") raise InvalidResponseError("Invalid response from OpenAI API")
message = response.choices[0].message message = response.choices[0].message
# Handle parsed responses (structured output via response_format)
# When using beta.chat.completions.parse(), the response is in message.parsed
if hasattr(message, "parsed") and message.parsed is not None:
# Serialize the parsed structured response to JSON
final_content = message.parsed.model_dump_json()
logger.debug("Using parsed structured response from API")
else:
# Handle regular content responses
content = getattr(message, "content", None) content = getattr(message, "content", None)
reasoning_content = getattr(message, "reasoning_content", "") reasoning_content = getattr(message, "reasoning_content", "")