1. 初识 Microsoft Agent Framework
第一次听说 Microsoft Agent Framework(简称 MAF)是在一个技术社区里,当时看到有人分享用这个框架快速搭建了一个智能客服系统。作为一个长期在 AI 领域摸爬滚打的老兵,我立刻被这个新框架吸引住了。MAF 给我的第一印象就像是把 Semantic Kernel 和 AutoGen 这两个框架的优点都吸收进来,还加入了不少新特性。
简单来说,MAF 是微软推出的一个开源开发套件,专门用来构建人工智能代理和多智能体工作流。它支持 .NET 和 Python 两种语言,这点对开发者特别友好。我特别喜欢它的设计理念 - 不是简单地封装大模型 API,而是提供了一套完整的工具链,让开发者能轻松实现多轮对话、函数调用、工具集成这些高级功能。
2. 环境搭建与基础配置
2.1 创建项目与安装依赖
我决定从一个最简单的控制台项目开始。打开终端,运行:
dotnet new console -o MyFirstMAFAgent然后进入项目目录安装核心包。这里要注意 MAF 目前还是预览版,需要加上 --prerelease 参数:
dotnet add package Azure.AI.OpenAI --prerelease dotnet add package Microsoft.Agents.AI.OpenAI --prerelease我在实际操作时遇到了一个版本冲突问题。Azure.AI.OpenAI 2.8.1-beta.1 这个版本会和其他包产生依赖冲突,后来我把版本降到 2.7.0-beta2 就解决了。这也是为什么我建议新手在 IDE(比如 Visual Studio)里安装包更方便,可以直接看到依赖关系。
2.2 配置模型访问
接下来要配置大模型访问。我创建了一个简单的 ModelProvider 类来管理配置:
public class ModelProvider { public string ApiKey { get; init; } = string.Empty; public string ModelId { get; init; } = string.Empty; public string Endpoint { get; init; } = string.Empty; }然后在 appsettings.json 里配置参数:
{ "ModelProvider": { "EndPoint": "https://api.moonshot.cn/v1", "ApiKey": "你的API_KEY", "ModelId": "kimi-k2-0905-preview" } }读取配置的代码也很简单:
var config = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .Build(); var modelProvider = new ModelProvider { ApiKey = config["ModelProvider:ApiKey"], ModelId = config["ModelProvider:ModelId"], Endpoint = config["ModelProvider:Endpoint"] };3. 创建第一个智能体
3.1 基础聊天智能体
现在可以创建我们的第一个智能体了!我决定从一个笑话机器人开始:
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); }运行这个程序,你会看到一个关于程序员的冷笑话。这里有几个关键点:
CreateAIAgent方法创建了一个智能体实例instructions参数定义了智能体的行为特征RunStreamingAsync实现了流式输出
3.2 视觉智能体
MAF 还支持视觉能力。我尝试创建一个能分析图片的智能体:
var agent = new OpenAIClient( new ApiKeyCredential(modelProvider.ApiKey), new OpenAIClientOptions { Endpoint = new Uri(modelProvider.Endpoint) }) .GetChatClient("qwen-vl-plus") // 注意要换支持视觉的模型 .CreateAIAgent( instructions: "你是一个图片分析专家", name: "视觉助手"); var message = new ChatMessage(ChatRole.User, [ new TextContent("描述这张图片的内容"), new UriContent("https://example.com/image.jpg", "image/jpeg") ]); await foreach (var update in agent.RunStreamingAsync(message)) { Console.Write(update); }4. 实现功能工具集成
4.1 基础函数工具
智能体的真正威力在于它能调用外部工具。我创建了一个查询天气的函数:
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("获取指定城市的天气信息")] static string GetWeather([Description("要查询的城市名称")] string location) { // 这里应该是调用真实天气API return $"今天{city}的天气是晴天,气温25℃"; }4.2 需要人工审批的函数
在实际业务中,有些操作需要人工审批。MAF 提供了很好的支持:
var weatherFunc = AIFunctionFactory.Create(GetWeather); var approvalFunc = new ApprovalRequiredAIFunction(weatherFunc); var agent = new OpenAIClient( new ApiKeyCredential(modelProvider.ApiKey), new OpenAIClientOptions { Endpoint = new Uri(modelProvider.Endpoint) }) .GetChatClient(modelProvider.ModelId) .CreateAIAgent( instructions: "你是一个需要审批的助手", tools: [approvalFunc]); var thread = agent.GetNewThread(); var response = await agent.RunAsync("帮我预定会议室", thread); // 获取需要审批的请求 var approvalRequests = response.Messages .SelectMany(x => x.Contents) .OfType<FunctionApprovalRequestContent>() .ToList(); if (approvalRequests.Any()) { Console.WriteLine($"需要审批的操作: {approvalRequests[0].FunctionCall.Name}"); var approvalMessage = new ChatMessage(ChatRole.User, [ approvalRequests[0].CreateResponse(true) // true表示批准 ]); Console.WriteLine(await agent.RunAsync(approvalMessage, thread)); }5. 部署为可调用服务
5.1 创建 MCP 服务
MAF 最酷的功能之一是可以把智能体部署为 MCP 服务:
var agent = new OpenAIClient( new ApiKeyCredential(modelProvider.ApiKey), new OpenAIClientOptions { Endpoint = new Uri(modelProvider.Endpoint) }) .GetChatClient(modelProvider.ModelId) .CreateAIAgent( instructions: "你是一个笑话服务", name: "笑话服务"); var mcpTool = McpServerTool.Create(agent.AsAIFunction()); var builder = Host.CreateEmptyApplicationBuilder(); builder.Services .AddMcpServer() .WithStdioServerTransport() .WithTools([mcpTool]); await builder.Build().RunAsync();5.2 客户端调用
其他应用可以通过标准方式调用这个服务:
var client = new McpClient(); var result = await client.InvokeToolAsync("笑话服务", "讲个笑话"); Console.WriteLine(result);6. 实战:构建天气查询助手
现在让我们把这些知识综合起来,构建一个完整的天气查询助手。
6.1 项目结构设计
我创建了如下项目结构:
WeatherAssistant/ ├── Services/ │ ├── WeatherService.cs ├── Agents/ │ ├── WeatherAgent.cs ├── Program.csWeatherService 封装了真实的天气 API 调用:
public class WeatherService { [Description("获取城市天气信息")] public async Task<string> GetWeatherAsync( [Description("城市名称")] string city) { // 这里调用真实天气API return $"{city}今天晴转多云,气温20-28℃"; } }6.2 智能体实现
WeatherAgent 类封装了智能体逻辑:
public class WeatherAgent { private readonly OpenAIClient _client; private readonly string _modelId; public WeatherAgent(OpenAIClient client, string modelId) { _client = client; _modelId = modelId; } public AIAgent CreateAgent() { var weatherService = new WeatherService(); var weatherFunc = AIFunctionFactory.Create(weatherService.GetWeatherAsync); return _client.GetChatClient(_modelId) .CreateAIAgent( instructions: "你是一个专业的天气查询助手", name: "天气助手", tools: [weatherFunc]); } }6.3 主程序集成
最后在 Program.cs 中集成所有组件:
var modelProvider = // 初始化模型配置 var client = new OpenAIClient( new ApiKeyCredential(modelProvider.ApiKey), new OpenAIClientOptions { Endpoint = new Uri(modelProvider.Endpoint) }); var agent = new WeatherAgent(client, modelProvider.ModelId).CreateAgent(); while (true) { Console.Write("你想查询哪个城市的天气?"); var city = Console.ReadLine(); if (string.IsNullOrEmpty(city)) break; var response = await agent.RunAsync($"{city}的天气怎么样?"); Console.WriteLine(response); }7. 调试与优化技巧
在实际开发中,我发现了一些有用的调试技巧:
- 日志记录:MAF 提供了丰富的日志接口,可以记录智能体的思考过程
builder.Services.AddLogging(configure => configure.AddConsole().SetMinimumLevel(LogLevel.Debug));- 超时设置:对于长时间运行的操作,记得设置合理的超时
var options = new OpenAIClientOptions { Endpoint = new Uri(modelProvider.Endpoint), RetryPolicy = new RetryPolicy(maxRetries: 2), NetworkTimeout = TimeSpan.FromSeconds(30) };- 性能监控:可以使用 Application Insights 等工具监控智能体性能
builder.Services.AddApplicationInsightsTelemetry();8. 进阶功能探索
完成基础项目后,我开始尝试一些更高级的功能:
8.1 多智能体协作
MAF 支持创建多个智能体协同工作:
var translator = client.GetChatClient(modelId) .CreateAIAgent("你是一个专业翻译,负责中英互译"); var summarizer = client.GetChatClient(modelId) .CreateAIAgent("你是一个摘要专家,负责总结内容"); var workflow = new WorkflowBuilder() .AddAgent(translator) .AddAgent(summarizer) .Build(); var result = await workflow.RunAsync("请把这篇英文文章翻译成中文并总结");8.2 记忆与上下文
智能体可以记住对话历史:
var thread = agent.GetNewThread(); await agent.RunAsync("我叫张三", thread); var response = await agent.RunAsync("我叫什么名字?", thread); Console.WriteLine(response); // 输出"你叫张三"8.3 自定义中间件
可以插入自定义中间件来修改智能体行为:
public class LoggingMiddleware : IAgentMiddleware { public async Task InvokeAsync(AgentContext context, NextMiddleware next) { Console.WriteLine($"收到请求: {context.Request}"); await next(context); Console.WriteLine($"返回响应: {context.Response}"); } } // 注册中间件 agent.UseMiddleware<LoggingMiddleware>();9. 项目部署与运维
当项目开发完成后,需要考虑部署问题:
9.1 容器化部署
我通常使用 Docker 容器来部署 MAF 应用:
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY . . RUN dotnet publish -c Release -o /app FROM mcr.microsoft.com/dotnet/aspnet:8.0 WORKDIR /app COPY --from=build /app . ENTRYPOINT ["dotnet", "WeatherAssistant.dll"]9.2 性能优化
对于生产环境,我推荐以下优化措施:
- 使用连接池管理模型客户端
- 实现响应缓存
- 对耗时操作使用异步处理
9.3 监控与告警
完善的监控系统对智能体应用至关重要。我通常会配置:
- 请求成功率监控
- 响应时间监控
- 异常告警
10. 经验总结与避坑指南
经过这个项目的实践,我总结了以下几点经验:
版本兼容性问题:MAF 目前还是预览版,不同版本间可能存在兼容性问题。建议锁定特定版本号。
模型选择:不同模型对函数调用的支持程度不同。如果发现函数调用不工作,可以尝试换一个模型。
错误处理:智能体可能会产生意外输出,一定要做好输入验证和输出过滤。
测试策略:智能体行为具有一定不可预测性,需要设计专门的测试用例来验证各种边界情况。
成本控制:频繁调用大模型可能产生高昂费用,建议实现使用量监控和限流机制。
在实际项目中,我还发现 MAF 的一个隐藏优势 - 它很好地抽象了底层模型差异。这意味着你可以轻松切换不同的模型提供商,而不用重写业务逻辑。比如今天用 OpenAI,明天想换成国产模型,只需要修改配置即可。