前言
长期编写业务代码难免让思维僵化。趁着周末,我深入探索了微软最新推出的智能体开发框架——Microsoft Agent Framework(简称MAF)。按照官方文档运行了几个示例后,发现这套工具链确实颇具价值。它并非传统意义上的LLM SDK,而是一套面向开发者的完整工具链,支持多轮对话、函数调用、工具集成、可观测性等高级功能,底层架构设计非常扎实。
什么是 Microsoft Agent Framework?
概念层面的内容不宜重复造轮子,这里直接引用微软官方文档的定义(已通过翻译软件转换)。说起这个框架,难免让人联想到微软之前的两款产品:Semantic Kernel 和 AutoGen。简单来说,MAF 可以视为前两者整合后的升级版本。官方文档也对它们之间的关系做了详细说明,感兴趣的话可以自行搜索。如果你之前没有接触过 SK 和 AutoGen,那么恭喜你,完全无需绕弯路,直接上手 MAF 即可。如果已经了解过,也不必觉得白费功夫——MAF 正是基于这两者构建的,有了这些基础经验,上手会顺畅很多。笔者此前也分别写过关于 SK 和 AutoGen 的博客,此处不再展开。
上手案例
概念铺垫完毕,直接进入案例环节。官方文档虽然写得很详细,但如果缺乏模型开发经验或对相关工具链不熟悉,阅读门槛依然较高。至少访问 OpenAI 或 Azure OpenAI 的问题就需要花费不少时间处理。实际上,在 SK 时期就存在类似问题,到了 MAF 时代,处理方式反而更直接了。本文按照文档运行了几个案例,逐一介绍。
基础框架
第一个案例,先搭建最基础的框架,看看整体架构如何建立。
- 创建一个控制台项目
dotnet new console -o AgentFrameworkQuickStart
- 引入核心插件。注意,MAF 目前仍处于预览阶段,通过命令行引入时需加上 --preview 参数;在 IDE(如 Visual Studio)中,需要勾选“预览版”选项。
dotnet add package Azure.AI.OpenAI --prerelease
dotnet add package Microsoft.Agents.AI.OpenAI --prerelease
官方文档还安装了 Azure.Identity,但我们无需使用——因为后续要接入国内平台的大模型,且仅用于测试案例,暂不需要该包。
另外,我踩了一个坑,在此记录供参考。今天(2025.12.13)使用命令行安装的 Azure.AI.OpenAI 版本为 2.8.1-beta.1,该版本存在依赖冲突,导致与上级包不兼容。我在 IDE 中手动将版本号回退至 2.7.0-beta2 后解决问题。如果遇到相同情况,可以尝试此方法。
- 定义 Provider
这里我使用国内硅基流动平台,其他平台也可替换。定义一个类:
public class ModelProvider
{
public string ApiKey { get; init; } = string.Empty;
public string ModelId { get; init; } = string.Empty;
public string Endpoint { get; init; } = string.Empty;
}
对应创建一个配置文件,测试阶段非必须,但这样更便于管理:
{
"ModelProvider": {
"EndPoint": "https://api.moonshot.cn/v1",
"ApiKey": "{你的key}",
"ModelId": "kimi-k2-0905-preview"
}
}
然后执行常规操作即可:
var config = new ConfigurationBuilder()
.AddJsonFile($"llm.json", optional: false, reloadOnChange: true)
.Build();
var modelProvider = new ModelProvider()
{
ApiKey = config["ModelProvider:ApiKey"] ?? string.Empty,
ModelId = config["ModelProvider:ModelId"] ?? string.Empty,
Endpoint = config["ModelProvider:Endpoint"] ?? string.Empty,
};
Console.WriteLine($"正在使用【{modelProvider.ModelId}】模型", ConsoleColor.Yellow);
第一个智能体
文档中的第一个案例是一个笑话大师,我们稍作改造:
var agent = new OpenAIClient(
new ApiKeyCredential(modelProvider.ApiKey),
new OpenAIClientOptions { Endpoint = new Uri(modelProvider.Endpoint) })
.GetChatClient(modelProvider.ModelId)
.CreateAIAgent(
instructions: "你是个脱口秀大师,可以很轻松的逗笑大家.",
name: "脱口秀大师"
);
await foreach (var update in agent.RunStreamingAsync("来一段简短的脱口秀表演"))
{
Console.Write(update);
}
视觉智能体
接下来尝试视觉能力。注意,此时需要更换为支持视觉的模型,前面使用的 kimi 不支持,可改用 qwen 系列:
var agent = new OpenAIClient(
new ApiKeyCredential(modelProvider.ApiKey),
new OpenAIClientOptions { Endpoint = new Uri(modelProvider.Endpoint) })
.GetChatClient(modelProvider.ModelId)
.CreateAIAgent(
instructions: "你是一个能够分析图像的实用助手。",
name: "视觉袋里"
);
ChatMessage message = new ChatMessage(ChatRole.User, [
new TextContent("你在这张图片中看到了什么?"),
new UriContent("{图片实际地址}", "image/png")
]);
// Console.WriteLine(await agent.RunAsync(message));
await foreach (var update in agent.RunStreamingAsync(message))
{
Console.Write(update);
}
Function Tool
这个例子基本保持原样,直接拿来使用:
var agent = new OpenAIClient(
new ApiKeyCredential(modelProvider.ApiKey),
new OpenAIClientOptions { Endpoint = new Uri(modelProvider.Endpoint) })
.GetChatClient(modelProvider.ModelId)
.CreateAIAgent(
instructions: "你是一个智能助手。",
tools: [AIFunctionFactory.Create(GetWeather)]
);
Console.WriteLine(await agent.RunAsync("保定的天气怎么样?"));
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
需要补充一点:定义工具函数时,不再需要像 SK 时代那样标记方法工具名特性,直接写工具作用的描述即可,更加简洁。工具调用在 LLM 发展初期就已普及,这也是 Agent 的核心——让智能体不仅限于“回答问题”,还能像人一样“执行动作”。
需要人批准的函数工具
这个功能非常关键。在实际业务中,很多场景下我们不应让智能体直接执行操作,而需要人类授权后再决定是否执行,即“人机协同”模式。示例虽然简单,但可以在此基础上扩展丰富的业务逻辑,例如权限管理模块。它的核心价值在于实现安全可控的自动化流程,避免误操作。
AIFunction weatherFunction = AIFunctionFactory.Create(GetWeather);
AIFunction approvalRequiredWeatherFunction = new ApprovalRequiredAIFunction(weatherFunction);
var agent = new OpenAIClient(
new ApiKeyCredential(modelProvider.ApiKey),
new OpenAIClientOptions { Endpoint = new Uri(modelProvider.Endpoint) })
.GetChatClient(modelProvider.ModelId)
.CreateAIAgent(
instructions: "你是一个智能助手。",
tools: [approvalRequiredWeatherFunction]
);
AgentThread thread = agent.GetNewThread();
AgentRunResponse response = await agent.RunAsync("保定的天气如何?", thread);
var functionApprovalRequests = response.Messages
.SelectMany(x => x.Contents)
.OfType()
.ToList();
FunctionApprovalRequestContent requestContent = functionApprovalRequests.First();
Console.WriteLine($"我需要您的批准才能执行 '{requestContent.FunctionCall.Name}'");
var approvalMessage = new ChatMessage(ChatRole.User, [
requestContent.CreateResponse(true)
]);
Console.WriteLine(await agent.RunAsync(approvalMessage, thread));
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
将 Agent 暴露为 MCP 工具
通过 MAF,可以轻松将 Agent 封装为 MCP Server,然后在任意 MCP 客户端中注册并调用该工具。效果非常流畅,就像编写接口一样简单:
var agent = new OpenAIClient(
new ApiKeyCredential(modelProvider.ApiKey),
new OpenAIClientOptions { Endpoint = new Uri(modelProvider.Endpoint) })
.GetChatClient(modelProvider.ModelId)
.CreateAIAgent(
instructions: "你是个笑话大师.",
name: "笑话大师"
);
var jokerMcpTool = McpServerTool.Create(agent.AsAIFunction());
var builder = Host.CreateEmptyApplicationBuilder(settings: null);
builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithTools([jokerMcpTool]);
await builder.Build().RunAsync();
在 Cline 中调用它的效果如下——
结语
运行完这几个案例,整体体验非常不错。微软通过 MAF 提供了一条清晰的技术路径,让开发者能够轻松构建属于自己的“智能助手”。接下来,我会继续深入探索 MAF,因为当前项目也需要接入智能体框架。它绝不只是“锦上添花”的定位,而是提升办公效率、提质增效的核心要素——当然,前提是业务系统中的基础操作足够稳定可靠。基于这一基础,智能体的接入才能真正释放生产力。
关于 MAF 的介绍只是冰山一角,后续还有更具特色的工作流、AG-UI、DevUI 等模块,下次有机会再详细探讨。晚安,攻城狮们。
