這兩年如果你有同時碰 OpenAI API 與 Azure OpenAI Service,你一定會覺得同樣是呼叫 LLM 的 API,明明都是一樣的服務,但是 Azure OpenAI 的 API 設計就是特別難用,要先部署模型、呼叫路徑要帶 deployment name、每個請求還要綁 ?api-version=YYYY-MM-DD 查詢字串 (Query String)。這套設計不是沒有理由,但對應用開發者來說,確實也帶來不少心智負擔。

到了 2025 年下半年,Azure OpenAI 開始推進統一的 v1 介面,逐步把使用體驗往 OpenAI 官方 API 靠攏。這篇文章就來把這段演進史講清楚:為什麼以前是部署導向?開發者痛在哪裡?v1 到底解了哪些問題,又還留下了哪些現實限制?
TL;DR
- 舊版 Azure OpenAI API 以「部署」為核心,是為了對齊 Azure 的資源治理、配額配置、資料落地與 SLA 管理需求。
- 這個設計在企業治理上合理,但應用開發者要承受 API 版本頻繁演進、模型名稱與部署名稱差異、跨 OpenAI/Azure 切換成本高等痛點。
- 新一代
v1 API 把介面統一到 .../openai/v1/...,且 GA 能力不再需要每月追 api-version,大幅降低整合複雜度。
- 但
v1 並不是「所有能力一夜完成」,仍有部分功能採 preview 路徑或 preview header,遷移策略仍然要分階段做。
為什麼當年一定要「部署導向」?
Azure OpenAI 一開始的目標就不只是「把模型 API 包一層」,而是要把它放進 Azure 的企業治理體系裡。
1) 把模型能力變成可治理的 Azure 資源
Azure OpenAI 的資源模型本來就分成 control plane 與 data plane。你先在 control plane 建立資源、建立 deployment,然後在 data plane 呼叫推論 API。
這代表「模型可用性」是透過 deployment 管理,而不是直接拿模型名稱就呼叫。也因此,舊版 API 路徑自然就長成這樣:
POST https://{resource}.openai.azure.com/openai/deployments/{deployment-id}/chat/completions?api-version=2024-10-21
這樣的好處是,治理與推論被明確分層:誰可以部署、部署到哪個區域、配多少能力,都能在 Azure 管理面統一控管。
2) 配額與效能模型本來就是「跟 deployment 綁在一起」
Azure OpenAI 的 quota 是以「每訂用帳戶 / 每區域 / 每模型或部署型別」切分,再把 TPM 配給各 deployment。部署建立時配多少 TPM,就直接映射到該 deployment 的速率上限。
換句話說,deployment 不是純名稱別名,而是容量與限流的落點。如果沒有 deployment 這層,企業端就很難做精細化流量與成本治理。
3) 資料處理位置、法遵與 SLA 需求,需要 deployment type 來承載
Azure OpenAI 有 Global、Data Zone、Regional、Provisioned 等 deployment type。你可以按法遵與延遲需求,決定資料處理區域與計費 / 吞吐模式。
這也是為什麼早期設計不是「一支 endpoint 打天下」:在 Azure 的世界裡,部署配置本身就是產品能力的一部分。
這套設計的代價:開發者到底痛在哪?
企業治理視角很合理,但應用開發者會遇到幾個非常真實的痛點。
痛點 1:每月追 api-version,維護成本偏高
過去 Azure OpenAI 的新能力常常伴隨新日期版 API。你要吃新功能,就得更新程式碼、環境變數、甚至 SDK 版本。
這種節奏在 PoC 還能接受,但到多服務、多環境的大型系統,維運壓力會明顯放大。
痛點 2:OpenAI 與 Azure OpenAI 之間切換不夠平滑
以前很多團隊會同時維護 OpenAI 與 Azure OpenAI 路徑,常見結果是 codebase 內有兩套初始化與呼叫流程。
官方文件也直接點出,舊模式下從 OpenAI 遷移到 Azure OpenAI (或反向) 有 Azure-specific client 與路徑差異帶來的額外負擔。
痛點 3:model 參數看起來像模型名,實際上要填 deployment name
這是最多人踩的坑。OpenAI 直接用模型名;Azure OpenAI 則要求你在 API 呼叫時使用 deployment name (即使參數名稱叫 model)。
對新手非常不直覺,也很容易變成 404 / Not Found 類型問題。
演進轉折:從日期版 API 到統一 v1
到了 2025 年下半年,Azure OpenAI 開始推進下一代 v1 API。官方定位很明確:降低版本追逐成本、降低跨 OpenAI/Azure 的切換摩擦。
v1 帶來的核心改變
-
統一路徑:改成 .../openai/v1/...
例如以下端點網址:
https://resource-name.cognitiveservices.azure.com/openai/v1/chat/completions
-
GA 能力不再強迫每月換 api-version:v1 GA 呼叫可不再依賴日期版版本切換。
早期的端點網址長這樣,這個 api-version 參數用來指定 API 版本:
https://resource-name.cognitiveservices.azure.com/openai/deployments/gpt-4.1/chat/completions?api-version=2024-05-01-preview
-
OpenAI client 對齊:可以直接使用 OpenAI() client,base_url 指到 Azure 的 .../openai/v1/。
-
認證體驗更一致:可用 API Key,也可用 Entra ID token provider。
典型寫法會像這樣:
from openai import OpenAI
client = OpenAI(
api_key="AZURE_OPENAI_API_KEY",
base_url="https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/"
)
API 呼叫範例:前後對照
1) REST Chat Completions (HTTP)
Before (舊版部署導向 + 日期版 API)
# 舊版:路徑綁 deployment,且每次呼叫都要帶 api-version
POST https://{resource}.openai.azure.com/openai/deployments/gpt-4o-prod/chat/completions?api-version=2024-10-21
Content-Type: application/json
api-key: {AZURE_OPENAI_API_KEY}
{
"messages": [
{ "role": "user", "content": "請用一句話介紹 v1 API。" }
]
}
After (v1 統一介面)
# v1:改用統一 /openai/v1 路徑,model 欄位填 deployment name
POST https://{resource}.openai.azure.com/openai/v1/chat/completions
Content-Type: application/json
api-key: {AZURE_OPENAI_API_KEY}
{
"model": "gpt-4o-prod",
"messages": [
{ "role": "user", "content": "請用一句話介紹 v1 API。" }
]
}
💡 重點:路徑與版本策略是最大差異;治理上仍然是「先部署、再呼叫」。
2) Python SDK 初始化 (AzureOpenAI → OpenAI)
Before (舊版)
import os
from openai import AzureOpenAI
# 舊版:Azure 專屬 client,且通常需要明確指定 api_version
client = AzureOpenAI(
api_key=os.getenv("AZURE_OPENAI_API_KEY"),
azure_endpoint="https://YOUR-RESOURCE-NAME.openai.azure.com/",
api_version="2024-10-21",
)
resp = client.chat.completions.create(
model="gpt-4o-prod", # 注意:在 Azure 這裡填的是 deployment name
messages=[{"role": "user", "content": "哈囉"}],
)
After (v1)
import os
from openai import OpenAI
# v1:直接用 OpenAI client,改用 base_url 指向 Azure v1 端點
client = OpenAI(
api_key=os.getenv("AZURE_OPENAI_API_KEY"),
base_url="https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/",
)
resp = client.chat.completions.create(
model="gpt-4o-prod", # 在 Azure 仍是 deployment name 的語意
messages=[{"role": "user", "content": "哈囉"}],
)
💡 重點:初始化流程更接近 OpenAI,但 model 參數在 Azure 端仍需對應既有 deployment 規劃。
3) C# (Legacy vs v1)
Before (Legacy)
using System.Text;
using System.Text.Json;
var resource = Environment.GetEnvironmentVariable("AZURE_OPENAI_RESOURCE");
var apiKey = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY");
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("api-key", apiKey);
var legacyUrl = $"https://{resource}.openai.azure.com/openai/deployments/gpt-4o-prod/chat/completions?api-version=2024-10-21";
var legacyBody = JsonSerializer.Serialize(new
{
messages = new[]
{
new { role = "user", content = "請用一句話介紹 v1 API。" }
}
});
var legacyResp = await http.PostAsync(
legacyUrl,
new StringContent(legacyBody, Encoding.UTF8, "application/json"));
After (v1)
using System.Text;
using System.Text.Json;
var resource = Environment.GetEnvironmentVariable("AZURE_OPENAI_RESOURCE");
var apiKey = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY");
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("api-key", apiKey);
var v1Url = $"https://{resource}.openai.azure.com/openai/v1/chat/completions";
var v1Body = JsonSerializer.Serialize(new
{
model = "gpt-4o-prod",
messages = new[]
{
new { role = "user", content = "請用一句話介紹 v1 API。" }
}
});
var v1Resp = await http.PostAsync(
v1Url,
new StringContent(v1Body, Encoding.UTF8, "application/json"));
💡 重點:C# 呼叫邏輯幾乎不變,主要是把 URL 換成 .../openai/v1/... 並在 payload 補上 model。這樣可以把舊有 deployment-path 的耦合降到最低。
4) TypeScript (Legacy vs v1)
Before (Legacy)
const resource = process.env.AZURE_OPENAI_RESOURCE!;
const apiKey = process.env.AZURE_OPENAI_API_KEY!;
const legacyUrl =
`https://${resource}.openai.azure.com/openai/deployments/gpt-4o-prod/chat/completions?api-version=2024-10-21`;
const legacyResp = await fetch(legacyUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"api-key": apiKey,
},
body: JSON.stringify({
messages: [{ role: "user", content: "請用一句話介紹 v1 API。" }],
}),
});
After (v1)
const resource = process.env.AZURE_OPENAI_RESOURCE!;
const apiKey = process.env.AZURE_OPENAI_API_KEY!;
const v1Url =
`https://${resource}.openai.azure.com/openai/v1/chat/completions`;
const v1Resp = await fetch(v1Url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"api-key": apiKey,
},
body: JSON.stringify({
model: "gpt-4o-prod",
messages: [{ role: "user", content: "請用一句話介紹 v1 API。" }],
}),
});
💡 重點:TypeScript 端遷移也幾乎是「換路徑 + 補 model」,其餘 middleware、重試與 logging 大多可沿用。若你有前後端共用 SDK,這種改法也更容易統一抽象層。
差異比較表 (舊版 vs v1)
| 比較面向 |
舊版 (部署導向 + 日期版 API) |
v1 (統一介面) |
實務影響 |
| Endpoint 路徑 |
/openai/deployments/{deployment}/... |
/openai/v1/... |
呼叫 URL 更一致,跨 OpenAI/Azure 抽換成本下降 |
| 版本策略 |
幾乎每波新能力都要指定 / 更新 api-version=YYYY-MM-DD |
GA 能力走 v1 穩定介面 (部分功能仍另走 preview) |
降低版本追逐與多環境同步更新壓力 |
| Client 初始化 |
常見 AzureOpenAI(azure_endpoint, api_version, ...) |
可用 OpenAI(base_url=.../openai/v1/) |
SDK 初始化與共用元件更容易標準化 |
| Model/Deployment 命名語意 |
model 參數實際上是 deployment name,且常與路徑 deployment 雙重綁定 |
model 參數在 Azure 仍對應 deployment name,但路徑語意更一致 |
可讀性提升,但命名規範仍要管好避免誤用 |
| Preview 功能啟用方式 |
多半透過特定日期版 API 或獨立 preview 路徑 |
可能透過 preview header 或 preview path (依功能而定) |
需把 GA/Preview 呼叫明確隔離,避免互相汙染 |
| 維護成本 |
版本、端點、SDK 參數差異多,跨平台整合成本高 |
介面收斂、抽象層更單純 |
長期維運與遷移成本可明顯下降 |
那是不是從此天下太平?其實還有幾個現實
1) v1 是演進,不是一次性重寫
官方也明講:v1 初始 GA 階段只涵蓋部分 inference / authoring 能力,其餘能力持續補齊。
所以你會看到有些功能走 GA 路徑、有些功能仍在 preview,甚至需要 preview header 或 preview path。
2) 部署概念沒有消失,只是體感變好
即便在 v1,Azure OpenAI 仍要求你先有 deployment,且 model 參數在 Azure 側仍是 deployment name。
也就是說,治理模型還在,但 API 體驗變得更接近 OpenAI。這是一種工程折衷,不是完全捨棄 Azure 的管理哲學。
3) 舊版 API 仍會存在一段時間
現場實務通常是「新服務優先 v1,舊服務分批遷移」。只要你還有既有相依 (例如特定 preview 能力或舊 SDK),短期內雙軌共存是常態。
我會怎麼建議你遷移?
如果你現在手上有既有系統,我會建議這樣走:
- 先把 deployment naming 規範化 (避免
model / deployment 混淆)。
- 把 endpoint 與認證抽象成可切換配置 (OpenAI / Azure 共用一層 adapter)。
- 新功能一律優先走
v1,舊功能再逐步搬遷。
- 對 preview 功能做顯式隔離 (header/path/feature flag 不要跟 GA 混在一起)。
- 建立回歸測試基線 (token 用量、延遲、錯誤碼、輸出格式一致性) 再切流量。
總結
回頭看這段演進,其實很有意思:
- 舊版部署導向 API 解決的是企業治理、配額與法遵問題;
- 新一代 v1 API 解決的是開發者體驗與跨平台整合效率問題。
這不是誰對誰錯,而是產品成熟度的自然路徑:先把「可管、可控、可落地」做好,再把「好用、好遷移、好維護」拉上來。
如果你問我一句話結論:Azure OpenAI 沒有放棄 deployment-centric 的治理核心,但在 v1 這一波,終於把開發者體驗補到比較像現代 API 平台該有的樣子了。
相關連結