微软 AI Agent 入门课怎么定义 Agent:第 1 课划的最小构成

2026-08-18

「Agent」这个词现在被用得很松,接了个模型 API 的对话框也叫 Agent。ai-agents-for-beginners 这门课的第 1 课(01-intro-to-ai-agents/README.md)没有在这上面绕,它把 Agent 拆成能数得清的部件,然后配了一份能对上号的代码。这篇就沿着那份代码走一遍:从环境变量到 tools=[...],看看分界线到底落在哪一行。

第 1 课的定义拆成了三个部件

README 的 Defining AI Agents and Types of AI Agents 一节先强调 Agent 是一个 system 而不是单个东西,然后给出了每个 agent 都有的三个部件:Environment(agent 工作的场地)、Sensors(读取环境当前状态的方式)、Actuators(对环境采取动作的方式)。课程用一个订旅行的场景把这三个词坐实:订票平台是 environment,查酒店余量和机票价是 sensor,订房、发确认、取消预订是 actuator。

在这三个部件之外,README 又补了几层:LLM 负责理解自然语言、对上下文做推理、把含糊的请求变成具体计划;Perform Actions 那一条写得很直白——没有 agent 系统时 LLM 只是生成文本,在 agent 系统里它才能真的去执行一步(查库、调 API、发消息);Access to Tools 说 agent 能用什么工具取决于它跑在什么环境里、以及开发者选择给了它什么;最后是短期记忆(当前会话)与长期记忆(客户库、历史交互)。

这些概念本身不新鲜,值钱的是它们和代码能一一对上。所以别停在 README,直接翻 01-intro-to-ai-agents/code_samples/

Python 侧:一个 provider、一个 @tool、一次 as_agent

01-python-agent-framework.ipynb 的依赖是这一行:

%pip install agent-framework azure-ai-projects azure-identity -q

前置条件 notebook 的 Setup 小节写得很清楚:要有一个已部署 chat 模型的 Microsoft Foundry 项目,要先在终端 az login,还要设两个环境变量——AZURE_AI_PROJECT_ENDPOINT(Foundry 项目 endpoint)和 AZURE_AI_MODEL_DEPLOYMENT_NAME(部署名)。这两个名字后面会有个坑,先记住。

接下来是三段代码,正好对应上面那三个部件。

第一段是接线。agent_framework.foundry 引入 FoundryChatClient,用 AzureCliCredential() 作为凭据构造出 provider

from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential

provider = FoundryChatClient(
    project_endpoint=endpoint,
    model=model,
    credential=AzureCliCredential()
)

notebook 里在这之前还有一句 logging.getLogger("agent_framework.foundry").setLevel(logging.ERROR),是把这个 logger 的级别调高,别把它当成必需步骤。

第二段是工具。agent_framework 引入 tool,装饰一个普通的 Python 函数:

from agent_framework import tool

@tool(approval_mode="never_require")
def get_destinations() -> list[str]:
    """Get a list of popular vacation destinations."""
    return ["Barcelona", "Paris", "Berlin", ...]

注意这个函数的 docstring 和返回类型标注不是装饰用的。第 1 课的 notebook 只说到 tools 是「agent 可以调用来取信息或执行动作的、用 @tool 装饰的 Python 函数」,至于 docstring 起什么作用,这一课并没有交代;这句话要到 02-explore-agentic-frameworks/code_samples/02-python-agent-framework.ipynb 才写明——docstring 会成为模型看到的工具描述(tool description)。第 4 课的 notebook 又把这层说得更完整:用 @tool 装饰、带类型标注的参数和 docstring 一起构成工具的 schema。所以第 1 课里那行看着像注释的 """Get a list of popular vacation destinations.""",其实是要被送给模型的内容,改它等于改工具描述。

第三段是组装。 provider.as_agent() 收三样东西——名字、instructions、tools:

agent = provider.as_agent(
    name="TravelAgent",
    instructions="You are a helpful travel agent. ...",
    tools=[get_destinations],
)

response = await agent.run("I'm looking for a warm beach destination. What do you recommend?")

分界线就在 tools=[get_destinations] 这一个参数上。把它删掉,剩下的 instructions + run() 就是一个系统提示词加一次对话——这正是 README 里说的「LLM 只是生成文本」那种形态。加上它,模型才有了 README 说的 sensor 那一层。同一份 notebook 后面还演示了流式:agent.run("...", stream=True)async for chunk in ...,那是输出形态的差别,不改变是不是 agent。

name="TravelAgent" 这个参数看着像装饰,其实后面要用上:仓库 tests/README.md 的对照表要求第 1 课的 agent 部署时就叫 TravelAgent,smoke test 靠这个名字找到它。这一节最后会讲到。

第 1 课埋了一个没解释的开关

@tool(approval_mode="never_require") 这个参数,第 1 课的 notebook 从头到尾没解释。它的解释在后面两课里:02-explore-agentic-frameworks/code_samples/02-python-agent-framework.ipynb 写了一句 approval_mode="never_require" 表示工具会自动执行、不需要用户确认;04-tool-use/code_samples/04-python-agent-framework.ipynb 则把它单列成一小节,说明这个参数控制工具调用在执行前是否需要人工批准,另一个取值是 "always_require"——每次调用都必须先经用户批准,课程建议把它用在有副作用的工具上(示例举的是订机票、刷信用卡)。那一课还演示了这个属性可以从工具对象上读回来:book_flight.approval_mode

把第 1 课和第 4 课并在一起看,会发现一个值得留意的不对称:README 举 actuator 的例子是订房、发确认、取消预订,全是写操作;而第 1 课示例里唯一那个工具 get_destinations 只返回一个常量列表,是纯读的,所以它落在 sensor 这一侧,actuator 那一侧在第 1 课并没有真的出现。带副作用的工具连同它的审批开关要到第 4 课才登场。知道这一点,你就不会误以为跑通第 1 课就等于建好了一个会动手的 agent。

.NET 侧是另一套环境变量,别照抄

01-dotnet-agent-framework.md 和同目录的 .cs 是 .NET 版本,别和 Python 版混着配。前置条件文档写明需要 .NET 10 SDK 或更高、一个带模型部署的 Azure OpenAI 资源,以及 Azure CLI(az login,供 AzureCliCredential 取 token)。

工具在这边是一个带 [Description] 特性的静态方法,再交给 AIFunctionFactory.Create 包装:

[Description("Provides a random vacation destination.")]
static string GetRandomDestination() { /* ... */ }

AIAgent agent = azureClient
    .GetChatClient(deployment)
    .AsAIAgent(
        instructions: "You are a helpful AI Agent that can help plan vacations for customers at random destinations",
        tools: [AIFunctionFactory.Create(GetRandomDestination)]
    );

[Description] 在这里承担的就是 Python 那边 docstring 的角色——文档里那句 Key Takeaways 自述,带 [Description] 特性的函数才会成为 agent 可用的工具。

真正容易踩的是环境变量:.NET 这份读的是 AZURE_OPENAI_ENDPOINTAZURE_OPENAI_DEPLOYMENT,客户端是 AzureOpenAIClient,走的是 Azure OpenAI Responses API;Python 那份读的是 AZURE_AI_PROJECT_ENDPOINTAZURE_AI_MODEL_DEPLOYMENT_NAME,走的是 Foundry 项目 endpoint。同一课的两个实现接的不是同一个 endpoint,配错了不会有任何提示告诉你「你配的是另一份示例的变量」。另外 .csAZURE_OPENAI_DEPLOYMENT 没设时会回落到 "gpt-5-mini"——这是仓库当前代码里的默认值,随版本可能变动,别把它当成你环境里一定存在的部署名。

流式在这边是 agent.RunStreamingAsync("Plan me a day trip")await foreach,和 Python 侧 stream=True 是同一件事的两种写法。

Windows 侧要注意:文档给的第一种运行方式是 chmod +x ./01-dotnet-agent-framework.cs 再直接执行脚本,那是写在 zsh/bash 段落下的;Windows 上走文档给的另一条——dotnet run ./01-dotnet-agent-framework.cs。环境变量同样有 PowerShell 版本,文档里逐条给了 $env:AZURE_OPENAI_ENDPOINT = "https://<your-resource>.openai.azure.com" 这种写法,照抄它比自己拼 set 命令稳。

以上代码片段抄自仓库对应文件,删节处以 ... 标出;为按仓库代码中的接口语义作的说明未经实测,以仓库最新代码为准。

怎么验证它真的用了工具

第 1 课末尾指到 tests/lesson-01-smoke-tests.json,这个文件比 README 更能说明「agent 和聊天机器人差在哪」。它的断言不是看回复通不通顺,而是看工具的返回值有没有出现在输出里——recommends-destinations 那条的期望值就是 get_destinations 返回列表里的城市名(contains_any)。还有一条 stays-on-topic,用 contains_none 断言模型不会在被诱导时吐出 import osshutil.rmtree 这类内容。

tests/README.md 说明了这些 catalog 的用法:先按 Lesson 16 的流程把 agent 部署为 Foundry hosted agent(第 1 课这个的部署名要求是 TravelAgent),再由 .github/workflows/smoke-test.yml 这个工作流去跑。同一份 README 也把话说在前面——smoke test 只是第一道门,不能替代 Lesson 10 和 Lesson 16 里的完整评测流程。它还说明了哪些课不适用:纯设计模式和理论课没有单一可部署的 agent,Lesson 17 因为跑在本机、不暴露 Foundry Responses endpoint 也不适用。

仓库自己把这条线划在哪

如果你觉得「三个部件」还是抽象,仓库根目录的 STUDY_GUIDE.md 里有一段更实在的自述。它设了一个「课程助手 agent」的假想场景,用户说的是「我想学 agent 怎么用工具,帮我找到对应的课、说说先看哪篇、再给个练习」,然后仓库文档自述:一个普通 chatbot 只能拿它已经知道的东西作答,而 agent 能多做几件事——去读或搜课程文件找到对的课、调工具取回链接和示例、规划出一条短的学习路径而不是甩一段长回答、用当前会话的上下文保持聚焦、在应用支持记忆时记住偏好、把 trace 与引用或日志亮出来让用户看懂发生了什么、在动手做有风险的操作或碰敏感数据前套上护栏。

这份清单值得对着第 1 课的代码逐条打勾:tools=[get_destinations] 落了「调工具」这条;instructions 落了半条「保持聚焦」;其余几条——规划、记忆、trace、护栏——在第 1 课的代码里一个都没有。这不是缺陷,STUDY_GUIDE.md 自己给的建议就是每学一课回来问一句「这一课给这个 demo 加了什么新能力」。换句话说,第 1 课交付的是最小构成,不是完整形态。

顺带一提,02-explore-agentic-frameworks/README.md 提到 chatbot 时用的是客服场景,讲的是它处理常见问询、把复杂问题留给人工。这跟第 1 课的分界是一致的:能力边界写死在你给了什么工具上,而不是写在「用没用大模型」上。

几个边界

第 1 课的两份示例都要连云端:Python 侧连 Foundry 项目,.NET 侧连 Azure OpenAI,都靠 az login 后的 CLI 凭据取 token。这意味着你在 notebook 里敲的每句话都会离开本机,密钥和数据边界要自己评估,跑之前先想清楚哪些内容不该发出去。

另外,README 在 Basics of Agentic Solutions 里写明这门课的主平台是 Microsoft Foundry Agent Service、构建用的框架是 Microsoft Agent Framework。所以本文里所有 @toolas_agentAsAIAgent 的写法都是这套框架的写法,不是 Agent 的通用语法,换个框架就不成立。

最后一句老实话:这门课持续更新,上面提到的文件路径、依赖包名、环境变量名和接口写法都随版本变动,以仓库最新内容为准。真要动手,先按你手上那一版的 notebook 走。


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

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