AutoGen for .NET 的函数调用(Function Call)和多 Agent 协作(WorkFlow+GroupChat)机制。
参考:https://www.cnblogs.com/chenwolong/p/21742326
Function Call 是 AutoGen 的核心杀手锏!学完这个,你的 Agent 就从"只会聊天"变成"能干活"了!🥚
📋 什么是 Function Call?
❌ 没有 Function Call 的 Agent
用户:北京今天天气怎么样?
LLM:抱歉,我无法获取实时天气信息,建议您查看天气应用...
↑ 纯聊天,干不了实事
有 Function Call 的 Agent
用户:北京今天天气怎么样? LLM:[内部思考] 用户问天气,我需要调用天气工具 ↓ 调用 GetWeather("北京") ↓ 返回:晴天,25°C,湿度 60% ↓ LLM:北京今天晴天,气温 25 度,湿度 60%,适合出门! ↑ 能干实事了!
和 Semantic Kernel 对比
你学过 SK,对比着看更容易理解!
| 特性 | Semantic Kernel | AutoGen |
|---|---|---|
| 工具定义 | [KernelFunction] |
[Function] |
| 工具注册 | kernel.Plugins.Add() |
agent.RegisterFunctions() |
| 调用时机 | 自动检测 | 自动检测 |
| 多工具协作 | ✅ 支持 | ✅ 支持 |
| 多 Agent 协作 | ❌ 不支持 | ✅ 支持(AutoGen 强项) |
本质是一样的!都是 AOP + 反射 + 元数据!
AutoGen的workFlow-智能体编排能手
┌─────────────────────────────────────────────────────────┐ │ Workflow = 智能体编排引擎 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 没有 Workflow: │ │ User → Agent1 → Agent2 → Agent1 → Agent2... │ │ (盲目轮流,没有业务逻辑) │ │ │ │ 有 Workflow: │ │ User → 天气查询 → 行程规划 → 预算评估 → 完成 │ │ (固定流程,符合业务逻辑) │ │ │ │ 价值: │ │ → 定义 Agent 发言顺序 │ │ → 控制业务流程 │ │ → 避免无效对话 │ │ → 适合生产环境 │ │ │ └─────────────────────────────────────────────────────────┘
GroupChat 默认几种执行顺序?
三种 Orchestrator(执行策略)
| Orchestrator | 触发条件 | 执行顺序 |
|---|---|---|
| RoundRobinOrchestrator | admin = null + workflow = null |
A→B→C→A→B→C...(轮询) |
| RolePlayOrchestrator | admin != null |
Admin 决定下一个谁发言(协调者模式) |
| WorkflowOrchestrator | workflow != null |
按 Graph 定义的转换链 |
GroupChatManager(群聊/可建设多个群里,每个群里N个智能体) vs SendAsync 的真正优势
核心优势对比
| 维度 | SendAsync | GroupChatManager |
|---|---|---|
| 定位 | 底层 API | 高层抽象 |
| 语义 | "发送消息" | "发起对话" |
| 角色分离 | ❌ User 和 GroupChat 混在一起 | ✅ User 和 Group 分离 |
| 多轮对话管理 | ❌ 手动管理 chatHistory | ✅ 自动管理 |
| 终止条件 | ❌ 手动检测 | ✅ 内置检测 |
| 扩展性 | ❌ 难扩展 | ✅ 易扩展 |
| 符合业务语义 | ❌ 技术视角 | ✅ 业务视角 |
🎯 总结
┌─────────────────────────────────────────────────────────┐ │ 项目总结 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 1. Workflow 是重点 ✅ │ │ → 实现智能体编排 │ │ → 定义业务流程 │ │ → 本项目核心价值 │ │ │ │ 2. GroupChat 默认三种执行顺序 │ │ → RoundRobinOrchestrator(轮询) │ │ → RolePlayOrchestrator(协调员) │ │ → WorkflowOrchestrator(工作流) │ │ │ │ 3. GroupChatManager 优势 │ │ → 短对话看不出(六爷感受正确) │ │ → 长对话/多用户/多群组优势明显 │ │ → 高层抽象,符合业务语义 │ │ → 自动管理对话历史 │ │ → 易于扩展和维护 │ │ │ │ 类比: │ │ → SendAsync = 手动档(灵活但麻烦) │ │ → GroupChatManager = 自动档(简单但封装多) │ │ │ └─────────────────────────────────────────────────────────┘
短对话用 SendAsync 就够了,长对话/生产环境用 GroupChatManager!🥚
项目代码:
两个智能体:天气预报智能体 及 行程规划智能体
using Applier; using AutoGen.Core; using AutoGen.OpenAI; using AutoGen.OpenAI.Extension; using OpenAI; using System; using System.ClientModel; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.Json; using System.Threading.Tasks; namespace FuntionCalls { public class AgentFactory { private readonly OpenAIClient _client; private readonly HttpClient _httpClient; private readonly string _amapApiKey; public AgentFactory() { _client = new OpenAIClient( new ApiKeyCredential(ConstParm.apiKey), new OpenAIClientOptions { Endpoint = new Uri(ConstParm.endpoint) }); _httpClient = new HttpClient(); _amapApiKey = ConstParm.amapApiKey; Console.WriteLine("✅ AgentFactory 初始化完成"); Console.WriteLine($" 使用模型:{ConstParm.modelId}"); } /// <summary> /// 创建天气查询智能体 /// </summary> public IAgent CreateWeatherAgent() { Console.WriteLine("🔧 创建天气查询智能体..."); var weatherTool = new WeatherTool(_httpClient, _amapApiKey); // ① 创建 FunctionContract var functionContract = new FunctionContract { Name = "GetWeatherAsync", Description = "获取指定城市的实时天气信息,包括温度、湿度、天气现象、风向风力等", Parameters = new List<FunctionParameterContract>() { new FunctionParameterContract() { Name = "city", Description = "城市名称,如:苏州、北京", IsRequired=true, DefaultValue="北京", ParameterType=typeof(string) }} }; // ② 创建 functionMap(函数执行逻辑) var functionMap = new Dictionary<string, Func<string, Task<string>>> { { functionContract.Name, async (args) => { var city = JsonDocument.Parse(args) .RootElement.GetProperty("city").GetString(); return await weatherTool.GetWeatherAsync(city!); } } }; // ③ 创建 FunctionCallMiddleware var functionCallMiddleware = new FunctionCallMiddleware( functions: new[] { functionContract }, functionMap: functionMap); // ④ 创建 Agent 并注册中间件 var agent = new OpenAIChatAgent( name: "GetWeatherAgent", systemMessage: "你是一个专业的天气预报分析师。当用户询问天气时,必须调用 get_weather 函数获取真实数据,不要编造天气信息。", chatClient: _client.GetChatClient(ConstParm.modelId)); return agent .RegisterMessageConnector() .RegisterMiddleware(functionCallMiddleware) .RegisterPrintMessage(); } /// <summary> /// 创建行程规划智能体 /// </summary> public IAgent CreateTravelPlannerAgent() { Console.WriteLine("🔧 创建行程规划智能体..."); var plannerTool = new TravelPlannerTool(); // ① 创建 FunctionContract var functionContract = new FunctionContract { Name = "PlanTravel", Description = "根据天气情况推荐旅游行程", Parameters = new List<FunctionParameterContract> { new FunctionParameterContract { Name = "city", Description = "城市名称", IsRequired = true, ParameterType = typeof(string), DefaultValue = null }, new FunctionParameterContract { Name = "weather", Description = "天气状况,如:晴、雨、多云", IsRequired = true, ParameterType = typeof(string), DefaultValue = null }, new FunctionParameterContract { Name = "temperature", Description = "温度(摄氏度)", IsRequired = true, ParameterType = typeof(int), DefaultValue = null }, new FunctionParameterContract { Name = "days", Description = "游玩天数", IsRequired = false, ParameterType = typeof(int), DefaultValue = 1 } } }; // ② 创建 functionMap var functionMap = new Dictionary<string, Func<string, Task<string>>> { { functionContract.Name, async (args) => { var json = JsonDocument.Parse(args); var root = json.RootElement; var city = root.GetProperty("city").GetString(); var weather = root.GetProperty("weather").GetString(); var temperature = root.GetProperty("temperature").GetInt32(); var days = root.TryGetProperty("days", out var daysElem) ? daysElem.GetInt32() : 1; return plannerTool.PlanTravel(city!, weather!, temperature, days); } } }; // ③ 创建 FunctionCallMiddleware var functionCallMiddleware = new FunctionCallMiddleware( functions: new[] { functionContract }, functionMap: functionMap); // ④ 创建 Agent 并注册中间件 var agent = new OpenAIChatAgent( name: "PlannerAgent", systemMessage: "你是一个专业的旅游规划师。根据天气情况和用户偏好,推荐合适的行程。必须调用 plan_travel 函数生成建议。", chatClient: _client.GetChatClient(ConstParm.modelId)); return agent .RegisterMessageConnector() .RegisterMiddleware(functionCallMiddleware) .RegisterPrintMessage(); } } }
两个Function/工具:高德天气查询工具 及 行程规划工具
using Applier; using AutoGen.Core; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Text.Json; using System.Threading.Tasks; namespace FuntionCalls { /// <summary> /// 天气查询助手 /// </summary> public class WeatherTool { private readonly HttpClient _httpClient; private readonly string _apiKey; public WeatherTool(HttpClient httpClient, string apiKey) { _httpClient = httpClient; _apiKey = apiKey; } public async Task<string> GetWeatherAsync(string city) { try { // ① 查城市 ADCode var adcodeUrl = $"https://restapi.amap.com/v3/config/district?keywords={city}&subdistrict=0&key={_apiKey}"; var adcodeData = await _httpClient.GetStringAsync(adcodeUrl); var adcodeJson = JsonDocument.Parse(adcodeData); if (adcodeJson.RootElement.GetProperty("status").GetString() != "1") { return $"❌ 未找到城市:{city}"; } var adcode = adcodeJson.RootElement.GetProperty("districts")[0] .GetProperty("adcode").GetString(); // ② 查实时天气 var weatherUrl = $"https://restapi.amap.com/v3/weather/weatherInfo?city={adcode}&key={_apiKey}"; var weatherData = await _httpClient.GetStringAsync(weatherUrl); var weatherJson = JsonDocument.Parse(weatherData); if (weatherJson.RootElement.GetProperty("status").GetString() != "1") { return $"❌ 天气查询失败:{city}"; } var info = weatherJson.RootElement.GetProperty("lives")[0]; var result = new { city = info.GetProperty("city").GetString(), weather = info.GetProperty("weather").GetString(), temperature = info.GetProperty("temperature").GetString(), humidity = info.GetProperty("humidity").GetString(), windDirection = info.GetProperty("winddirection").GetString(), windPower = info.GetProperty("windpower").GetString(), reportTime = info.GetProperty("reporttime").GetString() }; return JsonSerializer.Serialize(result, new JsonSerializerOptions { WriteIndented = true }); } catch (Exception ex) { return $"❌ 错误:{ex.Message}"; } } } /// <summary> /// 行程规划助手 /// </summary> public class TravelPlannerTool { public string PlanTravel(string city, string weather, int temperature, int days = 1) { var recommendations = new List<string>(); // 根据天气推荐 if (weather.Contains("晴") || weather.Contains("多云")) { recommendations.Add("✅ 适合户外活动"); recommendations.Add($"- 推荐景点:{city}园林、古镇、湖边散步"); recommendations.Add("- 建议穿薄外套,带防晒霜"); } else if (weather.Contains("雨")) { recommendations.Add("☔ 建议室内活动"); recommendations.Add($"- 推荐景点:{city}博物馆、美术馆、购物中心"); recommendations.Add("- 记得带伞,穿防水鞋"); } else { recommendations.Add("⚠️ 天气一般,灵活安排"); recommendations.Add("- 准备室内外两套方案"); } // 根据温度推荐 if (temperature < 10) { recommendations.Add("🥶 天气较冷,注意保暖"); } else if (temperature > 30) { recommendations.Add("☀️ 天气炎热,注意防暑"); } return string.Join("\n", recommendations); } } }
主函数的两种实现方式:群聊-GroupChatManager 及 groupChat.SendAsync
GroupChatManager(推荐):
class Program { static async Task Main(string[] args) { Console.OutputEncoding = System.Text.Encoding.Unicode; Console.InputEncoding = System.Text.Encoding.Unicode; Console.WriteLine("🤖 AutoGen 第 3 课实战 - 天气 + 行程规划联动"); Console.WriteLine("==============================================\n"); var factory = new AgentFactory(); // 创建两个智能体 var weatherAgent = factory.CreateWeatherAgent(); var plannerAgent = factory.CreateTravelPlannerAgent(); var userProxy = new UserProxyAgent(name: "User"); // ✅ 创建工作流 var workflow = new Graph(); workflow.AddTransition(Transition.Create(userProxy, weatherAgent)); workflow.AddTransition(Transition.Create(weatherAgent, plannerAgent)); workflow.AddTransition(Transition.Create(plannerAgent, weatherAgent)); // ✅ 创建 GroupChat var groupChat = new GroupChat( members: new[] { userProxy, weatherAgent, plannerAgent }, workflow: workflow); // ✅ 创建 GroupChatManager(代表整个群聊) var groupChatManager = new GroupChatManager(groupChat); Console.WriteLine("\n========================================"); Console.WriteLine("🌍 旅行咨询智能体已就绪!"); Console.WriteLine("💬 输入旅行计划,如:"); Console.WriteLine(" - 我想明天去北京玩,有什么建议?"); Console.WriteLine("输入 'quit' 退出\n"); Console.WriteLine("========================================\n"); while (true) { Console.Write("👤 你:"); var input = Console.ReadLine(); if (string.IsNullOrWhiteSpace(input) || input.ToLower() == "quit") { Console.WriteLine("\n👋 再见!"); break; } Console.WriteLine("\n🔄 智能体正在协作处理...\n"); // ✅ 用 UserProxyAgent 发起对话(receiver 是 GroupChatManager) var chatHistory = new List<IMessage> { new TextMessage(Role.User, input, from: "User") }; // ✅ InitiateChatAsync 发起对话 var response = await userProxy.InitiateChatAsync( receiver: groupChatManager, message: input, maxRound: 4); // ✅ 打印所有消息 foreach (var message in response) { Console.WriteLine($"【{message.From}】: {message.GetContent()}\n"); } Console.WriteLine("\n✅ 处理完成\n"); } } }
groupChat.SendAsync:
class Program { static async Task Main(string[] args) { Console.OutputEncoding = System.Text.Encoding.Unicode; Console.InputEncoding = System.Text.Encoding.Unicode; Console.WriteLine("🤖 AutoGen 第 3 课实战 - 天气 + 行程规划联动"); Console.WriteLine("==============================================\n"); var factory = new AgentFactory(); // 创建一个虚拟的"User Agent" var userProxy = new UserProxyAgent(name: "User"); // 创建两个智能体 var weatherAgent = factory.CreateWeatherAgent(); var plannerAgent = factory.CreateTravelPlannerAgent(); // ✅ 创建工作流 - var workflow = new Graph(); workflow.AddTransition(Transition.Create(userProxy, weatherAgent)); // ✅ 创建转换规则(用 Transition.Create) workflow.AddTransition(Transition.Create(weatherAgent, plannerAgent)); workflow.AddTransition(Transition.Create(plannerAgent, weatherAgent)); // 创建 GroupChat(传入 workflow) var groupChat = new GroupChat( members: new[] { userProxy, weatherAgent, plannerAgent }, workflow: workflow); Console.WriteLine("\n========================================"); Console.WriteLine("🌍 旅行咨询智能体已就绪!"); Console.WriteLine("💬 输入旅行计划,如:"); Console.WriteLine(" - 我想明天去北京玩,有什么建议?"); Console.WriteLine("输入 'quit' 退出\n"); Console.WriteLine("========================================\n"); while (true) { Console.Write("👤 你:"); var input = Console.ReadLine(); if (string.IsNullOrWhiteSpace(input) || input.ToLower() == "quit") { Console.WriteLine("\n👋 再见!"); break; } var chatHistory = new List<IMessage> { new TextMessage(Role.User, input, from: "User") }; Console.WriteLine("\n🔄 智能体正在协作处理...\n"); await foreach (var message in groupChat.SendAsync(chatHistory, maxRound: 4)) { Console.WriteLine($"【{message.From}】: {message.GetContent()}\n"); } Console.WriteLine("\n✅ 处理完成\n"); } } }

浙公网安备 33010602011771号