.agents/skills/:微软 AI Agent 入门课怎么固化一套工作流
有一类活儿你大概也遇到过:同一套操作步骤,每开一个新会话就得重新对 agent 交代一遍。「先检查 .env 里有没有 endpoint,再 az login,然后跑那个 PowerShell 脚本,失败了先看是不是 429」——讲第三遍的时候你就会想,这段东西为什么不能存成文件。
ai-agents-for-beginners 这个课程仓里就有一个存这种东西的地方:.agents/skills/。它跟课程正文是两套材料,课程正文是给人看的,这个目录是给 agent 看的。下面沿着这几个文件走一遍,看它到底约定了什么。
一个 skill 在磁盘上长什么样
最小形态就是一个目录加一个文件:目录名即 skill 名,目录里放一份 SKILL.md。deploying-scalable-agents/ 和 local-ai-agents/ 就是这个最小形态,各自只有一份 SKILL.md。
复杂一点的会往目录里加东西。azure-openai-to-responses/ 除了 SKILL.md 还有 references/(三份 markdown)和 scripts/(一个 detect_legacy.py)。jupyter-notebook/ 铺得最开,除了 references/ 和 scripts/,还有 assets/(两份模板 .ipynb 加两个图标)、agents/(一份 openai.yaml),以及一份单独的 LICENSE.txt。
SKILL.md 开头是 YAML frontmatter。字段不多,name 和 description 是共有的,另有几份(local-ai-agents、deploying-scalable-agents、azure-openai-to-responses)还带一个 license: MIT,其余几份没有这个字段——仓库里没有说明这个差别是怎么来的。正文就是普通 markdown,没有什么特殊语法。
链接写法是这里一个值得注意的细节。skill 内部指向自己的材料用 ./references/cheat-sheet.md 这种相对路径;指回课程本体则一路 ../ 爬出去,比如 local-ai-agents/SKILL.md 里指向课程的写法是:
> Companion skill for [Lesson 17 – Creating Local AI Agents](../../../17-creating-local-ai-agents/README.md).
三层 ../ 正好从 .agents/skills/local-ai-agents/ 回到仓库根。也就是说,这些 skill 默认自己是躺在仓库里的,不是独立分发的包。
触发靠的是 frontmatter 里那段 description
skill 什么时候该被用起来,仓库里的答案落在 description 上。写法有两种风格。
一种是自然语言。testing-course-samples/SKILL.md 的 description 直接以 “Use when asked to validate, test, smoke-test, or run the course’s notebook and code samples…” 开头,后面把这份 skill 覆盖的范围逐项摊开——环境准备、runner 脚本、PASS/FAIL 结果怎么读、哪些课需要额外资源。
另一种是关键词清单,而且成对出现。local-ai-agents/SKILL.md 的 description 里有这么两段:
USE FOR: run an agent locally, offline agent, on-device agent, Foundry Local,
Qwen function calling, local tool calling, local RAG, Chroma vector database,
local MCP server, privacy-preserving agent, hybrid local and cloud agent,
small language model agent, engineering assistant on my machine.
DO NOT USE FOR: deploying agents to the cloud at scale (use deploying-scalable-agents /
Lesson 16), building your first agent concept (Lesson 01), Foundry (cloud) hosted
agents, GPU cluster / server-side inference provisioning.
DO NOT USE FOR 这半段里点了兄弟 skill 的名字。反过来看 deploying-scalable-agents 的 description,它的 DO NOT USE FOR 也写着 “running agents locally on-device (use local-ai-agents / Lesson 17)“。两份文件互相把对方的地盘划出来,形成一条明确的分流规则,而不是各写各的。azure-openai-to-responses 的 DO NOT USE FOR 更狠,把语言边界也写进去了:Node/TypeScript/C#/Java/Go 的迁移不归它管,这份 skill 只管 Python。
除了 frontmatter,正文里通常还有一个专讲触发场景的小节,把「学习者想干什么」再列一遍——local-ai-agents、deploying-scalable-agents、azure-openai-to-responses 用的标题是 ## Triggers,jupyter-notebook 和 testing-course-samples 用的是 ## When to use。这是白纸黑字的两处:一处在 frontmatter 里,一处在正文里,内容重叠但不完全相同。testing-course-samples 正文里那条否定说明就没出现在 frontmatter 中——它写明这份 skill 不用于 AI Smoke Test 的 GitHub Action,那个是验证已部署的 hosted agent 的,指向 tests/README.md。
还有第三条触发路径,只有 jupyter-notebook/ 这一份有。它的 agents/openai.yaml 是界面级元数据:
interface:
display_name: "Jupyter Notebooks"
short_description: "Create Jupyter notebooks for experiments and tutorials"
icon_small: "./assets/jupyter-small.svg"
icon_large: "./assets/jupyter.png"
default_prompt: "Create a Jupyter notebook for this task with clear sections, runnable cells, and concise takeaways."
这几个键写的是显示名、一句话说明、两个图标路径,外加一条 default_prompt。仓库里没有进一步说明这份 yaml 由哪个工具读取、default_prompt 具体在什么时机被填进对话框,所以这里只照抄字段本身。其余几份 skill 目录下没有 agents/ 这一层。
references 到底分走了什么
azure-openai-to-responses 是拆得最彻底的一份。它的 SKILL.md 里留下的是决策类内容:先做兼容性 smoke test,再看框架层怎么改,然后是 Step 0 到 Step 2 的迁移动作,最后是一串 checkbox 形式的验收门。真正的长材料都被推出去了:
references/cheat-sheet.md—— before/after 完整代码,从客户端构造、流式、多轮到工具定义references/test-migration.md—— mock、snapshot、断言这一层怎么跟着改references/troubleshooting.md—— 400 报错排查、迁移风险表、gotchas
指路方式是两道:正文里改到哪一步就在那一步末尾插一句 “For complete before/after code examples, see cheat-sheet.md”,同时文末还有一个 ## References 小节把它们汇总一遍。
jupyter-notebook 的拆法不一样。留在 SKILL.md 里的是决策树——请求是探索性的就走 experiment,是教学性的就走 tutorial——以及工作流的六个步骤。四份 reference 各管一段:experiment-patterns.md 和 tutorial-patterns.md 是两条路各自的结构模板,notebook-structure.md 讲 .ipynb 的 JSON 形状和安全编辑规则(比如 code cell 脚手架阶段 execution_count 置 null、outputs 置空数组),quality-checklist.md 是交付前的最终检查表。文末的 ## Reference map 一行一份说明什么时候读哪个。
而 deploying-scalable-agents 和 local-ai-agents 干脆没有 references/。它们把长材料的位置指回课程本体:SKILL.md 里只留心智模型和要点,具体代码让 agent 去读 16-deploying-scalable-agents/code_samples/16-python-agent-framework.ipynb 或 17-creating-local-ai-agents/code_samples/17-local-agent-foundry-local.ipynb。所以 references 并不是必须品,它解决的是「这份材料在仓库里没有别的落脚点」的情况。
scripts/ 是第三类附件。azure-openai-to-responses/scripts/detect_legacy.py 的 docstring 里写明了退出码语义:没扫到遗留写法退 0,扫到了退 1。它内部维护一张 PATTERNS 列表,每条是 (regex_pattern, description, category) 三元组,category 分成 api-call、client、response-shape、parameter、env-var、github-models、framework、test 这几类。把判定收敛成一个退出码,是让流水线能直接消费它的通用做法——这一句是通用工程经验,不是仓库里的说法。仓库自己写明的是它的边界,SKILL.md 的 Guardrails 一节:Do not run `git add`/`git commit`/`git push`; produce working-tree edits only.——只改工作区,不碰 git。
被固化下来的不只是步骤,还有怎么交差
testing-course-samples/SKILL.md 里有一段容易被略过的内容,是结果怎么读、怎么报。
结果读法它给了判据:PASS 表示 notebook 从头跑到尾没有 cell 报错;FAIL 会打出第一行 *Error / *Exception,完整栈要去输出目录里对应的 log_*.txt 里翻。还有一条是关于卡死的——-Timeout 是按 cell 计的,所以一个等人输入的 human-in-the-loop cell 会以 StdinNotImplementedError 的形式浮出来,而不是让整轮验证挂在那里。
接着是一张「哪些课注定会失败」的表,把环境缺口先摘出去:Lesson 05 的 Agentic RAG 要 Azure AI Search,文档里注明它有一条 in-memory 的回退路径;Lesson 11 要 GitHub MCP server 加一个 PAT;Lesson 13 的 memory 要 cognee 配好模型 provider;Lesson 15 的 browser-use 要先装 Playwright 的浏览器;Lesson 17 要 Foundry Local 运行时和一个下载好的 Qwen 模型,这一课是完全在设备上跑的。文件名带 *-dotnet-* 的 notebook 默认被排除在外,要跑得加 -IncludeDotnet。
最后是 ## Reporting back 一节,直接规定了汇报格式:按 lesson 分组给 PASS/FAIL 表,把真正的回归(代码或配置的 bug)与环境缺口(缺 Search、缺 Foundry Local、缺 PAT)分开写,每个真实失败都要引用对应的 log_*.txt。
这一段其实才是「工作流固化成文件」这件事里最省事的部分。步骤写下来只是让 agent 少问几句,而输出格式写下来,才让每次回来的东西是同一个形状,能直接往上一层塞。
两处对不上的地方
第一处在路径上。azure-openai-to-responses/SKILL.md 的 Step 1 里给的调用方式是 python skills/azure-openai-to-responses/scripts/detect_legacy.py .,而这份文件在课程仓里的实际位置是 .agents/skills/azure-openai-to-responses/scripts/detect_legacy.py,开头少了 .agents/。CHANGELOG 写明这份 skill 是从 Azure-Samples/azure-openai-to-responses 装进来的,包括它的 references 和扫描脚本。两处摆在一起就是这样,照着 SKILL.md 里那行敲会找不到文件。
第二处在同步上,而且是仓库自己交代的。CHANGELOG 2026-07-14 那条记录说,课程把模型引用整体换掉的时候,azure-openai-to-responses skill 里的 capability notes 是有意保留未改的(同时保留的还有 vendored 的第三方文件和历史 GitHub Models 文本)。所以这份 skill 里关于模型能力的描述,跟课程正文不在同一个更新节奏上,读的时候心里要有数。
Windows 这边
testing-course-samples 是这几份里对 Windows 最友好的,因为 runner 本身就是 PowerShell 脚本:
# All Python notebooks (skips .NET, .venv, site-packages, translations, skill assets)
pwsh scripts/validate-notebooks.ps1
# A single lesson, with a longer per-cell timeout
pwsh scripts/validate-notebooks.ps1 -Filter '08-*' -Timeout 600
# Just list what would run (no execution)
pwsh scripts/validate-notebooks.ps1 -List
这三行原样抄自 testing-course-samples/SKILL.md,其中 '08-*' 与 600 只是仓库里给出的示例值,不是推荐配置。
SKILL.md 还专门给了一条 Windows 上的坑:如果 python 不在 PATH 上(比如被 Windows Store 的别名占了),用 -Python 显式指定解释器。输出写到 $env:TEMP\aiab-nbval,退出码是失败数。文档还写明瞬时失败会自动重试,-Retries 与 -RetryDelaySeconds 有各自的默认值——这是仓库当前文档里的默认值,随版本可能变动。
反过来 jupyter-notebook/SKILL.md 的「Skill path (set once)」用的是 export CODEX_HOME=... 这种 POSIX 写法,PowerShell 下不能直接用;仓库里我们没有找到对应的 PowerShell 写法。这份 skill 说明用户级安装位置默认在 $CODEX_HOME/skills(即 ~/.codex/skills),跟课程仓里的 .agents/skills/ 不是同一个地方——同一份 skill 放在哪儿,脚本路径就跟着变,前面那处路径对不上多半也是这个原因。
想照着做的话
把上面这些拼起来,可以抄的约定其实就几条:一个目录一份 SKILL.md;frontmatter 里的 description 是唯一负责「什么时候用我」的地方,正面关键词和 DO NOT USE FOR 一起写,边界指向兄弟 skill;长代码、排错表、检查清单外置到 references/,主文件只留决策和验收;能脚本化的判定写成带退出码的脚本放 scripts/;正文里明确写清哪些事不许做(比如不碰 git)。
需要提醒的是,这套目录约定是这个仓库当前的写法,不同 agent 工具对 skill 的发现规则并不统一,.agents/skills/ 能不能被你手上的工具读到要看工具自己的文档。该项目持续更新,文中涉及的文件路径、字段名与默认值都可能随版本变动,以仓库最新内容为准。
本文依据 github.com/microsoft/ai-agents-for-beginners 仓库于 2026-08-18 的公开内容整理,
事实来自仓库内的课程正文与代码示例。我们没有跑过文中涉及的代码,
因此不涉及运行结果、耗时与 Agent 实际表现的任何描述。
该课程持续更新,文中涉及的文件路径、依赖与接口写法随版本变动,请以仓库最新内容为准。
文中涉及的云端服务调用会产生费用并可能上传数据,请自行评估密钥与数据边界。
文中涉及在本机执行仓库自带的脚本,并会读取 .env 与云端凭据。安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。
许可条款请以仓库 LICENSE 原文与你所在组织的要求为准,本文不构成法律意见。