SuperAPI AI Directory

azure-openai-to-responses

Agents & models

View repository

Updated 10-16 00:31

About this skill

Migrate Python Apps from Azure OpenAI Chat Completions to Responses API

AUTHORITATIVE GUIDANCE — FOLLOW EXACTLY

This skill migrates Python codebases using Azure OpenAI Chat Completions to the unified Responses API. Follow these instructions precisely. Do not improvise parameter mappings or invent API shapes.

Installed from Azure-Samples/azure-openai-to-responses (MIT).

Triggers

Activate this skill when the user wants to:

  • Migrate a Python app from Azure OpenAI Chat Completions to Responses API
  • Upgrade Python OpenAI SDK usage to the latest API shape against Azure OpenAI
  • Prepare Python code for GPT-5 or newer models that require Responses on Azure
  • Switch from AzureOpenAI/AsyncAzureOpenAI to standard OpenAI/AsyncOpenAI client with the v1 endpoint
  • Fix deprecation warnings related to AzureOpenAI constructors or api_version

Why migrate

GPT-5 and newer models require the Responses API. The new /openai/v1/ endpoint uses the standard OpenAI() client instead of AzureOpenAI(), requires no api_version parameter, and works identically across OpenAI and Azure OpenAI.

What changes

Chat Completions (before) Responses API (after)
AzureOpenAI() / AsyncAzureOpenAI() OpenAI(base_url=...) / AsyncOpenAI(base_url=...)
azure_endpoint=... base_url=f"{endpoint.rstrip('/')}/openai/v1/"
api_version="2024-..." Remove entirely — /openai/v1/ is stable
azure_ad_token_provider=... api_key=token_provider
client.chat.completions.create(messages=...) client.responses.create(input=...)
resp.choices[0].message.content resp.output_text
max_tokens max_output_tokens (min 16 on Azure)
response_format text={"format": {...}}
seed Remove (not supported)
tools nested {"type":"function","function":{...}} flat {"type":"function","name":...}
tool result {"role":"tool","tool_call_id":...} {"type":"function_call_output","call_id":...,"output":...}
content[].type: "text" content[].type: "input_text"
content[].type: "image_url" + {"url": "..."} content[].type: "input_image" + flat "image_url": "..."
streaming chunk.choices[0].delta.content event.type == "response.output_text.delta" → event.delta

Model compatibility — CHECK FIRST

Verify the deployed model supports the Responses API before migrating. GPT-4o and GPT-4 support Responses for basic text/chat/streaming/tools but not all features. Newer models (gpt-4.1+, gpt-5.x) have full support. GitHub Models (models.github.ai, models.inference.ai.azure.com) do NOT support the Responses API — remove those code paths and switch to Azure OpenAI, OpenAI, or a compatible local endpoint.

Smoke test:

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["AZURE_OPENAI_API_KEY"],
    base_url=f"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/",
)
resp = client.responses.create(
    model=os.environ["AZURE_OPENAI_DEPLOYMENT"],
    input="ping",
    max_output_tokens=50,
    store=False,
)
print(resp.output_text)

Step 0: Client migration (prerequisite)

AzureOpenAI/AsyncAzureOpenAI constructors are deprecated in openai>=1.108.1.

Before:

from openai import AzureOpenAI
client = AzureOpenAI(
    api_version=os.environ["AZURE_OPENAI_API_VERSION"],
    azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
    api_key=os.environ["AZURE_OPENAI_API_KEY"],
)

After:

from openai import OpenAI
client = OpenAI(
    api_key=os.environ["AZURE_OPENAI_API_KEY"],
    base_url=f"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/",
)

Cleanup: remove api_version args, remove AZURE_OPENAI_API_VERSION / AZURE_OPENAI_VERSION from .env/infra, rename AZURE_OPENAI_CLIENT_ID → AZURE_CLIENT_ID, ensure openai>=1.108.1.

Step 1: Detect legacy call sites

rg "chat\.completions\.create"        # legacy API calls
rg "ChatCompletion\.create|Completion\.create"
rg "AzureOpenAI\(|AsyncAzureOpenAI\("  # deprecated constructors
rg "choices\[0\]\.message\.content"    # response access
rg "choices\[0\]\.delta\.content"      # streaming access
rg "max_tokens\b"                      # rename to max_output_tokens
rg "['\"]seed['\"]"                    # remove entirely
rg "response_format"                   # → text.format
rg "AZURE_OPENAI_API_VERSION|AZURE_OPENAI_VERSION"
rg "models\.github\.ai|models\.inference\.ai\.azure"  # GitHub Models: remove

Step 2: Apply migration

  • client.chat.completions.create(messages=...) → client.responses.create(input=...)
  • resp.choices[0].message.content → resp.output_text
  • max_tokens → max_output_tokens (min 16); remove seed
  • response_format → text={"format": {"type": "json_schema", "name": "Output", "strict": True, "schema": {...}}}
  • Set store=False on every request (client-managed state)
  • Streaming: iterate events, handle event.type == "response.output_text.delta" (use event.delta) and response.completed
  • Tools: flat format, tool_choice, return results as function_call_output items; append response.output items for round-trips
  • Multi-turn: maintain conversation in an input array, or use previous_response_id (requires store=True)
  • Reasoning models (o-series, GPT-5): max_completion_tokens → max_output_tokens (4096+), reasoning_effort → reasoning={"effort": ...}, omit temperature/top_p (GPT-5 rejects temperature outright; to vary output use a non-reasoning model like Llama-3.3-70B-Instruct via Foundry Models)

Acceptance criteria (all must pass)

  • Zero matches for chat.completions.create|ChatCompletion.create|Completion.create
  • Zero matches for AzureOpenAI(|AsyncAzureOpenAI( — all use OpenAI/AsyncOpenAI + v1 endpoint
  • Zero matches for models.github.ai|models.inference.ai.azure
  • Zero matches for choices[0] — all access uses resp.output_text / Responses schema
  • No top-level response_format; structured output uses text={"format": {...}}
  • openai>=1.108.1 in requirements; store=False on every call; no api_version in client construction
  • Tests updated (mocks use kwargs.get("input"), snapshots use Responses shape); pytest passes

See references/cheat-sheet.md for complete before/after code examples.

References