[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M69A15PVQWW1FCA4X33TSP7Y":3,"skill-same:01M69A15PVQWW1FCA4X33TSP7Y":62},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":24,"commitSha":25,"skillDirectory":26,"forksCount":27,"repositoryHtmlUrl":28,"repositoryHomepageUrl":29,"ownerHtmlUrl":30,"ownerBlogUrl":31,"ownerDescription":32,"updatedAt":33,"install":34,"resources":47},"01M69A15PVQWW1FCA4X33TSP7Y","azure-openai-to-responses",null,"microsoft\u002Fai-agents-for-beginners","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M6998ZK2275KMJE6Y5SEA2X2",79423,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-MO\u002F.agents\u002Fskills\u002Fazure-openai-to-responses\u002FSKILL.md",[],[18],"azure openai to responses","2026-11-10 10:12:30",false,"---\nname: azure-openai-to-responses\nlicense: MIT\n---\n# 將 Python 應用程式從 Azure OpenAI Chat Completions 遷移到 Responses API\n\n> **權威指南 — 請嚴格遵循**\n>\n> 本技能協助遷移使用 Azure OpenAI Chat Completions 的 Python 程式碼庫\n> 至統一的 Responses API。請嚴格按照這些指示執行。\n> 請勿即興映射參數或自行創建 API 結構。\n\n---\n\n## 啟動條件\n\n當用戶希望執行下列操作時啟用此技能：\n- 將 Python 應用程式從 Azure OpenAI Chat Completions 遷移至 Responses API\n- 將 Python OpenAI SDK 用法升級至針對 Azure OpenAI 的最新 API 結構\n- 為 GPT-5 或更新版本需要在 Azure 上使用 Responses 的模型準備 Python 程式碼\n- 從 `AzureOpenAI`\u002F`AsyncAzureOpenAI` 切換至使用標準的 `OpenAI`\u002F`AsyncOpenAI` 客戶端及 v1 端點\n- 修正與 `AzureOpenAI` 建構函式或 `api_version` 相關的棄用警告\n\n---\n\n## ⚠️ 模型相容性 — 請先確認\n\n> **遷移前，請確認您的 Azure OpenAI 部署支援 Responses API。**\n\n### 1. 簡易測試您的部署（最快速）\n\n```python\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('\u002F')}\u002Fopenai\u002Fv1\u002F\",\n)\n\ntry:\n    resp = client.responses.create(\n        model=os.environ[\"AZURE_OPENAI_DEPLOYMENT\"],\n        input=\"ping\",\n        max_output_tokens=50,\n        store=False,\n    )\n    print(f\"✅ Deployment supports Responses API: {resp.output_text}\")\nexcept Exception as e:\n    print(f\"❌ Deployment does NOT support Responses API: {e}\")\n```\n\n> \u003Cstrong>注意\u003C\u002Fstrong>：Azure OpenAI 上的 `max_output_tokens` 最小值為 **16**。小於 16 將返回 400 錯誤。簡易測試請使用 50 以上。\n\n若此請求返回 404，表示該部署使用的模型尚未支援 Responses，請參考下面的參考資料或重新部署支援的模型。\n\n### 2. 檢查您區域可用模型（推薦）\n\n運行內建的模型相容性工具來查看您區域有哪些模型支援 Responses API：\n\n```bash\npython migrate.py models --subscription YOUR_SUB_ID --location YOUR_REGION\n```\n\n此命令會查詢 Azure ARM 實時狀態並展示相容性矩陣 — 哪些模型支援 Responses、結構化輸出、工具等。可用 `--filter gpt-5.1,gpt-5.2` 篩選結果，或用 `--json` 做腳本處理。\n\n### 3. 完整模型相容參考\n\n- \u003Cstrong>即時查詢\u003C\u002Fstrong>：`python migrate.py models`（如上述所示 — 依區域不同，資料永遠最新）\n- \u003Cstrong>瀏覽可用性\u003C\u002Fstrong>：[模型摘要表及區域可用性](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Ffoundry\u002Ffoundry-models\u002Fconcepts\u002Fmodels-sold-directly-by-azure?tabs=global-standard-aoai%2Cglobal-standard&pivots=azure-openai#model-summary-table-and-region-availability)\n- \u003Cstrong>快速入門與指南\u003C\u002Fstrong>：**https:\u002F\u002Faka.ms\u002Fopenai\u002Fstart**\n\n### ⚠️ 舊版模型限制\n\n> \u003Cstrong>警告\u003C\u002Fstrong>：舊版模型（`gpt-4.1` 之前的）可能無法完全支援所有 Responses API 功能。\n>\n> 舊版模型已知限制：\n> - **`reasoning` 參數**：許多非推理模型不支援。只有原本代碼使用過才遷移此參數。\n> - **`seed` 參數**：Responses API 完全不支援，務必移除。\n> - **透過 `text.format` 的結構化輸出**：舊版模型可能無法穩定強制 `strict: true` 的 JSON 架構。\n> - \u003Cstrong>工具編排\u003C\u002Fstrong>：GPT-5+ 在推理中整合工具呼叫。舊版模型仍運作，但缺乏此深入整合。\n> - \u003Cstrong>溫度限制\u003C\u002Fstrong>：遷移至 `gpt-5` 時，溫度需省略或設定為 `1`。舊版模型無此限制。\n\n### O 系列推理模型 (o1, o3-mini, o3, o4-mini)\n\nO 系列模型有特別的參數限制。遷移針對 O 系列模型的應用程式時：\n\n- **`temperature`**：必須是 `1`（或省略）。O 系列不接受其他值。\n- **`max_completion_tokens` → `max_output_tokens`**：使用 Azure 專屬的 `max_completion_tokens` 的應用需切換至 `max_output_tokens`。由於推理會消耗 Token，設定較高值（4096 以上）。\n- **`reasoning_effort`**：若使用 `reasoning_effort`（low\u002Fmedium\u002Fhigh），保留即可 — Responses API 支援 O 系列模型這參數。\n- \u003Cstrong>串流行為\u003C\u002Fstrong>：O 系列模型可能會緩衝輸出直到推理完成才發出文字差異事件。串流仍可用，但第一個 `response.output_text.delta` 可能較 GPT 模型延遲較久才送達。\n- **`top_p`**：O 系列不支援此參數 — 若存在請移除。\n- \u003Cstrong>工具使用\u003C\u002Fstrong>：O 系列模型透過 Responses API 支援工具，與 GPT 模型相同，但工具呼叫編排品質因模型不同而異。\n\n**措施 — 主動模型諮詢**：掃描階段檢查應用程式目標模型（部署名稱、環境變數、設定）。若模型為 `gpt-4.1` 之前版本，主動告知用戶：\n- 對其目前模型，遷移可支援基本文字、聊天、串流及工具功能。\n- 較新模型（`gpt-5.1`、`gpt-5.2`）提供更好的工具編排、結構化輸出強制、推理和跨區域可用性。\n- 建議用戶在準備好時考慮升級部署 — 並非遷移阻礙。\n\n不要以模型版本為由阻止或拒絕遷移。此諮詢為資訊性提示。\n\n### GitHub Models 不支援 Responses API\n\n> **GitHub Models (`models.github.ai`, `models.inference.ai.azure.com`) 不支援 Responses API。**\n\n若程式碼中有 GitHub Models 路徑（例如 `base_url` 指向 `models.github.ai` 或 `models.inference.ai.azure.com`），\u003Cstrong>請在遷移時完全移除\u003C\u002Fstrong>。Responses API 需使用 Azure OpenAI、OpenAI 或相容的本地端點（例如支援 Responses 的 Ollama）。\n\n掃描時應採取的措施：\n- 標示任何 GitHub Models 路徑以便移除。\n\n---\n\n## 框架遷移\n\n許多應用程式使用封裝 OpenAI 的高階框架。遷移這些框架時，不僅底層 OpenAI 呼叫改變，框架自身的 API 也會變更。\n\n### Microsoft Agent Framework (MAF)\n\n**首先檢查您的 MAF 版本** — 遷移將依您使用的是 MAF 1.0.0+ 還是 1.0.0 之前的 beta\u002Frc 版本而異。\n\n#### MAF 1.0.0+ (agent-framework-openai >= 1.0.0)\n\n`OpenAIChatClient` **已經使用 Responses API** — 無需遷移。若程式碼使用舊版 `OpenAIChatCompletionClient`（基於 `chat.completions.create`），請改用 `OpenAIChatClient`。\n\n| 之前 | 之後 |\n|--------|-------|\n| `from agent_framework.openai import OpenAIChatCompletionClient` | `from agent_framework.openai import OpenAIChatClient` |\n| `OpenAIChatCompletionClient(...)` | `OpenAIChatClient(...)` |\n\n查看版本：`python -c \"import agent_framework_openai; print(agent_framework_openai.__version__)\"` \n\n#### MAF 1.0.0 之前版本（beta\u002Frc）\n\n在 MAF 1.0.0 之前版本中，`OpenAIChatClient` 使用 Chat Completions。請升級到 `agent-framework-openai>=1.0.0`，它會預設使用 Responses API 的 `OpenAIChatClient`。\n\n其他 API（如 `Agent` 和工具）不變。\n\n### LangChain (`langchain-openai`)\n\n在 `ChatOpenAI()` 中新增 `use_responses_api=True`。並更新響應訪問方式，從 `.content` 改為 `.text`。\n\n| 之前 | 之後 |\n|--------|-------|\n| `ChatOpenAI(model=..., base_url=..., api_key=...)` | `ChatOpenAI(model=..., base_url=..., api_key=..., use_responses_api=True)` |\n| `result['messages'][-1].content` | `result['messages'][-1].text` |\n\n完整前後代碼範例，請參考 [cheat-sheet.md](.\u002Freferences\u002Fcheat-sheet.md)。\n\n---\n\n## 前端遷移指導\n\n> **Responses API 是後端處理。** 請遷移您的 Python 後端；前端的 HTTP 合約應保持不變，除非您的後端只是個簡單轉送層 — 在那種情況下，考慮採用 Responses 請求結構以消除翻譯層。若前端使用客戶端密鑰直接呼叫 OpenAI，請先將這些呼叫移至後端。\n\n### `@microsoft\u002Fai-chat-protocol` 棄用\n\n`@microsoft\u002Fai-chat-protocol` npm 包已棄用，應改用 [`ndjson-readablestream`](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fndjson-readablestream)。若前端遇到此包：\n\n1. 替換 CDN 腳本標籤：\n   ```html\n   \u003C!-- Before -->\n   \u003Cscript src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002F@microsoft\u002Fai-chat-protocol@...\u002Fdist\u002Fiife\u002Findex.js\">\u003C\u002Fscript>\n   \u003C!-- After -->\n   \u003Cscript src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fndjson-readablestream@1.0.7\u002Fdist\u002Fndjson-readablestream.umd.js\">\u003C\u002Fscript>\n   ```\n2. 移除 `AIChatProtocolClient` 實例化（`new ChatProtocol.AIChatProtocolClient(\"\u002Fchat\")`）。\n3. 將 `client.getStreamedCompletion(messages)` 改成直接 `fetch()` 後端串流端點。\n4. 將 `for await (const response of result)` 改為 `for await (const chunk of readNDJSONStream(response.body))`。\n5. 更新屬性訪問方式，從 `response.delta.content` \u002F `response.error` 改為 `chunk.delta.content` \u002F `chunk.error`。\n\n---\n\n## 目標\n\n- 枚舉所有使用 Chat Completions 或舊版 Completions 呼叫 Azure OpenAI 的 Python 呼叫點。\n- 擬定 Python 程式碼庫的遷移計畫與順序。\n- 採用安全且最小修改方式切換至 Responses API。\n- 更新呼叫端以消費 Responses 輸出結構；不使用任何向後相容包裝。\n- 執行測試與靜態檢查；修正遷移導致的小錯誤。\n- 準備小且可審核的變更集，並提供最終摘要及差異 (不執行 commit)。\n\n---\n\n## 防護措施\n\n- 僅修改 Git 工作區內的檔案，禁止對工作區外寫入。\n- 不保留向後相容性 shim；直接遷移至新 API 結構。\n- 不留存銘碑註解或備份檔案。\n- 若先前使用串流，務必保留串流語意；否則可改為非串流。\n- 若為審批模式，操作命令或網絡呼叫前請先取得批准。\n- 不執行 `git add`\u002F`git commit`\u002F`git push`；僅產生工作樹修改。\n\n---\n\n## 第 0 步：Azure OpenAI 客戶端遷移（先決條件）\n\n若程式碼庫使用 `AzureOpenAI` 或 `AsyncAzureOpenAI` 建構子，請先遷移到標準的 `OpenAI` \u002F `AsyncOpenAI` 建構子。Azure 專屬建構子在 `openai>=1.108.1` 中已棄用。\n\n### 為何使用 v1 API 路徑？\n\n新的 `\u002Fopenai\u002Fv1` 端點使用標準的 `OpenAI()` 客戶端替代 `AzureOpenAI()`，無需 `api_version` 參數，在 OpenAI 和 Azure OpenAI 間行為一致。相同的客戶端代碼具有未來相容性 — 無需版本管理。\n\n### 關鍵改變\n\n| 之前 | 之後 |\n|--------|-------|\n| `AzureOpenAI` | `OpenAI` |\n| `AsyncAzureOpenAI` | `AsyncOpenAI` |\n| `azure_endpoint` | `base_url` |\n| `azure_ad_token_provider` | `api_key` |\n| `api_version=...` | 完全移除 |\n\n### 清理清單\n\n- 移除建構客戶端時的 `api_version` 參數。\n- 從 `.env`、應用設置及 Bicep\u002F基礎架構檔移除 `AZURE_OPENAI_VERSION` \u002F `AZURE_OPENAI_API_VERSION` 環境變數。\n- 將 `.env`、應用設置、Bicep\u002F基礎架構及測試 fixture 中的 `AZURE_OPENAI_CLIENT_ID` 改名為 `AZURE_CLIENT_ID`（符合 Azure 身分識別 SDK 標準慣例）。\n- 確保在 `requirements.txt` 或 `pyproject.toml` 中使用 `openai>=1.108.1`。\n\n### 環境變數遷移\n\n| 舊環境變數 | 措施 | 備註 |\n|-------------|--------|-------|\n| `AZURE_OPENAI_VERSION` | \u003Cstrong>移除\u003C\u002Fstrong> | v1 端點不需 `api_version` |\n| `AZURE_OPENAI_API_VERSION` | \u003Cstrong>移除\u003C\u002Fstrong> | 同上 |\n| `AZURE_OPENAI_CLIENT_ID` | \u003Cstrong>改名\u003C\u002Fstrong> → `AZURE_CLIENT_ID` | Azure 身分識別 SDK 的標準 `ManagedIdentityCredential(client_id=...)` 慣例 |\n| `AZURE_OPENAI_ENDPOINT` | \u003Cstrong>保留\u003C\u002Fstrong> | 仍用於 `base_url` 建構 |\n| `AZURE_OPENAI_CHAT_DEPLOYMENT` | \u003Cstrong>保留\u003C\u002Fstrong> | 用作 `responses.create` 的 `model` 參數 |\n| `AZURE_OPENAI_API_KEY` | \u003Cstrong>保留\u003C\u002Fstrong> | 用於基於金鑰的認證 `api_key` |\n\n有關客戶端設置代碼範例（同步、非同步、EntraID、API 金鑰、多租戶）請參考 [cheat-sheet.md](.\u002Freferences\u002Fcheat-sheet.md)。\n\n---\n\n## 第 1 步：偵測舊版呼叫點\n\n執行 [detect_legacy.py](..\u002F..\u002F..\u002F..\u002F..\u002F.agents\u002Fskills\u002Fazure-openai-to-responses\u002Fscripts\u002Fdetect_legacy.py) 腳本以找到所有需要遷移的呼叫點：\n\n```bash\npython skills\u002Fazure-openai-to-responses\u002Fscripts\u002Fdetect_legacy.py .\n```\n\n或手動執行此類搜尋 — 每個匹配即為遷移目標：\n\n```bash\n# 傳統 API 調用（必須重寫）\nrg \"chat\\.completions\\.create\"\nrg \"ChatCompletion\\.create\"\nrg \"Completion\\.create\"\n\n# 已棄用的 Azure 客戶端建構子（必須替換）\nrg \"AzureOpenAI\\(\"\nrg \"AsyncAzureOpenAI\\(\"\n\n# 回應結構存取模式（必須更新）\nrg \"choices\\[0\\]\\.message\\.content\"\nrg \"choices\\[0\\]\\.delta\\.content\"\nrg \"choices\\[0\\]\\.message\\.function_call\"\nrg \"choices\\[0\\]\\.message\\.tool_calls\"\n\n# 舊巢狀格式的工具定義（必須扁平化）\nrg '\"function\":\\s*{\\s*\"name\"'\nrg \"pydantic_function_tool\"\n\n# 舊格式的工具結果（必須轉換為 function_call_output）\nrg '\"role\":\\s*\"tool\"'\nrg '\"tool_call_id\"'\n\n# 已棄用的參數（必須刪除或重新命名）\nrg \"response_format\"\nrg \"max_tokens\\b\"        # 重新命名為 max_output_tokens\nrg \"['\\\"]seed['\\\"]\"      # remove entirely\n\n# 已棄用的環境變量（清理）\nrg \"AZURE_OPENAI_API_VERSION|AZURE_OPENAI_VERSION\"\nrg \"AZURE_OPENAI_CLIENT_ID\"  # 應該是 AZURE_CLIENT_ID\n\n# GitHub 模型端點（必須移除 — 不支援 Responses API）\nrg \"models\\.github\\.ai|models\\.inference\\.ai\\.azure\"\n\n# 框架層級的傳統模式（必須更新）\nrg \"OpenAIChatCompletionClient\"  # MAF 1.0.0+：替換成 OpenAIChatClient\nrg \"ChatOpenAI\\(\" | grep -v \"use_responses_api\"  # LangChain：需要 use_responses_api=True\n\n# 測試基礎設施（必須更新）\nrg \"ChatCompletionChunk|AsyncCompletions\\.create\" tests\u002F\nrg \"_azure_ad_token_provider\" tests\u002F\nrg \"prompt_filter_results|content_filter_results\" tests\u002F\nrg \"choices\\[0\\]\" tests\u002F\n\n# 內容過濾錯誤主體存取（必須更新 — 結構已更改）\nrg 'innererror.*content_filter_result|error\\.body\\[\"innererror\"\\]'\nrg \"content_filter_result\\[\" # 舊單數形式 — 現在是 content_filters 陣列內的 content_filter_results（複數）\n\n# 對 Chat Completions 端點的原始 HTTP 調用（必須更新 URL）\nrg \"\u002Fopenai\u002Fdeployments\u002F.*\u002Fchat\u002Fcompletions\"\nrg \"api-version=\"\n```\n\n### 偵測與重寫的啟發式\n\n- **Chat Completions 客戶端**：從 `client.chat.completions.create` → `client.responses.create(...)`。\n\n- **Azure 用戶端建構子**：`AzureOpenAI(...)` → `OpenAI(base_url=..., api_key=...)`。\n- \u003Cstrong>工具\u003C\u002Fstrong>：將函式呼叫工具定義從巢狀格式 (`{\"type\": \"function\", \"function\": {\"name\": ...}}`) 轉換成平坦的 Responses 格式 (`{\"type\": \"function\", \"name\": ...}`)；使用 `tool_choice`；返回工具結果為 `{\"type\": \"function_call_output\", \"call_id\": ..., \"output\": ...}` 項目（而非 `{\"role\": \"tool\", ...}`）。\n- \u003Cstrong>工具迴圈往返\u003C\u002Fstrong>：當模型返回函式呼叫時，將 `response.output` 項目追加到對話中（非手動的 `{\"role\": \"assistant\", \"tool_calls\": [...]}` 字典），然後為每個結果追加 `function_call_output` 項目。\n- \u003Cstrong>少量範例工具呼叫\u003C\u002Fstrong>：若對話包括硬編碼的工具呼叫範例，將它們轉換成 `{\"type\": \"function_call\", \"id\": \"fc_...\", \"call_id\": \"fc_...\", ...}` + `{\"type\": \"function_call_output\", ...}` 項目。ID 必須以 `fc_` 開頭。\n- **`pydantic_function_tool()`\u003Cstrong>：此輔助函式仍會產生舊有的巢狀格式，\u003C\u002Fstrong>不相容**於 `responses.create()`。請改用手動工具定義或扁平化包裝器。\n- \u003Cstrong>多輪互動\u003C\u002Fstrong>：在應用中維護對話歷史；傳遞先前回合透過 `input` 項目。\n- \u003Cstrong>格式\u003C\u002Fstrong>：以 Responses 取代 Chat 的頂層 `response_format`，改為使用 `text.format`。規範格式：`text={\"format\": {\"type\": \"json_schema\", \"name\": \"Output\", \"strict\": True, \"schema\": {...}}}`。\n- \u003Cstrong>內容項目\u003C\u002Fstrong>：將 Chat 的 `content[].type: \"text\"` 替換為 Responses 的 `content[].type: \"input_text\"`（用戶／系統回合）。\n- \u003Cstrong>圖像內容項目\u003C\u002Fstrong>：將 Chat 的 `content[].type: \"image_url\"` 替換為 Responses 的 `content[].type: \"input_image\"`。`image_url` 欄位從巢狀物件 `{\"url\": \"...\"}` 變成扁平字串。詳見速查表前後範例。\n- \u003Cstrong>推理努力\u003C\u002Fstrong>：**僅在原始程式已有 `reasoning` 字段時遷移**。\n- \u003Cstrong>內容過濾錯誤處理\u003C\u002Fstrong>：錯誤主體結構變更。Chat Completions 使用 `error.body[\"innererror\"][\"content_filter_result\"]`（單數）；Responses API 使用 `error.body[\"content_filters\"][0][\"content_filter_results\"]`（複數，陣列中）。存取 `innererror` 的程式將引發 `KeyError`。請改用新路徑。\n- **原始 HTTP 呼叫**：若應用直接呼叫 Azure OpenAI REST API（透過 `requests`、`httpx` 等）使用 `\u002Fopenai\u002Fdeployments\u002F{name}\u002Fchat\u002Fcompletions?api-version=...`，請改寫為 `\u002Fopenai\u002Fv1\u002Fresponses`。請求主體變更：`messages` → `input`、新增 `max_output_tokens` 和 `store: false`、移除 `api-version` 查詢參數。回應主體變更：`choices[0].message.content` → `output[0].content[0].text`（註：`output_text` 為 SDK 方便屬性，原生 REST JSON 中無）。\n\n---\n\n## 步驟 2：應用遷移\n\n### 遷移注意事項 (Chat Completions → Responses)\n\n- \u003Cstrong>為何要遷移\u003C\u002Fstrong>：Responses 是文字、工具及串流統一 API；Chat Completions 為舊版。搭配 GPT-5，必須使用 Responses 以達最佳效能。\n- **HTTP**：Azure 端點從 `\u002Fopenai\u002Fdeployments\u002F{name}\u002Fchat\u002Fcompletions` 轉至 `\u002Fopenai\u002Fv1\u002Fresponses`。\n- \u003Cstrong>欄位\u003C\u002Fstrong>：`messages` → `input`，`max_tokens` → `max_output_tokens`。`temperature` 不變。\n- \u003Cstrong>格式\u003C\u002Fstrong>：`response_format` → `text.format`（物件格式）。\n- \u003Cstrong>內容項目\u003C\u002Fstrong>：替換 Chat 的 `content[].type: \"text\"` 為 Responses 的 `content[].type: \"input_text\"`，適用於系統／使用者回合。\n- \u003Cstrong>圖像內容項目\u003C\u002Fstrong>：替換 Chat 的 `content[].type: \"image_url\"` 為 Responses 的 `content[].type: \"input_image\"`。將 `image_url` 欄位從 `{\"image_url\": {\"url\": \"...\"}}` 扁平化為 `{\"image_url\": \"...\"}`（純字串—HTTPS URL 或 `data:image\u002F...;base64,...` 資料 URI）。\n\n### 參數對照參考\n\n| Chat Completions | Responses API |\n|-----------------|---------------|\n| `prompt` | `input` |\n| `messages` | `input`（項目陣列） |\n| `max_tokens` | `max_output_tokens` |\n| `response_format` | `text.format`（物件） |\n| `temperature` | `temperature`（不變） |\n| `stop` | `stop`（不變） |\n| `frequency_penalty` | `frequency_penalty`（不變） |\n| `presence_penalty` | `presence_penalty`（不變） |\n| `tools` \u002F 函式呼叫 | `tools`（不變） |\n| `seed` | \u003Cstrong>移除\u003C\u002Fstrong>（不支援） |\n| `store` | `store`（設定為 `false`） |\n| `content[].type: \"text\"` | `content[].type: \"input_text\"` |\n| `content[].type: \"image_url\"` | `content[].type: \"input_image\"` |\n| `\"image_url\": {\"url\": \"...\"}` | `\"image_url\": \"...\"`（扁平字串） |\n\n完整前後範例程式碼請參見 [cheat-sheet.md](.\u002Freferences\u002Fcheat-sheet.md)。\n\n考量測試基礎設施遷移（mocks、快照、斷言），請見 [test-migration.md](.\u002Freferences\u002Ftest-migration.md)。\n\n如需錯誤診斷及注意事項，請見 [troubleshooting.md](.\u002Freferences\u002Ftroubleshooting.md)。\n\n---\n\n## 資料保留與狀態\n\n- 所有 Responses 請求設定 `store: false`。\n- 不依賴先前訊息 ID 或伺服器保存的上下文；狀態由用戶端管理並盡量減少元資料。\n\n---\n\n## 驗收標準\n\n### 程式碼層級門檻（全部通過）\n\n- [ ] 在遷移後檔案中，搜尋 `rg \"chat\\.completions\\.create|ChatCompletion\\.create|Completion\\.create\"`，應為零結果。\n- [ ] 搜尋 `rg \"AzureOpenAI\\(|AsyncAzureOpenAI\\(\"`，全部建構子改用帶 v1 端點的 `OpenAI`\u002F`AsyncOpenAI`。\n- [ ] 搜尋 `rg \"models\\.github\\.ai|models\\.inference\\.ai\\.azure\"`，GitHub Models 相關程式路徑已移除。\n- [ ] 搜尋 `rg \"OpenAIChatCompletionClient\"`，MAF 1.0.0+ 程式碼使用 `OpenAIChatClient`（搭配 Responses API）。1.0.0 以前請升級至 `agent-framework-openai>=1.0.0`。\n- [ ] 所有 `ChatOpenAI(...)` 呼叫含 `use_responses_api=True`。\n- [ ] 搜尋 `rg \"choices\\[0\\]\"`，所有存取回應皆使用 `resp.output_text` 或 Responses 輸出結構。\n- [ ] 頂層不出現 `response_format`；所有結構化輸出使用 `text={\"format\": {...}}`。\n- [ ] `requirements.txt` 或 `pyproject.toml` 中有 `openai>=1.108.1` 與 `azure-identity`；依賴重新安裝完畢。\n- [ ] 每個 `responses.create` 呼叫設定 `store=False`。\n- [ ] 用戶端建構時不包含 `api_version`；環境變數及基礎設施中移除 `AZURE_OPENAI_API_VERSION`。\n\n### 測試基礎設施門檻（全部通過）\n\n- [ ] 在 `tests\u002F` 中搜尋 `rg \"ChatCompletionChunk|AsyncCompletions\\.create|chat\\.completions\"`，應為零結果。\n- [ ] 在 `tests\u002F` 中搜尋 `rg \"_azure_ad_token_provider\"`，斷言更新為檢查 `isinstance(client, AsyncOpenAI)` 或 `base_url`。\n- [ ] 在 `tests\u002F` 中搜尋 `rg \"prompt_filter_results|content_filter_results\"`，移除 Azure 特有過濾器 mocks。\n- [ ] mock fixtures 使用 `kwargs.get(\"input\")`，而非 `kwargs.get(\"messages\")`。\n- [ ] 快照與 golden 檔案更新為 Responses 串流格式（無 `choices[0]`、`function_call`、`logprobs` 等）。\n- [ ] 所有測試更新後 `pytest` 通過且無失敗。\n\n### 行為門檻（手動或透過測試套件驗證）\n\n- [ ] \u003Cstrong>基本完成測試\u003C\u002Fstrong>：非串流 `responses.create` 返回非空字串 `output_text`。\n- [ ] \u003Cstrong>串流一致性\u003C\u002Fstrong>：原程式有使用串流，則遷移後程式也串流並產生包含非空增量的 `response.output_text.delta` 事件。\n- [ ] \u003Cstrong>結構化輸出\u003C\u002Fstrong>：使用 `text.format` 加上 `json_schema` 時，`json.loads(resp.output_text)` 可成功解析且符合架構。\n- [ ] \u003Cstrong>工具呼叫迴圈\u003C\u002Fstrong>：若有使用工具，模型發出工具呼叫、應用執行呼叫，後續請求回傳最終 `output_text`（無無限迴圈）。\n- [ ] \u003Cstrong>非同步一致性\u003C\u002Fstrong>：若使用 `AsyncAzureOpenAI`，其對應的 `AsyncOpenAI` 可配合 `await` 正常運作。\n- [ ] \u003Cstrong>錯誤率\u003C\u002Fstrong>：相較遷移前基線，無新增 400\u002F401\u002F404 錯誤。\n\n### 交付項目\n\n- 摘要包含已編輯檔案、舊版調用數前後對比、下一步。\n- 變更僅限工作樹編輯（無提交）。\n\n---\n\n## SDK 版本需求\n\n| 套件 | 最低版本 |\n|---------|----------------|\n| `openai` | `>=1.108.1` |\n| `azure-identity` | 最新版（用於 EntraID 認證） |\n\n---\n\n## 參考資源\n\n- [速查表 — 所有程式碼片段](.\u002Freferences\u002Fcheat-sheet.md)\n- [測試遷移 — mocks、快照、斷言](.\u002Freferences\u002Ftest-migration.md)\n- [故障排除 — 錯誤、風險表、注意事項](.\u002Freferences\u002Ftroubleshooting.md)\n- [detect_legacy.py — 自動掃描器](..\u002F..\u002F..\u002F..\u002F..\u002F.agents\u002Fskills\u002Fazure-openai-to-responses\u002Fscripts\u002Fdetect_legacy.py)\n- [Azure OpenAI 入門套件](https:\u002F\u002Faka.ms\u002Fopenai\u002Fstart)\n- [Azure OpenAI Responses API 文件](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fai-foundry\u002Fopenai\u002Fhow-to\u002Fresponses)\n- [Azure OpenAI API 版本生命週期](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fai-foundry\u002Fopenai\u002Fapi-version-lifecycle?view=foundry-classic&tabs=python#api-evolution)\n- [OpenAI Responses API 參考](https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fapi-reference\u002Fresponses)\n\n---\n\n\u003C!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**免責聲明**：\n本文件使用 AI 翻譯服務 [Co-op Translator](https:\u002F\u002Fgithub.com\u002FAzure\u002Fco-op-translator) 進行翻譯。雖然我們力求準確，但請注意，自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊，建議尋求專業人工翻譯。我們不對因使用本翻譯而引起的任何誤解或曲解承擔責任。\n\u003C!-- CO-OP TRANSLATOR DISCLAIMER END -->","# 將 Python 應用程式從 Azure OpenAI Chat Completions 遷移到 Responses API\n\n> **權威指南 — 請嚴格遵循**\n>\n> 本技能協助遷移使用 Azure OpenAI Chat Completions 的 Python 程式碼庫\n> 至統一的 Responses API。請嚴格按照這些指示執行。\n> 請勿即興映射參數或自行創建 API 結構。\n\n---\n\n## 啟動條件\n\n當用戶希望執行下列操作時啟用此技能：\n- 將 Python 應用程式從 Azure OpenAI Chat Completions 遷移至 Responses API\n- 將 Python OpenAI SDK 用法升級至針對 Azure OpenAI 的最新 API 結構\n- 為 GPT-5 或更新版本需要在 Azure 上使用 Responses 的模型準備 Python 程式碼\n- 從 `AzureOpenAI`\u002F`AsyncAzureOpenAI` 切換至使用標準的 `OpenAI`\u002F`AsyncOpenAI` 客戶端及 v1 端點\n- 修正與 `AzureOpenAI` 建構函式或 `api_version` 相關的棄用警告\n\n---\n\n## ⚠️ 模型相容性 — 請先確認\n\n> **遷移前，請確認您的 Azure OpenAI 部署支援 Responses API。**\n\n### 1. 簡易測試您的部署（最快速）\n\n```python\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('\u002F')}\u002Fopenai\u002Fv1\u002F\",\n)\n\ntry:\n    resp = client.responses.create(\n        model=os.environ[\"AZURE_OPENAI_DEPLOYMENT\"],\n        input=\"ping\",\n        max_output_tokens=50,\n        store=False,\n    )\n    print(f\"✅ Deployment supports Responses API: {resp.output_text}\")\nexcept Exception as e:\n    print(f\"❌ Deployment does NOT support Responses API: {e}\")\n```\n\n> \u003Cstrong>注意\u003C\u002Fstrong>：Azure OpenAI 上的 `max_output_tokens` 最小值為 **16**。小於 16 將返回 400 錯誤。簡易測試請使用 50 以上。\n\n若此請求返回 404，表示該部署使用的模型尚未支援 Responses，請參考下面的參考資料或重新部署支援的模型。\n\n### 2. 檢查您區域可用模型（推薦）\n\n運行內建的模型相容性工具來查看您區域有哪些模型支援 Responses API：\n\n```bash\npython migrate.py models --subscription YOUR_SUB_ID --location YOUR_REGION\n```\n\n此命令會查詢 Azure ARM 實時狀態並展示相容性矩陣 — 哪些模型支援 Responses、結構化輸出、工具等。可用 `--filter gpt-5.1,gpt-5.2` 篩選結果，或用 `--json` 做腳本處理。\n\n### 3. 完整模型相容參考\n\n- \u003Cstrong>即時查詢\u003C\u002Fstrong>：`python migrate.py models`（如上述所示 — 依區域不同，資料永遠最新）\n- \u003Cstrong>瀏覽可用性\u003C\u002Fstrong>：[模型摘要表及區域可用性](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Ffoundry\u002Ffoundry-models\u002Fconcepts\u002Fmodels-sold-directly-by-azure?tabs=global-standard-aoai%2Cglobal-standard&pivots=azure-openai#model-summary-table-and-region-availability)\n- \u003Cstrong>快速入門與指南\u003C\u002Fstrong>：**https:\u002F\u002Faka.ms\u002Fopenai\u002Fstart**\n\n### ⚠️ 舊版模型限制\n\n> \u003Cstrong>警告\u003C\u002Fstrong>：舊版模型（`gpt-4.1` 之前的）可能無法完全支援所有 Responses API 功能。\n>\n> 舊版模型已知限制：\n> - **`reasoning` 參數**：許多非推理模型不支援。只有原本代碼使用過才遷移此參數。\n> - **`seed` 參數**：Responses API 完全不支援，務必移除。\n> - **透過 `text.format` 的結構化輸出**：舊版模型可能無法穩定強制 `strict: true` 的 JSON 架構。\n> - \u003Cstrong>工具編排\u003C\u002Fstrong>：GPT-5+ 在推理中整合工具呼叫。舊版模型仍運作，但缺乏此深入整合。\n> - \u003Cstrong>溫度限制\u003C\u002Fstrong>：遷移至 `gpt-5` 時，溫度需省略或設定為 `1`。舊版模型無此限制。\n\n### O 系列推理模型 (o1, o3-mini, o3, o4-mini)\n\nO 系列模型有特別的參數限制。遷移針對 O 系列模型的應用程式時：\n\n- **`temperature`**：必須是 `1`（或省略）。O 系列不接受其他值。\n- **`max_completion_tokens` → `max_output_tokens`**：使用 Azure 專屬的 `max_completion_tokens` 的應用需切換至 `max_output_tokens`。由於推理會消耗 Token，設定較高值（4096 以上）。\n- **`reasoning_effort`**：若使用 `reasoning_effort`（low\u002Fmedium\u002Fhigh），保留即可 — Responses API 支援 O 系列模型這參數。\n- \u003Cstrong>串流行為\u003C\u002Fstrong>：O 系列模型可能會緩衝輸出直到推理完成才發出文字差異事件。串流仍可用，但第一個 `response.output_text.delta` 可能較 GPT 模型延遲較久才送達。\n- **`top_p`**：O 系列不支援此參數 — 若存在請移除。\n- \u003Cstrong>工具使用\u003C\u002Fstrong>：O 系列模型透過 Responses API 支援工具，與 GPT 模型相同，但工具呼叫編排品質因模型不同而異。\n\n**措施 — 主動模型諮詢**：掃描階段檢查應用程式目標模型（部署名稱、環境變數、設定）。若模型為 `gpt-4.1` 之前版本，主動告知用戶：\n- 對其目前模型，遷移可支援基本文字、聊天、串流及工具功能。\n- 較新模型（`gpt-5.1`、`gpt-5.2`）提供更好的工具編排、結構化輸出強制、推理和跨區域可用性。\n- 建議用戶在準備好時考慮升級部署 — 並非遷移阻礙。\n\n不要以模型版本為由阻止或拒絕遷移。此諮詢為資訊性提示。\n\n### GitHub Models 不支援 Responses API\n\n> **GitHub Models (`models.github.ai`, `models.inference.ai.azure.com`) 不支援 Responses API。**\n\n若程式碼中有 GitHub Models 路徑（例如 `base_url` 指向 `models.github.ai` 或 `models.inference.ai.azure.com`），\u003Cstrong>請在遷移時完全移除\u003C\u002Fstrong>。Responses API 需使用 Azure OpenAI、OpenAI 或相容的本地端點（例如支援 Responses 的 Ollama）。\n\n掃描時應採取的措施：\n- 標示任何 GitHub Models 路徑以便移除。\n\n---\n\n## 框架遷移\n\n許多應用程式使用封裝 OpenAI 的高階框架。遷移這些框架時，不僅底層 OpenAI 呼叫改變，框架自身的 API 也會變更。\n\n### Microsoft Agent Framework (MAF)\n\n**首先檢查您的 MAF 版本** — 遷移將依您使用的是 MAF 1.0.0+ 還是 1.0.0 之前的 beta\u002Frc 版本而異。\n\n#### MAF 1.0.0+ (agent-framework-openai >= 1.0.0)\n\n`OpenAIChatClient` **已經使用 Responses API** — 無需遷移。若程式碼使用舊版 `OpenAIChatCompletionClient`（基於 `chat.completions.create`），請改用 `OpenAIChatClient`。\n\n| 之前 | 之後 |\n|--------|-------|\n| `from agent_framework.openai import OpenAIChatCompletionClient` | `from agent_framework.openai import OpenAIChatClient` |\n| `OpenAIChatCompletionClient(...)` | `OpenAIChatClient(...)` |\n\n查看版本：`python -c \"import agent_framework_openai; print(agent_framework_openai.__version__)\"` \n\n#### MAF 1.0.0 之前版本（beta\u002Frc）\n\n在 MAF 1.0.0 之前版本中，`OpenAIChatClient` 使用 Chat Completions。請升級到 `agent-framework-openai>=1.0.0`，它會預設使用 Responses API 的 `OpenAIChatClient`。\n\n其他 API（如 `Agent` 和工具）不變。\n\n### LangChain (`langchain-openai`)\n\n在 `ChatOpenAI()` 中新增 `use_responses_api=True`。並更新響應訪問方式，從 `.content` 改為 `.text`。\n\n| 之前 | 之後 |\n|--------|-------|\n| `ChatOpenAI(model=..., base_url=..., api_key=...)` | `ChatOpenAI(model=..., base_url=..., api_key=..., use_responses_api=True)` |\n| `result['messages'][-1].content` | `result['messages'][-1].text` |\n\n完整前後代碼範例，請參考 [cheat-sheet.md](.\u002Freferences\u002Fcheat-sheet.md)。\n\n---\n\n## 前端遷移指導\n\n> **Responses API 是後端處理。** 請遷移您的 Python 後端；前端的 HTTP 合約應保持不變，除非您的後端只是個簡單轉送層 — 在那種情況下，考慮採用 Responses 請求結構以消除翻譯層。若前端使用客戶端密鑰直接呼叫 OpenAI，請先將這些呼叫移至後端。\n\n### `@microsoft\u002Fai-chat-protocol` 棄用\n\n`@microsoft\u002Fai-chat-protocol` npm 包已棄用，應改用 [`ndjson-readablestream`](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fndjson-readablestream)。若前端遇到此包：\n\n1. 替換 CDN 腳本標籤：\n   ```html\n   \u003C!-- Before -->\n   \u003Cscript src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002F@microsoft\u002Fai-chat-protocol@...\u002Fdist\u002Fiife\u002Findex.js\">\u003C\u002Fscript>\n   \u003C!-- After -->\n   \u003Cscript src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fndjson-readablestream@1.0.7\u002Fdist\u002Fndjson-readablestream.umd.js\">\u003C\u002Fscript>\n   ```\n2. 移除 `AIChatProtocolClient` 實例化（`new ChatProtocol.AIChatProtocolClient(\"\u002Fchat\")`）。\n3. 將 `client.getStreamedCompletion(messages)` 改成直接 `fetch()` 後端串流端點。\n4. 將 `for await (const response of result)` 改為 `for await (const chunk of readNDJSONStream(response.body))`。\n5. 更新屬性訪問方式，從 `response.delta.content` \u002F `response.error` 改為 `chunk.delta.content` \u002F `chunk.error`。\n\n---\n\n## 目標\n\n- 枚舉所有使用 Chat Completions 或舊版 Completions 呼叫 Azure OpenAI 的 Python 呼叫點。\n- 擬定 Python 程式碼庫的遷移計畫與順序。\n- 採用安全且最小修改方式切換至 Responses API。\n- 更新呼叫端以消費 Responses 輸出結構；不使用任何向後相容包裝。\n- 執行測試與靜態檢查；修正遷移導致的小錯誤。\n- 準備小且可審核的變更集，並提供最終摘要及差異 (不執行 commit)。\n\n---\n\n## 防護措施\n\n- 僅修改 Git 工作區內的檔案，禁止對工作區外寫入。\n- 不保留向後相容性 shim；直接遷移至新 API 結構。\n- 不留存銘碑註解或備份檔案。\n- 若先前使用串流，務必保留串流語意；否則可改為非串流。\n- 若為審批模式，操作命令或網絡呼叫前請先取得批准。\n- 不執行 `git add`\u002F`git commit`\u002F`git push`；僅產生工作樹修改。\n\n---\n\n## 第 0 步：Azure OpenAI 客戶端遷移（先決條件）\n\n若程式碼庫使用 `AzureOpenAI` 或 `AsyncAzureOpenAI` 建構子，請先遷移到標準的 `OpenAI` \u002F `AsyncOpenAI` 建構子。Azure 專屬建構子在 `openai>=1.108.1` 中已棄用。\n\n### 為何使用 v1 API 路徑？\n\n新的 `\u002Fopenai\u002Fv1` 端點使用標準的 `OpenAI()` 客戶端替代 `AzureOpenAI()`，無需 `api_version` 參數，在 OpenAI 和 Azure OpenAI 間行為一致。相同的客戶端代碼具有未來相容性 — 無需版本管理。\n\n### 關鍵改變\n\n| 之前 | 之後 |\n|--------|-------|\n| `AzureOpenAI` | `OpenAI` |\n| `AsyncAzureOpenAI` | `AsyncOpenAI` |\n| `azure_endpoint` | `base_url` |\n| `azure_ad_token_provider` | `api_key` |\n| `api_version=...` | 完全移除 |\n\n### 清理清單\n\n- 移除建構客戶端時的 `api_version` 參數。\n- 從 `.env`、應用設置及 Bicep\u002F基礎架構檔移除 `AZURE_OPENAI_VERSION` \u002F `AZURE_OPENAI_API_VERSION` 環境變數。\n- 將 `.env`、應用設置、Bicep\u002F基礎架構及測試 fixture 中的 `AZURE_OPENAI_CLIENT_ID` 改名為 `AZURE_CLIENT_ID`（符合 Azure 身分識別 SDK 標準慣例）。\n- 確保在 `requirements.txt` 或 `pyproject.toml` 中使用 `openai>=1.108.1`。\n\n### 環境變數遷移\n\n| 舊環境變數 | 措施 | 備註 |\n|-------------|--------|-------|\n| `AZURE_OPENAI_VERSION` | \u003Cstrong>移除\u003C\u002Fstrong> | v1 端點不需 `api_version` |\n| `AZURE_OPENAI_API_VERSION` | \u003Cstrong>移除\u003C\u002Fstrong> | 同上 |\n| `AZURE_OPENAI_CLIENT_ID` | \u003Cstrong>改名\u003C\u002Fstrong> → `AZURE_CLIENT_ID` | Azure 身分識別 SDK 的標準 `ManagedIdentityCredential(client_id=...)` 慣例 |\n| `AZURE_OPENAI_ENDPOINT` | \u003Cstrong>保留\u003C\u002Fstrong> | 仍用於 `base_url` 建構 |\n| `AZURE_OPENAI_CHAT_DEPLOYMENT` | \u003Cstrong>保留\u003C\u002Fstrong> | 用作 `responses.create` 的 `model` 參數 |\n| `AZURE_OPENAI_API_KEY` | \u003Cstrong>保留\u003C\u002Fstrong> | 用於基於金鑰的認證 `api_key` |\n\n有關客戶端設置代碼範例（同步、非同步、EntraID、API 金鑰、多租戶）請參考 [cheat-sheet.md](.\u002Freferences\u002Fcheat-sheet.md)。\n\n---\n\n## 第 1 步：偵測舊版呼叫點\n\n執行 [detect_legacy.py](..\u002F..\u002F..\u002F..\u002F..\u002F.agents\u002Fskills\u002Fazure-openai-to-responses\u002Fscripts\u002Fdetect_legacy.py) 腳本以找到所有需要遷移的呼叫點：\n\n```bash\npython skills\u002Fazure-openai-to-responses\u002Fscripts\u002Fdetect_legacy.py .\n```\n\n或手動執行此類搜尋 — 每個匹配即為遷移目標：\n\n```bash\n# 傳統 API 調用（必須重寫）\nrg \"chat\\.completions\\.create\"\nrg \"ChatCompletion\\.create\"\nrg \"Completion\\.create\"\n\n# 已棄用的 Azure 客戶端建構子（必須替換）\nrg \"AzureOpenAI\\(\"\nrg \"AsyncAzureOpenAI\\(\"\n\n# 回應結構存取模式（必須更新）\nrg \"choices\\[0\\]\\.message\\.content\"\nrg \"choices\\[0\\]\\.delta\\.content\"\nrg \"choices\\[0\\]\\.message\\.function_call\"\nrg \"choices\\[0\\]\\.message\\.tool_calls\"\n\n# 舊巢狀格式的工具定義（必須扁平化）\nrg '\"function\":\\s*{\\s*\"name\"'\nrg \"pydantic_function_tool\"\n\n# 舊格式的工具結果（必須轉換為 function_call_output）\nrg '\"role\":\\s*\"tool\"'\nrg '\"tool_call_id\"'\n\n# 已棄用的參數（必須刪除或重新命名）\nrg \"response_format\"\nrg \"max_tokens\\b\"        # 重新命名為 max_output_tokens\nrg \"['\\\"]seed['\\\"]\"      # remove entirely\n\n# 已棄用的環境變量（清理）\nrg \"AZURE_OPENAI_API_VERSION|AZURE_OPENAI_VERSION\"\nrg \"AZURE_OPENAI_CLIENT_ID\"  # 應該是 AZURE_CLIENT_ID\n\n# GitHub 模型端點（必須移除 — 不支援 Responses API）\nrg \"models\\.github\\.ai|models\\.inference\\.ai\\.azure\"\n\n# 框架層級的傳統模式（必須更新）\nrg \"OpenAIChatCompletionClient\"  # MAF 1.0.0+：替換成 OpenAIChatClient\nrg \"ChatOpenAI\\(\" | grep -v \"use_responses_api\"  # LangChain：需要 use_responses_api=True\n\n# 測試基礎設施（必須更新）\nrg \"ChatCompletionChunk|AsyncCompletions\\.create\" tests\u002F\nrg \"_azure_ad_token_provider\" tests\u002F\nrg \"prompt_filter_results|content_filter_results\" tests\u002F\nrg \"choices\\[0\\]\" tests\u002F\n\n# 內容過濾錯誤主體存取（必須更新 — 結構已更改）\nrg 'innererror.*content_filter_result|error\\.body\\[\"innererror\"\\]'\nrg \"content_filter_result\\[\" # 舊單數形式 — 現在是 content_filters 陣列內的 content_filter_results（複數）\n\n# 對 Chat Completions 端點的原始 HTTP 調用（必須更新 URL）\nrg \"\u002Fopenai\u002Fdeployments\u002F.*\u002Fchat\u002Fcompletions\"\nrg \"api-version=\"\n```\n\n### 偵測與重寫的啟發式\n\n- **Chat Completions 客戶端**：從 `client.chat.completions.create` → `client.responses.create(...)`。\n\n- **Azure 用戶端建構子**：`AzureOpenAI(...)` → `OpenAI(base_url=..., api_key=...)`。\n- \u003Cstrong>工具\u003C\u002Fstrong>：將函式呼叫工具定義從巢狀格式 (`{\"type\": \"function\", \"function\": {\"name\": ...}}`) 轉換成平坦的 Responses 格式 (`{\"type\": \"function\", \"name\": ...}`)；使用 `tool_choice`；返回工具結果為 `{\"type\": \"function_call_output\", \"call_id\": ..., \"output\": ...}` 項目（而非 `{\"role\": \"tool\", ...}`）。\n- \u003Cstrong>工具迴圈往返\u003C\u002Fstrong>：當模型返回函式呼叫時，將 `response.output` 項目追加到對話中（非手動的 `{\"role\": \"assistant\", \"tool_calls\": [...]}` 字典），然後為每個結果追加 `function_call_output` 項目。\n- \u003Cstrong>少量範例工具呼叫\u003C\u002Fstrong>：若對話包括硬編碼的工具呼叫範例，將它們轉換成 `{\"type\": \"function_call\", \"id\": \"fc_...\", \"call_id\": \"fc_...\", ...}` + `{\"type\": \"function_call_output\", ...}` 項目。ID 必須以 `fc_` 開頭。\n- **`pydantic_function_tool()`\u003Cstrong>：此輔助函式仍會產生舊有的巢狀格式，\u003C\u002Fstrong>不相容**於 `responses.create()`。請改用手動工具定義或扁平化包裝器。\n- \u003Cstrong>多輪互動\u003C\u002Fstrong>：在應用中維護對話歷史；傳遞先前回合透過 `input` 項目。\n- \u003Cstrong>格式\u003C\u002Fstrong>：以 Responses 取代 Chat 的頂層 `response_format`，改為使用 `text.format`。規範格式：`text={\"format\": {\"type\": \"json_schema\", \"name\": \"Output\", \"strict\": True, \"schema\": {...}}}`。\n- \u003Cstrong>內容項目\u003C\u002Fstrong>：將 Chat 的 `content[].type: \"text\"` 替換為 Responses 的 `content[].type: \"input_text\"`（用戶／系統回合）。\n- \u003Cstrong>圖像內容項目\u003C\u002Fstrong>：將 Chat 的 `content[].type: \"image_url\"` 替換為 Responses 的 `content[].type: \"input_image\"`。`image_url` 欄位從巢狀物件 `{\"url\": \"...\"}` 變成扁平字串。詳見速查表前後範例。\n- \u003Cstrong>推理努力\u003C\u002Fstrong>：**僅在原始程式已有 `reasoning` 字段時遷移**。\n- \u003Cstrong>內容過濾錯誤處理\u003C\u002Fstrong>：錯誤主體結構變更。Chat Completions 使用 `error.body[\"innererror\"][\"content_filter_result\"]`（單數）；Responses API 使用 `error.body[\"content_filters\"][0][\"content_filter_results\"]`（複數，陣列中）。存取 `innererror` 的程式將引發 `KeyError`。請改用新路徑。\n- **原始 HTTP 呼叫**：若應用直接呼叫 Azure OpenAI REST API（透過 `requests`、`httpx` 等）使用 `\u002Fopenai\u002Fdeployments\u002F{name}\u002Fchat\u002Fcompletions?api-version=...`，請改寫為 `\u002Fopenai\u002Fv1\u002Fresponses`。請求主體變更：`messages` → `input`、新增 `max_output_tokens` 和 `store: false`、移除 `api-version` 查詢參數。回應主體變更：`choices[0].message.content` → `output[0].content[0].text`（註：`output_text` 為 SDK 方便屬性，原生 REST JSON 中無）。\n\n---\n\n## 步驟 2：應用遷移\n\n### 遷移注意事項 (Chat Completions → Responses)\n\n- \u003Cstrong>為何要遷移\u003C\u002Fstrong>：Responses 是文字、工具及串流統一 API；Chat Completions 為舊版。搭配 GPT-5，必須使用 Responses 以達最佳效能。\n- **HTTP**：Azure 端點從 `\u002Fopenai\u002Fdeployments\u002F{name}\u002Fchat\u002Fcompletions` 轉至 `\u002Fopenai\u002Fv1\u002Fresponses`。\n- \u003Cstrong>欄位\u003C\u002Fstrong>：`messages` → `input`，`max_tokens` → `max_output_tokens`。`temperature` 不變。\n- \u003Cstrong>格式\u003C\u002Fstrong>：`response_format` → `text.format`（物件格式）。\n- \u003Cstrong>內容項目\u003C\u002Fstrong>：替換 Chat 的 `content[].type: \"text\"` 為 Responses 的 `content[].type: \"input_text\"`，適用於系統／使用者回合。\n- \u003Cstrong>圖像內容項目\u003C\u002Fstrong>：替換 Chat 的 `content[].type: \"image_url\"` 為 Responses 的 `content[].type: \"input_image\"`。將 `image_url` 欄位從 `{\"image_url\": {\"url\": \"...\"}}` 扁平化為 `{\"image_url\": \"...\"}`（純字串—HTTPS URL 或 `data:image\u002F...;base64,...` 資料 URI）。\n\n### 參數對照參考\n\n| Chat Completions | Responses API |\n|-----------------|---------------|\n| `prompt` | `input` |\n| `messages` | `input`（項目陣列） |\n| `max_tokens` | `max_output_tokens` |\n| `response_format` | `text.format`（物件） |\n| `temperature` | `temperature`（不變） |\n| `stop` | `stop`（不變） |\n| `frequency_penalty` | `frequency_penalty`（不變） |\n| `presence_penalty` | `presence_penalty`（不變） |\n| `tools` \u002F 函式呼叫 | `tools`（不變） |\n| `seed` | \u003Cstrong>移除\u003C\u002Fstrong>（不支援） |\n| `store` | `store`（設定為 `false`） |\n| `content[].type: \"text\"` | `content[].type: \"input_text\"` |\n| `content[].type: \"image_url\"` | `content[].type: \"input_image\"` |\n| `\"image_url\": {\"url\": \"...\"}` | `\"image_url\": \"...\"`（扁平字串） |\n\n完整前後範例程式碼請參見 [cheat-sheet.md](.\u002Freferences\u002Fcheat-sheet.md)。\n\n考量測試基礎設施遷移（mocks、快照、斷言），請見 [test-migration.md](.\u002Freferences\u002Ftest-migration.md)。\n\n如需錯誤診斷及注意事項，請見 [troubleshooting.md](.\u002Freferences\u002Ftroubleshooting.md)。\n\n---\n\n## 資料保留與狀態\n\n- 所有 Responses 請求設定 `store: false`。\n- 不依賴先前訊息 ID 或伺服器保存的上下文；狀態由用戶端管理並盡量減少元資料。\n\n---\n\n## 驗收標準\n\n### 程式碼層級門檻（全部通過）\n\n- [ ] 在遷移後檔案中，搜尋 `rg \"chat\\.completions\\.create|ChatCompletion\\.create|Completion\\.create\"`，應為零結果。\n- [ ] 搜尋 `rg \"AzureOpenAI\\(|AsyncAzureOpenAI\\(\"`，全部建構子改用帶 v1 端點的 `OpenAI`\u002F`AsyncOpenAI`。\n- [ ] 搜尋 `rg \"models\\.github\\.ai|models\\.inference\\.ai\\.azure\"`，GitHub Models 相關程式路徑已移除。\n- [ ] 搜尋 `rg \"OpenAIChatCompletionClient\"`，MAF 1.0.0+ 程式碼使用 `OpenAIChatClient`（搭配 Responses API）。1.0.0 以前請升級至 `agent-framework-openai>=1.0.0`。\n- [ ] 所有 `ChatOpenAI(...)` 呼叫含 `use_responses_api=True`。\n- [ ] 搜尋 `rg \"choices\\[0\\]\"`，所有存取回應皆使用 `resp.output_text` 或 Responses 輸出結構。\n- [ ] 頂層不出現 `response_format`；所有結構化輸出使用 `text={\"format\": {...}}`。\n- [ ] `requirements.txt` 或 `pyproject.toml` 中有 `openai>=1.108.1` 與 `azure-identity`；依賴重新安裝完畢。\n- [ ] 每個 `responses.create` 呼叫設定 `store=False`。\n- [ ] 用戶端建構時不包含 `api_version`；環境變數及基礎設施中移除 `AZURE_OPENAI_API_VERSION`。\n\n### 測試基礎設施門檻（全部通過）\n\n- [ ] 在 `tests\u002F` 中搜尋 `rg \"ChatCompletionChunk|AsyncCompletions\\.create|chat\\.completions\"`，應為零結果。\n- [ ] 在 `tests\u002F` 中搜尋 `rg \"_azure_ad_token_provider\"`，斷言更新為檢查 `isinstance(client, AsyncOpenAI)` 或 `base_url`。\n- [ ] 在 `tests\u002F` 中搜尋 `rg \"prompt_filter_results|content_filter_results\"`，移除 Azure 特有過濾器 mocks。\n- [ ] mock fixtures 使用 `kwargs.get(\"input\")`，而非 `kwargs.get(\"messages\")`。\n- [ ] 快照與 golden 檔案更新為 Responses 串流格式（無 `choices[0]`、`function_call`、`logprobs` 等）。\n- [ ] 所有測試更新後 `pytest` 通過且無失敗。\n\n### 行為門檻（手動或透過測試套件驗證）\n\n- [ ] \u003Cstrong>基本完成測試\u003C\u002Fstrong>：非串流 `responses.create` 返回非空字串 `output_text`。\n- [ ] \u003Cstrong>串流一致性\u003C\u002Fstrong>：原程式有使用串流，則遷移後程式也串流並產生包含非空增量的 `response.output_text.delta` 事件。\n- [ ] \u003Cstrong>結構化輸出\u003C\u002Fstrong>：使用 `text.format` 加上 `json_schema` 時，`json.loads(resp.output_text)` 可成功解析且符合架構。\n- [ ] \u003Cstrong>工具呼叫迴圈\u003C\u002Fstrong>：若有使用工具，模型發出工具呼叫、應用執行呼叫，後續請求回傳最終 `output_text`（無無限迴圈）。\n- [ ] \u003Cstrong>非同步一致性\u003C\u002Fstrong>：若使用 `AsyncAzureOpenAI`，其對應的 `AsyncOpenAI` 可配合 `await` 正常運作。\n- [ ] \u003Cstrong>錯誤率\u003C\u002Fstrong>：相較遷移前基線，無新增 400\u002F401\u002F404 錯誤。\n\n### 交付項目\n\n- 摘要包含已編輯檔案、舊版調用數前後對比、下一步。\n- 變更僅限工作樹編輯（無提交）。\n\n---\n\n## SDK 版本需求\n\n| 套件 | 最低版本 |\n|---------|----------------|\n| `openai` | `>=1.108.1` |\n| `azure-identity` | 最新版（用於 EntraID 認證） |\n\n---\n\n## 參考資源\n\n- [速查表 — 所有程式碼片段](.\u002Freferences\u002Fcheat-sheet.md)\n- [測試遷移 — mocks、快照、斷言](.\u002Freferences\u002Ftest-migration.md)\n- [故障排除 — 錯誤、風險表、注意事項](.\u002Freferences\u002Ftroubleshooting.md)\n- [detect_legacy.py — 自動掃描器](..\u002F..\u002F..\u002F..\u002F..\u002F.agents\u002Fskills\u002Fazure-openai-to-responses\u002Fscripts\u002Fdetect_legacy.py)\n- [Azure OpenAI 入門套件](https:\u002F\u002Faka.ms\u002Fopenai\u002Fstart)\n- [Azure OpenAI Responses API 文件](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fai-foundry\u002Fopenai\u002Fhow-to\u002Fresponses)\n- [Azure OpenAI API 版本生命週期](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fai-foundry\u002Fopenai\u002Fapi-version-lifecycle?view=foundry-classic&tabs=python#api-evolution)\n- [OpenAI Responses API 參考](https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fapi-reference\u002Fresponses)\n\n---\n\n\u003C!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**免責聲明**：\n本文件使用 AI 翻譯服務 [Co-op Translator](https:\u002F\u002Fgithub.com\u002FAzure\u002Fco-op-translator) 進行翻譯。雖然我們力求準確，但請注意，自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊，建議尋求專業人工翻譯。我們不對因使用本翻譯而引起的任何誤解或曲解承擔責任。\n\u003C!-- CO-OP TRANSLATOR DISCLAIMER END -->",{"name":5,"license":14},"main","f09e94ffe170f8af6d3db7c42987bbe4db227723","translations\u002Fzh-MO\u002F.agents\u002Fskills\u002Fazure-openai-to-responses",26019,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners","https:\u002F\u002Faka.ms\u002Fai-agents-beginners","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-11-07 12:51:12",{"source":7,"skillName":5,"commands":35,"prompt":45,"zipAvailable":46},[36,39,42],{"tool":37,"command":38},"npx","npx skills add microsoft\u002Fai-agents-for-beginners --skill azure-openai-to-responses",{"tool":40,"command":41},"bunx","bunx skills add microsoft\u002Fai-agents-for-beginners --skill azure-openai-to-responses",{"tool":43,"command":44},"pnpm","pnpm dlx skills add microsoft\u002Fai-agents-for-beginners --skill azure-openai-to-responses","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-MO\u002F.agents\u002Fskills\u002Fazure-openai-to-responses\u002FSKILL.md",true,[48,54,58],{"path":49,"resourceType":50,"resourceTypeDesc":51,"sizeBytes":52,"sourceHtmlUrl":53},"references\u002Fcheat-sheet.md","REFERENCE","参考文档",28226,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-MO\u002F.agents\u002Fskills\u002Fazure-openai-to-responses\u002Freferences\u002Fcheat-sheet.md",{"path":55,"resourceType":50,"resourceTypeDesc":51,"sizeBytes":56,"sourceHtmlUrl":57},"references\u002Ftest-migration.md",7078,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-MO\u002F.agents\u002Fskills\u002Fazure-openai-to-responses\u002Freferences\u002Ftest-migration.md",{"path":59,"resourceType":50,"resourceTypeDesc":51,"sizeBytes":60,"sourceHtmlUrl":61},"references\u002Ftroubleshooting.md",14443,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-MO\u002F.agents\u002Fskills\u002Fazure-openai-to-responses\u002Freferences\u002Ftroubleshooting.md",[63,81,92,100,108,115],{"skillNo":64,"name":65,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":66,"categories":67,"keywords":78,"publishedAt":19},"01M69A206TRZ8KK0CW0HYJF5V5","testing-course-samples","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-TW\u002F.agents\u002Fskills\u002Ftesting-course-samples\u002FSKILL.md",[68,73],{"categoryNo":69,"categoryName":70,"taxonomyType":71,"taxonomyTypeDesc":72},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":74,"categoryName":75,"taxonomyType":76,"taxonomyTypeDesc":77},"01JBSEEDCAT000000000000039","教师与教育","PROFESSION","适用职业",[79,80],"testing","testing course samples",{"skillNo":82,"name":83,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":84,"categories":85,"keywords":89,"publishedAt":19},"01M69A1XRB2SFHYRMEH0K08EKZ","microsoft-docs","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-TW\u002F.agents\u002Fskills\u002Fmicrosoft-docs\u002FSKILL.md",[86],{"categoryNo":87,"categoryName":88,"taxonomyType":71,"taxonomyTypeDesc":72},"01JBSEEDCAT000000000000023","Skill与智能体开发",[90,8,91],"docs","microsoft docs",{"skillNo":93,"name":94,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":95,"categories":96,"keywords":97,"publishedAt":19},"01M69A1VPZFJQ1HNGTZQ5P3WSC","local-ai-agents","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-TW\u002F.agents\u002Fskills\u002Flocal-ai-agents\u002FSKILL.md",[],[98,99],"ai agents","local ai agents",{"skillNo":101,"name":102,"nameZh":6,"description":103,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":104,"categories":105,"keywords":106,"publishedAt":19},"01M69A1S947N7MM6V9JF85S2E7","jupyter-notebook","當使用者要求建立、搭建或編輯 Jupyter 筆記本（`.ipynb`）用於實驗、探索或教學時使用；優先使用隨附範本並執行輔助腳本 `new_notebook.py` 來產生一個乾淨的起始筆記本。","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-TW\u002F.agents\u002Fskills\u002Fjupyter-notebook\u002FSKILL.md",[],[107],"jupyter notebook",{"skillNo":109,"name":110,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":111,"categories":112,"keywords":113,"publishedAt":19},"01M69A1Q8EXPWKZSQK69V6WF22","deploying-scalable-agents","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-TW\u002F.agents\u002Fskills\u002Fdeploying-scalable-agents\u002FSKILL.md",[],[114],"deploying scalable agents",{"skillNo":116,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":119,"publishedAt":19},"01M69A1MHZTH3RH9N8VYSYG74X","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-TW\u002F.agents\u002Fskills\u002Fazure-openai-to-responses\u002FSKILL.md",[],[18]]