[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M69A087YFEQQ70ZZAATS6FKD":3,"skill-same:01M69A087YFEQQ70ZZAATS6FKD":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},"01M69A087YFEQQ70ZZAATS6FKD","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-CN\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 聊天补全迁移到 Responses API\n\n> **权威指南 — 请严格遵循**\n>\n> 该技能将使用 Azure OpenAI 聊天补全的 Python 代码库\n> 迁移到统一的 Responses API。请严格遵循这些说明。\n> 不要即兴映射参数或发明 API 形态。\n\n---\n\n## 触发条件\n\n当用户希望时启用此技能：\n- 将 Python 应用从 Azure OpenAI 聊天补全迁移到 Responses API\n- 升级 Python OpenAI SDK 的用法至针对 Azure OpenAI 的最新 API 形态\n- 为需要 Azure 上 Responses 的 GPT-5 或更新模型准备 Python 代码\n- 从 `AzureOpenAI`\u002F`AsyncAzureOpenAI` 切换到带 v1 端点的标准 `OpenAI`\u002F`AsyncOpenAI` 客户端\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` 参数**：许多非推理模型不支持。仅当原代码已经存在 `reasoning` 时才迁移。\n> - **`seed` 参数**：Responses API 完全不支持，需从所有请求中移除。\n> - **通过 `text.format` 实现的结构化输出**：旧模型可能无法可靠强制执行 `strict: true` 的 JSON schema。\n> - \u003Cstrong>工具编排\u003C\u002Fstrong>：GPT-5+ 作为内部推理部分协调工具调用。旧模型使用 Responses 仍能工作，但缺少深度集成。\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`。设置较高值（4096+），因为推理用的标记计入限制。\n- **`reasoning_effort`**：如果应用使用 `reasoning_effort`（低\u002F中\u002F高），请保留—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`（不是 gpt-4.1+），主动告知用户：\n- 当前模型下迁移支持基础文本、聊天、流式和工具。\n- 新模型（`gpt-5.1`、`gpt-5.2`）在工具编排、结构化输出强制、推理和跨区域可用性方面表现更好。\n- 用户应考虑在适当时升级部署 — 这不影响迁移本身。\n\n不因模型版本阻止或拒绝迁移。该建议为信息性质。\n\n### GitHub 模型不支持 Responses API\n\n> **GitHub 模型（`models.github.ai`、`models.inference.ai.azure.com`）不支持 Responses API。**\n\n如果代码库有 GitHub 模型的代码路径（检查 `base_url` 是否指向 `models.github.ai` 或 `models.inference.ai.azure.com`），\u003Cstrong>迁移时请完全移除\u003C\u002Fstrong>。Responses API 需要 Azure OpenAI、OpenAI 或兼容的本地端点（如支持 Responses 的 Ollama）。\n\n扫描阶段操作：\n- 标记所有 GitHub 模型代码路径以备删除。\n\n---\n\n## 框架迁移\n\n许多应用使用 OpenAI 之上的高级框架。迁移它们时，需变更框架自身 API，而非仅底层 OpenAI 调用。\n\n### Microsoft 代理框架 (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` 使用聊天补全。升级至 `agent-framework-openai>=1.0.0`，默认使用 Responses API。\n\n其他接口不变 — `Agent` 和工具 API 保持一样。\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 是服务器端的 concern。** 迁移您的 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- 执行测试\u002F静态检查；修复迁移带来的轻微破坏。\n- 准备小型、易复审的变更集并提供最终带差异摘要（不提交）。\n\n---\n\n## 保护措施\n\n- 仅修改 git 工作区内的文件，绝不向外写文件。\n- 不保留向后兼容 shim；将代码迁移至新 API 形态。\n- 不留墓碑\u002F过渡注释或备份文件。\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基础设施及测试夹具中的 `AZURE_OPENAI_CLIENT_ID` 重命名为 `AZURE_CLIENT_ID`（遵守 Azure Identity 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 Identity 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- \u003Cstrong>聊天补全客户端\u003C\u002Fstrong>：`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>：将 Chat 的顶层 `response_format` 替换为 Responses 的 `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\"`，适用于用户\u002F系统回合。\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 Completion 使用 `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 是文本、工具和流式的统一接口；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\"`，适用于系统\u002F用户回合。\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测试基础设施迁移（模拟、快照、断言）见 [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 模型代码路径已移除。\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- [ ] 测试文件中无 `rg \"ChatCompletionChunk|AsyncCompletions\\.create|chat\\.completions\"` 命中。\n- [ ] 测试文件中无 `rg \"_azure_ad_token_provider\"` 命中，断言更新为检查 `isinstance(client, AsyncOpenAI)` 或者 `base_url`。\n- [ ] 测试文件中无 `rg \"prompt_filter_results|content_filter_results\"` 命中，移除 Azure 特定过滤模拟。\n- [ ] 模拟夹具使用 `kwargs.get(\"input\")` 替代 `kwargs.get(\"messages\")`。\n- [ ] 快照\u002F黄金文件更新为 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` 事件，且 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- [测试迁移 — 模拟、快照、断言](.\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 聊天补全迁移到 Responses API\n\n> **权威指南 — 请严格遵循**\n>\n> 该技能将使用 Azure OpenAI 聊天补全的 Python 代码库\n> 迁移到统一的 Responses API。请严格遵循这些说明。\n> 不要即兴映射参数或发明 API 形态。\n\n---\n\n## 触发条件\n\n当用户希望时启用此技能：\n- 将 Python 应用从 Azure OpenAI 聊天补全迁移到 Responses API\n- 升级 Python OpenAI SDK 的用法至针对 Azure OpenAI 的最新 API 形态\n- 为需要 Azure 上 Responses 的 GPT-5 或更新模型准备 Python 代码\n- 从 `AzureOpenAI`\u002F`AsyncAzureOpenAI` 切换到带 v1 端点的标准 `OpenAI`\u002F`AsyncOpenAI` 客户端\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` 参数**：许多非推理模型不支持。仅当原代码已经存在 `reasoning` 时才迁移。\n> - **`seed` 参数**：Responses API 完全不支持，需从所有请求中移除。\n> - **通过 `text.format` 实现的结构化输出**：旧模型可能无法可靠强制执行 `strict: true` 的 JSON schema。\n> - \u003Cstrong>工具编排\u003C\u002Fstrong>：GPT-5+ 作为内部推理部分协调工具调用。旧模型使用 Responses 仍能工作，但缺少深度集成。\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`。设置较高值（4096+），因为推理用的标记计入限制。\n- **`reasoning_effort`**：如果应用使用 `reasoning_effort`（低\u002F中\u002F高），请保留—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`（不是 gpt-4.1+），主动告知用户：\n- 当前模型下迁移支持基础文本、聊天、流式和工具。\n- 新模型（`gpt-5.1`、`gpt-5.2`）在工具编排、结构化输出强制、推理和跨区域可用性方面表现更好。\n- 用户应考虑在适当时升级部署 — 这不影响迁移本身。\n\n不因模型版本阻止或拒绝迁移。该建议为信息性质。\n\n### GitHub 模型不支持 Responses API\n\n> **GitHub 模型（`models.github.ai`、`models.inference.ai.azure.com`）不支持 Responses API。**\n\n如果代码库有 GitHub 模型的代码路径（检查 `base_url` 是否指向 `models.github.ai` 或 `models.inference.ai.azure.com`），\u003Cstrong>迁移时请完全移除\u003C\u002Fstrong>。Responses API 需要 Azure OpenAI、OpenAI 或兼容的本地端点（如支持 Responses 的 Ollama）。\n\n扫描阶段操作：\n- 标记所有 GitHub 模型代码路径以备删除。\n\n---\n\n## 框架迁移\n\n许多应用使用 OpenAI 之上的高级框架。迁移它们时，需变更框架自身 API，而非仅底层 OpenAI 调用。\n\n### Microsoft 代理框架 (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` 使用聊天补全。升级至 `agent-framework-openai>=1.0.0`，默认使用 Responses API。\n\n其他接口不变 — `Agent` 和工具 API 保持一样。\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 是服务器端的 concern。** 迁移您的 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- 执行测试\u002F静态检查；修复迁移带来的轻微破坏。\n- 准备小型、易复审的变更集并提供最终带差异摘要（不提交）。\n\n---\n\n## 保护措施\n\n- 仅修改 git 工作区内的文件，绝不向外写文件。\n- 不保留向后兼容 shim；将代码迁移至新 API 形态。\n- 不留墓碑\u002F过渡注释或备份文件。\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基础设施及测试夹具中的 `AZURE_OPENAI_CLIENT_ID` 重命名为 `AZURE_CLIENT_ID`（遵守 Azure Identity 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 Identity 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- \u003Cstrong>聊天补全客户端\u003C\u002Fstrong>：`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>：将 Chat 的顶层 `response_format` 替换为 Responses 的 `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\"`，适用于用户\u002F系统回合。\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 Completion 使用 `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 是文本、工具和流式的统一接口；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\"`，适用于系统\u002F用户回合。\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测试基础设施迁移（模拟、快照、断言）见 [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 模型代码路径已移除。\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- [ ] 测试文件中无 `rg \"ChatCompletionChunk|AsyncCompletions\\.create|chat\\.completions\"` 命中。\n- [ ] 测试文件中无 `rg \"_azure_ad_token_provider\"` 命中，断言更新为检查 `isinstance(client, AsyncOpenAI)` 或者 `base_url`。\n- [ ] 测试文件中无 `rg \"prompt_filter_results|content_filter_results\"` 命中，移除 Azure 特定过滤模拟。\n- [ ] 模拟夹具使用 `kwargs.get(\"input\")` 替代 `kwargs.get(\"messages\")`。\n- [ ] 快照\u002F黄金文件更新为 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` 事件，且 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- [测试迁移 — 模拟、快照、断言](.\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-CN\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-CN\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","参考文档",28127,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-CN\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",7079,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-CN\u002F.agents\u002Fskills\u002Fazure-openai-to-responses\u002Freferences\u002Ftest-migration.md",{"path":59,"resourceType":50,"resourceTypeDesc":51,"sizeBytes":60,"sourceHtmlUrl":61},"references\u002Ftroubleshooting.md",14558,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fai-agents-for-beginners\u002Fblob\u002Fmain\u002Ftranslations\u002Fzh-CN\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]]