OpenAI、Azure OpenAI、Foundry Models:微软生成式 AI 入门课三条路线

2026-08-18

第一次打开 06-text-generation-apps/python/ 目录的人,八成会愣一下:同一个「文本生成应用」的课时里躺着 oai-app.pyaoai-app.pygithubmodels-app.py 三份文件,名字不同、代码也不是简单换个变量名那么回事。课程正文没有专门用一节来讲「你到底该配哪一条」,00-course-setup/03-providers.md 里也只是把 provider 列了一遍。这篇就把这三份文件摊开对齐,看清差异点落在哪几处,再倒推出选路径的依据。

先说一个会误导人的前缀

githubmodels- 这个前缀今天已经名不副实了,这一点不先讲清楚,后面全都会理解偏。

仓库在多处逐字写明:GitHub Models(连同它的 GITHUB_TOKEN 变量)将于 2026 年 7 月底退役,直接替代者是 Microsoft Foundry Models00-course-setup/02-setup-local.md 的「Add Your API Keys」一节、00-course-setup/03-providers.md(多处)、00-course-setup/README.md、根目录的 .env.copy 注释,以及 06-text-generation-apps/python/githubmodels-app.py 文件头的注释里,都写着这句话。按仓库文档给出的这个时间点,今天已经过去了。

对应的证据在 .env.copy 里也能直接看到:这个文件里已经没有 GITHUB_TOKEN 这个变量了,取而代之的是 AZURE_INFERENCE_ENDPOINTAZURE_INFERENCE_CREDENTIAL,注释写明「Get these from your Foundry project’s “Overview” page」。也就是说,变量早就换完了,只有文件名前缀还留在原地。03-providers.md 在列举作业文件名标签时的写法很能说明问题——它写的是「githubmodels - requires Microsoft Foundry Models endpoint, key」。

所以下文谈的第三条路线,准确的说法是 Microsoft Foundry Models(原 GitHub Models 路线),而不是「用 GitHub Models 跑起来」。

三套代码的差异点逐项对齐

先看第一条与第二条。oai-app.py 里客户端是这么建的:

client = OpenAI()
deployment = "gpt-5-mini"

aoai-app.py 用的是同一个 OpenAI 类,但构造参数完全不同:

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

deployment=os.environ['AZURE_OPENAI_DEPLOYMENT']

两处差异值得单独点出来。一是 OpenAI 那条路线里 OpenAI() 是空参构造,密钥靠 load_dotenv() 之后从环境里隐式读取;Azure 那条则把 key 显式传进去,并把 endpoint 拼上 /openai/v1/ 作为 base_url06-text-generation-apps/README.md 对这个后缀有一句解释:这个稳定的 v1 端点在 OpenAI 与 Azure OpenAI 上通用,不需要管理 api_versiongpt-5-mini 是仓库示例里用的模型名,不是你必须用的值)。

二是 deployment 这个变量的含义不一样。OpenAI 路线里它是模型名,写死在代码里;Azure 路线里它是你自己起的部署名,从 AZURE_OPENAI_DEPLOYMENT 读。这一层区别在报错时最容易咬人——名字对不上,问题不在密钥而在你 Foundry 门户里那个部署叫什么。

第三条路线则是另一套 SDK。githubmodels-app.py 的开头是:

from azure.ai.inference import ChatCompletionsClient
from azure.ai.inference.models import SystemMessage, UserMessage
from azure.core.credentials import AzureKeyCredential

token = os.environ["AZURE_INFERENCE_CREDENTIAL"]
endpoint = os.environ["AZURE_INFERENCE_ENDPOINT"]

client = ChatCompletionsClient(
    endpoint=endpoint,
    credential=AzureKeyCredential(token),
)

它换的不只是包名。前两条路线发请求走的是 Responses API:client.responses.create(model=..., input=prompt, store=False),结果从 response.output_text 取。第三条走的是 client.complete(messages=[...], model=model_name)messages 是 role/content 结构的列表,结果从 response.choices[0].message.content 取,并且原文件还加了一层判空:if response.choices and response.choices[0].message is not None

这不是写法偏好的问题。docs/ENHANCED_FEATURES_ROADMAP.md 里有一句说明:使用 azure-ai-inference / @azure-rest/ai-inference SDK(也就是 client.complete())的 Microsoft Foundry Models 示例仍在 Model Inference API 上,该 API 不支持 Responses API。这条差异往上传导,会牵出下面那个更实际的坑。

顺带一提,githubmodels-app.py 顶部导入了 SystemMessageUserMessage,但 messages 实际传的是普通 dict,这两个符号在该文件里没被用上;20-mistral/README.md21-meta/README.md 里的示例才用到了它们。

各自的前置门槛

把三条路线要准备的东西按「账号动作 + 环境变量 + 依赖包」三列对齐,门槛差得挺明显。

路线.env 里要填的变量需要的账号动作
OpenAI(oai-*OPENAI_API_KEY在 OpenAI 账号里创建 API key
Azure OpenAI(aoai-*AZURE_OPENAI_API_KEYAZURE_OPENAI_ENDPOINTAZURE_OPENAI_DEPLOYMENT(用到向量检索时还有 AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT有 Azure OpenAI 资源,并至少部署一个用于 chat completion 的模型
Microsoft Foundry Models(原 GitHub Models,githubmodels-*AZURE_INFERENCE_ENDPOINTAZURE_INFERENCE_CREDENTIAL建(或打开)一个 Foundry 项目并部署模型,从项目 Overview 页拿 endpoint 与 key

变量名与含义出自 00-course-setup/03-providers.md 的「Populate .env file」表格,账号侧步骤出自同一文件的配置小节。03-providers.md 的注册指引表里对 Azure 那一行还标了「Must Apply Ahead For Access」,06-text-generation-apps/README.md 也写了「At the time of writing, you need to apply for access to Azure OpenAI」——门槛差异主要在这儿,不在代码。

依赖这块有个不一致,值得单独提醒:06-text-generation-apps/python/requirements.txt 只列了 openaipython-dotenv 两个包,没有 azure-ai-inference;而仓库根目录的 requirements.txtpyproject.toml 里是有这个包的。只照课时目录那份清单装依赖,第三条路线那份代码缺的就是它。

采样参数这条岔路,才是真正的分界

06-text-generation-apps/README.md 里有一节专门讲这件事,标题是「Reasoning models don’t use temperature」。原文写明:Microsoft Foundry 上当前未废弃的模型是 reasoning 模型(GPT-5 家族、o 系列),它们不支持 temperaturetop_p,也不用 max_tokens(改用 max_output_tokens,把 temperature 传给 gpt-5-mini 会得到参数不支持的报错。README 给的替代做法是用提示工程与 reasoning 相关控制去引导输出。

.env.copy 里对应留了一条注释与一个变量:AZURE_INFERENCE_CHAT_MODEL,注释写明它用于放一个「支持 temperature/top_p 的非 reasoning 模型」,给温度示例用。06-text-generation-apps/python/githubmodels-assignment.ipynb 里的代码正是这么写的:

# temperature/top_p need a non-reasoning model (gpt-5 rejects them), so use a Llama model here.
model_name = os.environ.get("AZURE_INFERENCE_CHAT_MODEL", "Llama-3.3-70B-Instruct")

Llama-3.3-70B-Instruct 是仓库当前代码里写的默认回退值,随版本可能变动。同一个 notebook 里调用时传的是 temperaturetop_pmax_tokens;而 oai-app-recipe.pyaoai-app-recipe.py 走 Responses API,传的是 max_output_tokens同一个「限制输出长度」的意图,在两套 API 上参数名不同——这是三条路线里最容易复制粘贴出错的一处。

所以「怎么选」的分界线在这里就清楚了:你要跟着课程做 temperature 那几个练习,前两条路线配上仓库示例里的 reasoning 模型是走不通的,得走第三条路线并换一个支持采样控制的模型。

换个语言,可选的路线也跟着变

三条路线并列这件事只在 Python 目录里成立。同一课时下另外几个语言目录的情况是这样的:

  • 06-text-generation-apps/js-githubmodels/app.js 用的是 @azure-rest/ai-inferenceModelClient@azure/core-authAzureKeyCredential,读 AZURE_INFERENCE_CREDENTIALAZURE_INFERENCE_ENDPOINT,也就是 Foundry Models 那条路线;模型名同样从 AZURE_INFERENCE_CHAT_MODEL 取,回退值与 Python notebook 一致。
  • 06-text-generation-apps/typescript/recipe-app/src/main.ts 走的是另一条:它 import OpenAI from "openai",把 baseURL 拼成 ${endpoint.replace(/\/$/, '')}/openai/v1/,读的是 AZURE_OPENAI_ENDPOINTAZURE_OPENAI_API_KEYAZURE_OPENAI_DEPLOYMENT,属于 Azure OpenAI 路线。
  • 06-text-generation-apps/dotnet/ 下是一个 .dib 交互式 notebook 文件,文件名是 notebook-azure-openai.dib

所以「选哪条路线」这个问题,先要过一道语言的筛子:你打算用哪个语言跟着做,这一课里就未必三条都给了实现。

还有一处容易被当成等价物的地方:同一条路线下、名字只差一个前缀的两份文件,内容并不总是对称的。aoai-app-recipe.py 里额外写了 get_required_env() 做环境变量校验,还有 validate_number_input()validate_text_input() 两个函数,后者用 re.sub 过滤了一批字符并对长度设上限,文件注释把它标为防提示注入的处理;而 oai-app-recipe.py 里没有这些,用户输入直接插进 f-string 拼进 prompt。JS 那份也对两个环境变量做了显式 throw。要拿哪份当模板往自己项目里搬,这个差别比 provider 本身更值得先看一眼。

从你的处境倒推

  • 手上只有一把 OpenAI 的 key,想尽快把课时跑通:走 oai-*。它是三条里前置最少的,.env 只填一个变量,OpenAI() 空参构造。
  • 公司要求走 Azure 资源、有合规与区域要求:走 aoai-*。多出来的成本是要先有资源、先部署模型,还要记住 deployment 填的是部署名不是模型名。
  • 想在一个 endpoint 下试多家模型,或者要做 temperature 那组练习:走 githubmodels-*,但按 Microsoft Foundry Models 来配,别去找 GITHUB_TOKEN。代价是这条路线的 SDK 与前两条不通用,示例代码的调用形状与取结果方式都得跟着换。
  • 完全不想接云端03-providers.md 提到了 Foundry Local 与 Ollama 这两个本地选项,并指向第 19 课的实操示例。这条路线的示例代码不在本课时目录里,本文不展开。

一处仓库内部的不一致也顺手记下:.env.copy06-text-generation-apps/README.md.env 示例里都还列着 AZURE_OPENAI_API_VERSION,但在 translations/ 之外的 Python 示例代码里,没有一处读这个变量——走 /openai/v1/ 端点的写法按 README 的说法不需要 api_version。照抄 .env 模板不会出错,但别以为改这个值能影响示例行为。

Windows 与 macOS/Linux 的两处差异

06-text-generation-apps/README.md 的练习步骤给的是 python -m venv venvsource venv/bin/activate,并在紧跟的 NOTE 里写明:Windows 下改用 venv\Scripts\activate

00-course-setup/02-setup-local.md 创建 .env 那一步也分了两种写法,Unix 侧是 touch .env,Windows 侧是 echo . > .env。以上两处均为仓库文档原文中的命令,未经实测,以仓库最新内容为准。

最后

三条路线的差异不在「哪个更好」,而在边界画在哪:OpenAI 那条把配置压到最少,Azure 那条把控制权换成了部署管理的成本,Foundry Models 那条换来多模型目录与采样参数的可用性,但代价是换一套 SDK 与另一套 API 语义。上面所有差异点都能在文中给出的文件里逐行核到——课程持续更新,看到的写法与本文有出入时,以仓库最新内容为准。


本文依据 github.com/microsoft/generative-ai-for-beginners 仓库于 2026-08-18 的公开内容整理, 事实来自仓库内的课程正文与代码示例。我们没有跑过文中涉及的代码, 因此不涉及运行结果、耗时与生成质量的任何描述。 该课程持续更新,文中涉及的文件路径、依赖与接口写法随版本变动,请以仓库最新内容为准。 文中涉及的云端服务调用会产生费用并可能上传数据,请自行评估密钥与数据边界。

本文对照的是同一项目内的三条 provider 路线,依据均为上述仓库内容,不对三条路线做优劣排名, 选型结论只在仓库文档写明的能力边界内成立。

安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。