現在隨手一搜,還是很容易搜到教你寫 AzureOpenAI(api_version="2024-xx-xx", ...) 的舊文章。但 2026 年開新專案,這已經不是首選寫法。今天要把 Day 3 骨架的第一個真實下游依賴接上 Azure OpenAI;在寫 code 之前,先回答 backend 工程師接任何下游服務都會問的問題:連線設定長什麼樣、哪些名字會進 config、哪些名字改了會弄壞系統?
讀完這篇,你能畫出 Azure OpenAI 的三層結構、分清楚哪些設定屬於 runtime、哪些屬於 provisioning、說出 quota 的完整 scope,並用現行的 v1 API 把設定接進骨架。
接一般的下游服務,你的 config 通常是一組 (endpoint, credential)。Azure OpenAI 多一層:
Subscription
└── Resource(例:aoai-<project>,kind=OpenAI)
├── endpoint:https://<name>.openai.azure.com/
├── region:japaneast(建立時決定,不可改)
└── Deployment(例:chat-mini)← 名字由你取
└── Model(例:gpt-5-mini, version 2025-08-07)
+ deployment type(GlobalStandard)+ 分配的 capacity(50K TPM)

model 參數填的是 deployment name,不是模型名。這是新手最常撞的一面牆。用 backend 的語言說:deployment name 是一個 CNAME。你的 code 指向 chat-mini,chat-mini 指向 gpt-5-mini 2025-08-07;哪天要換模型,建新 deployment 後改一行環境變數切換(比原地更新模型版本更安全的做法),application code 一行不動。
Azure 上你命名的東西很多(resource、resource group 也都是你取的名),但 deployment name 特別的地方在於:它是 application runtime 與模型版本之間唯一由你控制的間接層。名字應描述用途而非綁死型號,例如 chat-mini,而不是 gpt-5-mini-deploy。
但類比有失真的地方:換 CNAME 指向,下游行為不變;換 deployment 指向的模型,回應行為一定會變。間接層保護的是 Day 3 說的 transport contract(你的 code 不用改),不保護 semantic contract(答案的風格與品質)。換模型仍然是一次要驗證的變更,不是一次改 DNS。
Quota 的完整 scope 是 subscription × region × model × deployment type:每個訂閱在每個 region,針對特定模型與部署類型,各有一個可分配的 TPM(tokens per minute)總額度(查核 2026-07,quota 文件)。
而且它的運作方式是建立時分配,不是執行時分食:建 deployment 時你從這個 pool 劃出一份 capacity,成為該 deployment 自己的 TPM/RPM rate limit;所有 deployment 分配到的 TPM 總和不能超過額度。
所以選 region 不只是選 latency:是在選你拿得到多少額度、以及那個 region 能建哪些模型與部署類型(模型與 region 對照)。
本系列的 resource 建在 japaneast。這個訂閱在該 region 能建 gpt-5-mini 的 GlobalStandard deployment,額度也夠;本次從可用 quota 中分配 50K TPM 給 chat-mini,單人開發綽綽有餘。Region 在 resource 建立時就固定,之後要換等於重建,這是少數「第一天就要想清楚」的決定。
一個容易誤會的點:deployment type 是 GlobalStandard 時,推論會由 Azure 全球基礎設施動態路由,prompt 可能在任何 region 的機房處理(查核 2026-07,deployment types 文件)。
忍喵:「resource 在日本,推論不一定在日本——這句值得回頭再讀一次,尤其你家法務坐你隔壁的話。」
那 japaneast 到底保證了什麼?data at rest 留在該 geography、control plane 的位置,以及前面說的 quota 與模型可用性。不是「推論就在日本算」,也不能直接推論低 latency。
如果有單一 region 的資料處理要求,要用 Standard;要限制在 APAC 資料區域,看 DataZoneStandard。Region、deployment type、資料處理邊界——是三件不同的事。
建立資源用的是 repo 裡的 script(Azure CLI 兩條指令的封裝,含防呆;macOS + Azure CLI,2026-07 對 japaneast 實際執行過):
AZ_SUBSCRIPTION_ID=<your-sub> AZ_RESOURCE_GROUP=rg-<yours> \
AZ_LOCATION=japaneast AZ_OPENAI_NAME=aoai-<yours> \
./infra/scripts/create-openai.sh
兩件事值得說。其一,script 強制指定 subscription ID,不吃 az 的預設 context,多訂閱環境下這救過我一次。其二,每個 create script 都有配對的 delete-openai.sh,這是本系列的成本紀律(Day 1 說過的 ephemeral-by-default)。
不過 Standard / GlobalStandard 部署純 token 計費、沒有閒置成本(查核 2026-07,定價頁),所以這顆資源可以常駐:不呼叫就不花錢。建立前先設好 budget alert,我的順序是:預算警報 → 第一顆計費資源,永遠不要反過來。
寫這篇時最花時間的不是技術,是名詞。這個平台兩年內改了兩次名:Azure AI Studio → Azure AI Foundry(2024-12)→ Microsoft Foundry(2026-01 生效,官方文件)。現在的對照表(查核 2026-07):
| 你查到的舊名 | 現在的名字 | 對你的意義 |
|---|---|---|
| Azure OpenAI Service | Azure OpenAI in Microsoft Foundry Models | 服務本體沒變,standalone resource 照樣能開 |
| Azure AI Studio / AI Foundry portal | Microsoft Foundry portal(ai.azure.com) | 部署模型、看 quota 都在這裡 |
| Azure OpenAI Studio(oai.azure.com) | 導向 Foundry portal | 舊書籤會自動轉 |
實務建議:搜尋資料時把「Azure OpenAI」當關鍵字仍然有效(API 與 CLI 層面這個名字都還在,--kind OpenAI),但看到 portal 截圖跟你的畫面對不上時,先確認文章日期,再確認它講的是不是改名前的介面。
忍喵:「兩年改兩次名,查資料像在考古。關鍵字照用 Azure OpenAI,畫面對不上先看發文日期。」
過去接 Azure OpenAI 有兩個著名的摩擦點:要用 Azure 專屬的 AzureOpenAI client,以及每月更新的 api-version 字串(功能一更新就得追版號)。2025-08 起的 v1 API 讓兩者對新專案都不再必要(GA,查核 2026-07,官方遷移文件);舊寫法仍受支援,但沒有理由讓新 code 揹著它。
先用同步版 OpenAI client 看最小呼叫(本系列的 FastAPI adapter 用的是同介面的 AsyncOpenAI,避免在 async handler 裡阻塞 event loop):
import os
from openai import OpenAI # 不是 AzureOpenAI
client = OpenAI(
api_key=os.environ["AZURE_OPENAI_API_KEY"],
base_url="https://<your-resource>.openai.azure.com/openai/v1/",
)
response = client.chat.completions.create(
model="chat-mini", # deployment name,不是模型名
messages=[{"role": "user", "content": "ping"}],
)
三個表面差異:標準 OpenAI client 直接用、endpoint 後面接 /openai/v1/、不再需要 api-version。SDK client 與主要呼叫形狀更接近 public OpenAI API,但 Azure 特有的 deployment name、認證、quota、region/model 可用性、deployment type 與服務行為仍然存在,還是得靠 adapter 隔離。少掉 api-version,則確實讓 config 少一個會過期的欄位。
這也直接改了我們的骨架。Day 3 的 config.py 裡有一行 azure_openai_api_version: str = "2025-01-01-preview",寫 skeleton 時照舊慣例放的,今天的 milestone 把它拿掉:
class Settings(BaseSettings):
# ...
# v1 GA API (2025-08): plain OpenAI client against <endpoint>/openai/v1/, no api-version
azure_openai_endpoint: str | None = None
azure_openai_api_key: SecretStr | None = None
azure_openai_deployment_name: str | None = None
use_fake_llm: bool = Field(default=True)
新增的 key 欄位用 Pydantic 的 SecretStr:它的 repr 印出來是 **********,log 或錯誤訊息不小心把 settings 倒出來時,key 不會跟著出去。
adapter 端則是把 Day 3 的 fake 佔位換成真假雙軌:use_fake_llm=true(預設)走 fake;提供 endpoint、API key、deployment name,並關掉 flag,才建立真的 client。選擇發生在 composition point,handler 裡沒有任何 if use_fake。
完整 wrapper 雛形見 day-04 tag;真正的 chat API 合約是 Day 5 的事。
順帶一提:官方現在推薦 Azure OpenAI 模型優先用 Responses API(client.responses.create),chat completions 仍完整支援。要選哪個當本系列的 API 基礎,牽涉到 streaming 與工具呼叫的合約設計,留到 Day 5 一起決定。
model 參數填模型名」:填的是 deployment name。錯了會拿到 404 DeploymentNotFound,而不是一個好懂的錯誤訊息。GlobalStandard 與 Standard 也不是同一份 quota。AzureOpenAI client + api-version」:v1 GA 之後標準 OpenAI client 即可。看到教學在傳 api_version 參數,先看發文日期。GlobalStandard 的推論可能在任何 Azure region 處理;region 保證的是 data at rest 與 control plane。有資料處理位置的要求,要選對 deployment type,不是只選對 region。今天把 runtime 與 provisioning 的設定邊界弄清楚了:application runtime 需要的是 endpoint、credential、deployment name 三個值;region、model version、deployment type 與 capacity 屬於建立資源時的 control-plane 設定,不進 application code。
deployment name 是 runtime 與模型版本之間由你控制的間接層;quota 的 scope 是 subscription × region × model × deployment type;v1 API 讓 api-version 從 config 消失。
骨架的 config.py 與 .env.example 已更新成 v1 風格,wrapper 雛形就位,完整程式碼在 day-04 tag,該 tag 上 CI 是綠的。
明天(Day 5)開始設計第一個 chat API——不是把 SDK 包一層轉手就好:request/response schema、timeout、retry、error boundary,Day 3 鎖下的 error envelope 終於要接到真的錯誤上了。
(本篇新增雲端資源:Azure OpenAI resource + gpt-5-mini deployment,GlobalStandard 純 token 計費、無閒置成本;建立前已設 US$20 budget alert。)
| 工程需求 | Azure / Microsoft 對應服務 | 本篇怎麼用 |
|---|---|---|
| LLM 推論的資源與額度管理 | Azure OpenAI in Microsoft Foundry Models | 建立 resource(japaneast)與 deployment(gpt-5-mini, GlobalStandard,分配 50K TPM),以 v1 API 接進 FastAPI 骨架的 config |
本文由作者規劃與撰寫,AI(Claude)協助草稿整理與程式碼驗證;技術內容與觀點由作者確認並負責。