微软生成式 AI 入门课第 21 课 Meta 模型:调用路径与作业设计
打开 generative-ai-for-beginners 的 21-meta/python/githubmodels-assignment.ipynb,第一眼会有点错乱:文件名前缀写着 githubmodels,往下翻到第一个代码单元格,读的却是 AZURE_INFERENCE_CREDENTIAL 和 AZURE_INFERENCE_ENDPOINT,通篇找不到一个跟 GitHub Models 有关的变量。
这不是文件放错了。这一篇就从这个错位开始,把这一课的调用路径和「怎么算做完」拆一遍。
前缀名和实际接入目标已经脱节
00-course-setup/03-providers.md 里有一张 provider 标签表,写明作业文件名里的标签代表它需要哪套凭据。其中 githubmodels 这一行现在的原文是:需要 Microsoft Foundry Models 的 endpoint 与 key,并在同一行注明 GitHub Models 于 2026 年 7 月底退役。也就是说,仓库把文件名保留了下来,但标签背后指向的凭据已经整体换掉了。
同一件事在仓库里不止一处交代。00-course-setup/02-setup-local.md、00-course-setup/README.md、根目录的 .env.copy 都写了这条退役说明,.env.copy 里 Microsoft Foundry Models 那一节的注释原文把它描述为 GitHub Models 的替代者。今天是 2026-08-18,这个时间点已经过去了。更直接的证据是:.env.copy 里已经没有 GITHUB_TOKEN 这个变量,它列出来的是
AZURE_INFERENCE_ENDPOINT='<add your Microsoft Foundry project endpoint here, e.g. https://<resource-name>.services.ai.azure.com/models>'
AZURE_INFERENCE_CREDENTIAL='<add your Microsoft Foundry Models API key here>'
所以要跑这一课,你在 .env 里填的是 Foundry 项目 Overview 页面上的 endpoint 与 key。03-providers.md 的「Configure Microsoft Foundry Models: From Portal」一节把取值位置写明了:进 Foundry 项目,从模型目录部署一个模型,在项目 Overview 页复制 endpoint 与 API key,分别填进上面这两个变量。文件名里的 githubmodels 现在只剩「这个练习走 Foundry Models 这条统一入口」的意思,别再按字面理解。
课程里另外两条路线是 oai(OpenAI 的 key)和 aoai(Azure OpenAI 的 endpoint 与 key),第 21 课只提供了 Foundry Models 这一条,仓库里没有 oai- 或 aoai- 版本的对应文件。
两个代码单元格各自在做什么
notebook 里的依赖安装单独占一个单元格,而且原样重复了两次——两个调用单元格各自前面挂了一份,内容一模一样,就这两行:
%pip install azure-core
%pip install azure-ai-inference
这里要留个心眼。notebook 里不带版本约束,而 pyproject.toml 的 dependencies 写的是 azure-ai-inference>=1.0.0b1 —— 下限是一个 beta 版本;根目录 requirements.txt 里这一项则完全不带版本。三处口径不一致,你实际装到哪个版本取决于你是照哪个文件装的。这个 SDK 的下限标着 beta,接口签名随版本变动的可能性不能当成零。
第一个调用单元格是文本对话加原生工具调用:
import os
from azure.ai.inference import ChatCompletionsClient
from azure.ai.inference.models import AssistantMessage, SystemMessage, UserMessage
from azure.core.credentials import AzureKeyCredential
# Get these from your Microsoft Foundry project's "Overview" page
token = os.environ["AZURE_INFERENCE_CREDENTIAL"]
endpoint = os.environ["AZURE_INFERENCE_ENDPOINT"]
model_name = "Meta-Llama-3.1-405B-Instruct"
client = ChatCompletionsClient(
endpoint=endpoint,
credential=AzureKeyCredential(token),
)
model_name 这个值是仓库里给出的示例值,跟着 Foundry 目录里的部署名走,不是固定常量。
真正值得看的是工具是怎么声明的。这一课没有用 SDK 层面的工具参数,工具名直接写进了 system 文本里:
tool_prompt=f"""
<|begin_of_text|><|start_header_id|>system<|end_header_id|>
Environment: ipython
Tools: brave_search, wolfram_alpha
Cutting Knowledge Date: December 2023
Today Date: 23 July 2024
You are a helpful assistant<|eot_id|>
"""
messages = [
SystemMessage(content=tool_prompt),
UserMessage(content="What is the weather in Stockholm?"),
]
response = client.complete(messages=messages, model=model_name)
client.complete() 只传了 messages 和 model,没有传任何工具定义参数。Environment: ipython、Tools: 这些是写在 Llama 提示模板里的标记,<|begin_of_text|>、<|start_header_id|>、<|eot_id|> 也一样。课程 README 对这两个内置工具的说明是:brave_search 用来做网页搜索取实时信息,wolfram_alpha 用来做较复杂的数学计算,另外你也可以定义自己的工具让模型调用。
两个细节顺手记一下:tool_prompt 声明成了 f-string,但字符串里没有任何插值占位;AssistantMessage 被 import 进来却没有在这个单元格里用到。这两处都无伤大雅,指出来只是免得你照抄的时候,以为 f-string 或者那个 AssistantMessage 在这段里另有用途,反过来去猜自己是不是漏掉了什么。仓库里没有对这两处写任何说明。
第二个调用单元格换成多模态,模型名换成 Llama-3.2-90B-Vision-Instruct(同样是仓库里的示例值),import 也随之变长:
from azure.ai.inference.models import (
SystemMessage,
UserMessage,
TextContentItem,
ImageContentItem,
ImageUrl,
ImageDetailLevel,
)
差别在 UserMessage 的 content 上。文本那次传的是一个字符串,这次传的是一个列表,里面装 TextContentItem 和 ImageContentItem 两种条目:
UserMessage(
content=[
TextContentItem(text="What's in this image?"),
ImageContentItem(
image_url=ImageUrl.load(
image_file="sample.jpg",
image_format="jpg",
detail=ImageDetailLevel.LOW)
),
],
),
ImageUrl.load() 收的是三个参数:image_file、image_format、detail。image_file 给的是裸文件名 sample.jpg,而这张图就躺在 21-meta/python/ 目录里,和 notebook 同级。也就是说它按相对路径解析,解析结果取决于 kernel 的工作目录。仓库里没有对这个文件的定位方式再做说明,也没有交代把 notebook 换个目录打开会怎样。如果你在别处打开它而报找不到文件,把 image_file 换成绝对路径是通用的排查手段——这是通用做法,不是仓库里写的官方步骤。
这一课怎么算做完
先说仓库里白纸黑字给了依据的部分。
README 对第一个单元格写明了预期回应的形态:模型会以工具调用的形式回应,样子是 <|python_tag|>brave_search.call(query="Stockholm weather")。这句就是你判断第一个单元格是否走通的依据——看到这种形态的输出,说明模型识别出了 system 文本里声明的工具。
紧跟着的那条注记同样重要:这个例子只产生工具调用本身,不产生调用结果;想拿到真实结果,你得去 Brave API 注册一个免费账号,并自己把函数实现出来。所以「没有返回斯德哥尔摩的天气」不是这一课的失败,它本来就到不了那一步。
再说仓库里没有给的部分。第 21 课的 README 和这个 notebook 里都没有作业题面,也没有评分标准或检查清单。03-providers.md 对 assignment 的定义只到「按 provider 打标签的可运行练习文件」这一层,作业是可选的,缺凭据时相关练习会直接报错退出。所以这一课的「作业」实质就是:把凭据配上,把两个单元格逐个执行一遍,对照 README 里写明的输出形态自己判断。
CI 也帮不上忙。.github/workflows/code-quality.yml 里 Python 侧有两个 job:python-quality 强制跑 ruff check shared/ 和 black --check shared/,另有一步 ruff check . 覆盖全仓,但那一步标了 continue-on-error: true,工作流注释自述这是「advisory」,理由是课程示例刻意保持简单;python-tests 跑的是 pytest tests/,而 tests/ 目录下的测试文件是 test_api_utils.py、test_env_utils.py、test_input_validation.py(另有一个 conftest.py),测的是 shared/python/ 里的公共工具。任何一处都不会执行课程 notebook。也就是说,第 21 课这两个单元格能不能跑通,没有任何自动化会告诉你。
顺带一提,仓库里其实有 shared/python/env_utils.py,提供了 get_required_env() 和 validate_env_vars(),缺变量时会抛出带变量名和提示语的 ValueError。第 21 课的 notebook 没有用它,直接写的 os.environ["..."]。这两处摆在一起看:受测试保护的那套读取工具,和课程实际用的读取方式,是两条路。
采样参数在这一课的位置
这一课的两个单元格都没有传 temperature 或 top_p,但它和采样参数有一层关系值得说清。
06-text-generation-apps/README.md 写明了 2026 年的一个变化:Foundry 上当前未废弃的模型是 reasoning 模型(GPT-5 家族、o 系列),它们不支持 temperature 和 top_p,也不支持 max_tokens(改用 max_output_tokens),传了会收到参数不支持的报错。那一节给出的建议是,要试 temperature 示例就指向一个仍然支持采样控制的开放模型,并且原文点名了 Llama,走的正是 Foundry Models / Azure AI Inference 这条入口,「和 githubmodels-* 示例同一种方式」。
.env.copy 里也留了对应的口子:AZURE_INFERENCE_CHAT_MODEL 这一项的注释写明它要填一个支持 temperature/top_p 的非 reasoning 模型部署名,供 temperature 示例使用。换句话说,第 21 课这条 Meta 模型路线,同时也是课程里给采样参数示例准备的落脚点。
读这个文件时另外注意两处
一是 notebook 里的 markdown 单元格和章节 README 是同一段内容的两份副本,但两边措辞有出入——同一句话在 README 里是通顺的写法,在 notebook 副本里还带着笔误(比如把 model 写成 mode)。仓库里没有交代这两份为什么不一致,你只需要知道它们不是逐字相同的。要看正文,以 21-meta/README.md 为准,notebook 留着的是可运行的那两个单元格。
二是这几段代码会把你的 prompt 和 sample.jpg 发到云端 endpoint,会产生费用,也意味着数据离开了本机。跑之前先想清楚这两件事,密钥只放 .env(该文件已被 gitignore 覆盖),不要写进 notebook 单元格。
这个课程仓持续更新,上面提到的文件路径、变量名、依赖与接口写法都可能随版本变动,动手前请以仓库最新内容为准。
本文依据 github.com/microsoft/generative-ai-for-beginners 仓库于 2026-08-18 的公开内容整理,
事实来自仓库内的课程正文与代码示例。我们没有跑过文中涉及的代码,
因此不涉及运行结果、耗时与生成质量的任何描述。
该课程持续更新,文中涉及的文件路径、依赖与接口写法随版本变动,请以仓库最新内容为准。
文中涉及的云端服务调用会产生费用并可能上传数据,请自行评估密钥与数据边界。
安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。