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 KernelAutoGen
工具定义 [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 的真正优势

核心优势对比

维度SendAsyncGroupChatManager
定位 底层 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");
          }
      }
  }

 

posted @ 2026-08-18 17:04  天才卧龙  阅读(5)  评论(0)    收藏  举报