AutoGen 高并发(限流)、会话隔离、多Agent协助、WorkFlow编排、重试中间件、重试熔断超时中间件

🎯 AutoGen 高并发多 Agent 协作系统 - 架构设计

📐 整体架构图

┌─────────────────────────────────────────────────────────────────────────┐
│                    AutoGen 高并发多 Agent 协作系统                        │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  用户请求                                                                 │
│     ↓                                                                   │
│ ┌───────────────────────────────────────────────────────────────────┐  │
│ │ L1: RateLimitingService(入口令牌桶限流)                          │  │
│ │     ├─ ConcurrentDictionary<string, RateLimiter>                  │  │
│ │     └─ 每用户独立令牌桶(TokenBucket)                            │  │
│ └───────────────────────────────────────────────────────────────────┘  │
│     ↓                                                                   │
│ ┌───────────────────────────────────────────────────────────────────┐  │
│ │ L2: SemaphoreSlim(系统并发控制)                                  │  │
│ │     └─ 全局信号量(同时最多 5 个请求)                               │  │
│ └───────────────────────────────────────────────────────────────────┘  │
│     ↓                                                                   │
│ ┌───────────────────────────────────────────────────────────────────┐  │
│ │ L3: GroupChatFactory(Session 隔离)⭐ 核心                        │  │
│ │     ├─ ConcurrentDictionary<string, GroupChatManager>             │  │
│ │     ├─ 每 Session 独立 Workflow                                   │  │
│ │     └─ 每 Session 独立 Agent 实例                                   │  │
│ └───────────────────────────────────────────────────────────────────┘  │
│     ↓                                                                   │
│ ┌───────────────────────────────────────────────────────────────────┐  │
│ │ L4: FunctionCallMiddleware(工具限流)                             │  │
│ │     ├─ 自定义 IMiddleware                                         │  │
│ │     └─ 每工具独立限流(每分钟 N 次)                                 │  │
│ └───────────────────────────────────────────────────────────────────┘  │
│     ↓                                                                   │
│ ┌───────────────────────────────────────────────────────────────────┐  │
│ │ L5: PollyMiddleware(重试 + 熔断 + 超时)                           │  │
│ │     ├─ 自定义 IMiddleware                                         │  │
│ │     └─ 每工具独立策略(Retry + CircuitBreaker + Timeout)          │  │
│ └───────────────────────────────────────────────────────────────────┘  │
│     ↓                                                                   │
│ ┌───────────────────────────────────────────────────────────────────┐  │
│ │ L6: SessionHistoryStore(历史存储隔离)                            │  │
│ │     ├─ ConcurrentDictionary<string, List<IMessage>>               │  │
│ │     └─ 可持久化到 MongoDB/CosmosDB                                │  │
│ └───────────────────────────────────────────────────────────────────┘  │
│     ↓                                                                   │
│  GroupChat + Workflow 执行                                               │
│  UserAgent → WeatherAgent → PlannerAgent → BudgetAgent                 │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

🎯 Workflow 设计(4 Agent 协作)

┌─────────────────────────────────────────────────────────┐
│ 旅行规划 Workflow                                        │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  UserAgent(用户代理)                                  │
│     ↓                                                   │
│  WeatherAgent(天气查询)                               │
│     ├─ 调用高德天气 API                                  │
│     └─ 限流:60 次/分钟                                  │
│     ↓                                                   │
│  PlannerAgent(行程规划)                               │
│     ├─ 根据天气推荐景点                                  │
│     └─ 限流:30 次/分钟                                  │
│     ↓                                                   │
│  BudgetAgent(预算评估)                                │
│     ├─ 计算交通 + 门票 + 餐饮                            │
│     └─ 限流:30 次/分钟                                  │
│     ↓                                                   │
│  返回 UserAgent(最终输出)                              │
│                                                         │
└─────────────────────────────────────────────────────────┘

 项目代码

超时/重试/熔断策略--函数/工具级别中间件
using AutoGen.Core;
using Microsoft.Extensions.Logging;
using Polly;
using Polly.CircuitBreaker;
using Polly.Timeout;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AutoGenLimit.Middleware
{
    #region 超时/重试/熔断策略--函数/工具级别中间件
    /// <summary>
    /// Polly 策略中间件(重试 + 熔断 + 超时)
    /// </summary>
    public static class PollyMiddlewareExtensions
    {
        /// <summary>
        /// 注册 Polly 策略中间件(全局策略)
        /// </summary>
        public static MiddlewareAgent<IAgent> WithPolly(
            this IAgent agent,
            ILogger? logger = null,
            int maxRetries = 3,
            int circuitBreakerThreshold = 5,
            int timeoutSeconds = 20)
        {
            // ✅ 重试:最多 3 次,指数退避
            var retryPolicy = Policy
                .Handle<Exception>()
                .WaitAndRetryAsync(
                    retryCount: maxRetries,
                    sleepDurationProvider: retry =>
                        TimeSpan.FromSeconds(Math.Pow(1.1, retry)),
                    onRetry: (outcome, timeSpan, retryNumber, context) =>
                    {
                        logger?.LogWarning(
                            "重试 {Retry}/{Max},等待 {Wait}s,原因:{Error}",
                            retryNumber, maxRetries,
                            timeSpan.TotalSeconds, outcome.GetBaseException()?.Message);
                    });

            // ✅ 熔断:连续失败 5 次 → 熔断 30 秒
            var circuitBreakerPolicy = Policy
                .Handle<Exception>()
                .CircuitBreakerAsync(
                    exceptionsAllowedBeforeBreaking: circuitBreakerThreshold,
                    durationOfBreak: TimeSpan.FromSeconds(30),
                    onBreak: (outcome, timeSpan) =>
                    {
                        logger?.LogError("⚠️ 熔断器打开!连续失败 {Count} 次,暂停 {Seconds}s",
                            circuitBreakerThreshold, timeSpan.TotalSeconds);
                    },
                    onReset: () =>
                    {
                        logger?.LogInformation("✅ 熔断器复位,恢复正常");
                    });

            // ✅ 超时:20 秒
            var timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromSeconds(timeoutSeconds));

            // ✅ 组合策略(执行顺序:Timeout → CircuitBreaker → Retry)
            var policyWrap = Policy.WrapAsync(timeoutPolicy, circuitBreakerPolicy, retryPolicy);

            return agent.RegisterMiddleware<IAgent>(async (msgs, options, nextAgent, ct) =>
            {
                try
                {
                    logger?.LogInformation("🛡️ Polly 执行:{AgentName}", nextAgent.Name);

                    // ✅ 用 Polly 包装执行
                    return await policyWrap.ExecuteAsync(
                        async () => await nextAgent.GenerateReplyAsync(msgs, options, ct));
                }
                catch (BrokenCircuitException ex)
                {
                    logger?.LogError("⚡ 熔断触发:{Agent} - {Error}", nextAgent.Name, ex.Message);
                    throw;
                }
                catch (TimeoutRejectedException ex)
                {
                    logger?.LogError("⏱️ 超时触发:{Agent} - {Error}", nextAgent.Name, ex.Message);
                    throw;
                }
                catch (Exception ex)
                {
                    logger?.LogError("❌ Polly 失败:{Agent} - {Error}", nextAgent.Name, ex.Message);
                    throw;
                }
            });
        }

        /// <summary>
        /// 仅注册重试策略(轻量级)
        /// </summary>
        public static MiddlewareAgent<IAgent> WithRetry(
            this IAgent agent,
            int maxRetries = 3,
            TimeSpan? delay = null)
        {
            delay ??= TimeSpan.FromSeconds(1);

            var retryPolicy = Policy
                .Handle<Exception>()
                .WaitAndRetryAsync(
                    maxRetries,
                    attempt => delay.Value * attempt,
                    onRetry: (exception, timeSpan, retryCount, context) =>
                    {
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine($"🔁 重试 {retryCount}/{maxRetries}");
                        Console.ResetColor();
                    });

            return agent.RegisterMiddleware<IAgent>(async (msgs, options, nextAgent, ct) =>
            {
                return await retryPolicy.ExecuteAsync(
                    async () => await nextAgent.GenerateReplyAsync(msgs, options, ct));
            });
        }

        /// <summary>
        /// 仅注册超时策略
        /// </summary>
        public static MiddlewareAgent<IAgent> WithTimeout(
            this IAgent agent,
            TimeSpan timeout)
        {
            var timeoutPolicy = Policy.TimeoutAsync(timeout, TimeoutStrategy.Optimistic);

            return agent.RegisterMiddleware<IAgent>(async (msgs, options, nextAgent, ct) =>
            {
                return await timeoutPolicy.ExecuteAsync(
                    async () => await nextAgent.GenerateReplyAsync(msgs, options, ct));
            });
        }
    }
    #endregion
}
View Code
系统整体流量入口限流服务 - 处理高并发场景 创建和管理限流器	工厂(生产令牌桶)
using AutoGen.Core;
using Google.Cloud.Iam.V1;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.RateLimiting;
using System.Threading.Tasks;

namespace AutoGenLimit.Middleware
{

    #region 系统整体流量入口限流服务 - 处理高并发场景 创建和管理限流器    工厂(生产令牌桶)
    /// <summary>
    /// 系统整体/流量入口级限流服务【限制的同时允许多少人可以访问系统,令牌的补充机制】
    /// </summary>
    public class RateLimitingService
    {
        private readonly ConcurrentDictionary<string, RateLimiter> _limiters = new();
        private readonly int _tokenLimit;
        private readonly int _tokensPerPeriodCount;

        public RateLimitingService()
        {
            _tokenLimit = 5; 
            _tokensPerPeriodCount = 2;
        }

        public async Task<bool> TryAcquireAsync(string sessionId)
        {
            var limiter = _limiters.GetOrAdd(sessionId, _ =>
                new TokenBucketRateLimiter(new()
                {
                    TokenLimit = _tokenLimit,              // 桶容量
                    TokensPerPeriod = _tokensPerPeriodCount, // 每次补充数量
                    ReplenishmentPeriod = TimeSpan.FromSeconds(1), // 补充周期
                    QueueLimit = 5,                        // ✅ 队列上限:最多排 5 个请求
                    QueueProcessingOrder = QueueProcessingOrder.OldestFirst, // 先到先得
                    AutoReplenishment = true               // ✅ 自动补充:定时器自动补
                }));

            using var lease = await limiter.AcquireAsync(1);
            return lease.IsAcquired;
        }

        public RateLimiter GetLimiter(string sessionId)
        {
            return _limiters.GetOrAdd(sessionId, _ =>
                new TokenBucketRateLimiter(new()
                {
                    TokenLimit = _tokenLimit,
                    TokensPerPeriod = _tokensPerPeriodCount,
                    ReplenishmentPeriod = TimeSpan.FromSeconds(1),
                    QueueLimit = 5,
                    QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                    AutoReplenishment = true
                }));
        }

        public void RemoveLimiter(string sessionId)
        {
            if (_limiters.TryRemove(sessionId, out var limiter))
            {
                limiter.Dispose();
                Console.WriteLine($"[RateLimitingService] 移除 Session {sessionId} 的限流器");
            }
        }
    }
    #endregion


    #region 函数/工具级限流组件
    /// <summary>
    /// 函数/工具级限流中间件(扩展方法模式)
    /// </summary>
    public static class RateLimitMiddlewareExtensions
    {
        /// <summary>
        /// 注册工具调用限流中间件
        /// </summary>
        public static MiddlewareAgent<IAgent> WithRateLimiting(
            this IAgent agent,
            RateLimiter rateLimiter,
            string toolName)
        {
            return agent.RegisterMiddleware<IAgent>(async (msgs, options, nextAgent, ct) =>
            {
                // 检查消息中是否有工具调用
                var hasToolCall = msgs.Any(m =>
                    m is ToolCallMessage toolCallMsg &&
                    toolCallMsg.ToolCalls.Any(tc => tc.FunctionName == toolName));

                if (hasToolCall)
                {
                    // ✅ 修复:使用 AttemptAcquire 立即返回,不等待
                    using var lease = rateLimiter.AttemptAcquire(1);

                    if (!lease.IsAcquired)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine($"🚫 触发限流:{toolName}");
                        Console.ResetColor();

                        throw new RateLimitExceededException(
                            $"🚫 工具调用频率超限:{toolName}");
                    }

                    Console.ForegroundColor = ConsoleColor.DarkYellow;
                    Console.WriteLine($"🚦 限流通过:{toolName}");
                    Console.ResetColor();
                }

                return await nextAgent.GenerateReplyAsync(msgs, options, ct);
            });
        }

        /// <summary>
        /// 注册全局限流中间件(不限工具类型)
        /// </summary>
        public static MiddlewareAgent<IAgent> WithGlobalRateLimiting(
            this IAgent agent,
            RateLimiter rateLimiter)
        {
            return agent.RegisterMiddleware<IAgent>(async (msgs, options, nextAgent, ct) =>
            {
                using var lease = rateLimiter.AttemptAcquire(1);
                if (!lease.IsAcquired)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine($"🚫 触发全局限流");
                    Console.ResetColor();

                    throw new RateLimitExceededException("🚫 全局请求频率超限,请稍后重试");
                }

                return await nextAgent.GenerateReplyAsync(msgs, options, ct);
            });
        }
    }

    /// <summary>
    /// 限流异常
    /// </summary>
    public class RateLimitExceededException : Exception
    {
        public RateLimitExceededException(string message) : base(message)
        {
        }
    }
    #endregion
}
View Code
 注册时间戳中间件(记录响应时长)
using AutoGen.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AutoGenLimit.Middleware
{
    public static class TimestampLoggingMiddlewareExtensions
    {
        /// <summary>
        /// 注册时间戳中间件(记录响应时长)
        /// </summary>
        public static MiddlewareAgent<IAgent> WithTimestamp(this IAgent agent)
        {
            return agent.RegisterMiddleware<IAgent>(async (msgs, options, nextAgent, ct) =>
            {
                var timestampRequest = DateTime.Now;
                Console.ForegroundColor = ConsoleColor.Gray;
                Console.WriteLine($"[{timestampRequest:HH:mm:ss.fff}] ⬇️ {nextAgent.Name} 收到 {msgs.Count()} 条消息");
                Console.ResetColor();

                var response = await nextAgent.GenerateReplyAsync(msgs, options, ct);

                var timestampResponse = DateTime.Now;
                Console.ForegroundColor = ConsoleColor.Gray;
                Console.WriteLine($"[{timestampResponse:HH:mm:ss.fff}] ⬆️ {nextAgent.Name} 发送响应");
                Console.WriteLine($"    响应时长:{(timestampResponse - timestampRequest).TotalMilliseconds}ms");
                Console.ResetColor();

                return response;
            });
        }

        /// <summary>
        /// 注册日志中间件(写入日志文件)
        /// </summary>
        public static MiddlewareAgent<IAgent> WithLogging(
            this IAgent agent,
            string logFile = "agent_logs.txt")
        {
            return agent.RegisterMiddleware<IAgent>(async (msgs, options, nextAgent, ct) =>
            {
                var logEntry = new StringBuilder();
                logEntry.AppendLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] Agent: {nextAgent.Name}");
                logEntry.AppendLine($"  消息数量:{msgs.Count()}");

                var stopwatch = Stopwatch.StartNew();
                var response = await nextAgent.GenerateReplyAsync(msgs, options, ct);
                stopwatch.Stop();

                logEntry.AppendLine($"  响应耗时:{stopwatch.ElapsedMilliseconds}ms");
                logEntry.AppendLine(new string('-', 50));

                _ = Task.Run(async () => await File.AppendAllTextAsync(logFile, logEntry.ToString()));

                return response;
            });
        }

        /// <summary>
        /// 注册消息计数中间件(统计 Token)
        /// </summary>
        public static MiddlewareAgent<IAgent> WithMessageCount(this IAgent agent)
        {
            // ✅ 闭包变量在 lambda 外部初始化(累计统计)
            int totalMessages = 0;
            int totalTokens = 0;

            return agent.RegisterMiddleware<IAgent>(async (msgs, options, nextAgent, ct) =>
            {
                // ✅ 先拼接所有消息内容,再估算 Token
                var allContent = string.Join(" ", msgs.Select(m => m.GetContent()));
                var inputTokens = EstimateTokens(allContent);

                var response = await nextAgent.GenerateReplyAsync(msgs, options, ct);

                var outputTokens = EstimateTokens(response.GetContent());

                totalMessages++;
                totalTokens += inputTokens + outputTokens;

                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine($"📊 累计消息:{totalMessages} | 估算 Token: {totalTokens}");
                Console.ResetColor();

                return response;
            });
        }

        private static int EstimateTokens(string? content)
        {
            if (string.IsNullOrWhiteSpace(content)) return 0;
            var chineseChars = content.Count(c => c >= 0x4E00 && c <= 0x9FFF);
            var englishWords = content.Split(new[] { ' ', '\n', '\t' }, StringSplitOptions.RemoveEmptyEntries).Length;
            return chineseChars + englishWords;
        }
    }
}
View Code
用户会话、会话隔离核心工厂
using Applier;
using AutoGen;
using AutoGen.Core;
using AutoGen.OpenAI;
using AutoGen.OpenAI.Extension;
using AutoGenLimit.Middleware;
using Microsoft.Extensions.Configuration;
using OpenAI;
using System;
using System.ClientModel;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace AutoGenLimit
{
    #region 用户会话、会话隔离核心工厂
    /// <summary>
    /// GroupChat 工厂类 - 实现 Session 隔离
    /// 每 Session 独立的 GroupChatManager + Workflow + Agent 实例
    /// </summary>
    public class GroupChatFactory
    {
        private readonly ConcurrentDictionary<string, GroupChatManager> _managers = new();
        private readonly string _apiKey;
        private readonly string _endpoint;
        private readonly string _modelId;
        private readonly RateLimitingService _rateLimitingService;
        private readonly HttpClient _httpClient;
        private readonly string _amapApiKey;

        public GroupChatFactory( 
            RateLimitingService rateLimitingService)
        {
            _apiKey = ConstParm.apiKey;
            _endpoint = ConstParm.endpoint;
            _modelId = ConstParm.modelId ?? "qwen-plus";
            _rateLimitingService = rateLimitingService;
            _httpClient = new HttpClient();
            _amapApiKey = ConstParm.amapApiKey!;

            Console.WriteLine("✅ GroupChatFactory 初始化完成");
            Console.WriteLine($"   使用模型:{_modelId}");
        }

        /// <summary>
        /// 获取或创建 GroupChatManager(自动创建 Workflow)
        /// </summary>
        public GroupChatManager GetOrCreateGroupChat(string sessionKey)
        {
            return _managers.GetOrAdd(sessionKey, key =>
            {
                Console.WriteLine($"[GroupChatFactory] Creating GroupChat for Session: {key}");

                // ① 创建每 Session 独立的 Agent
                var userAgent = CreateUserAgent(key);
                var weatherAgent = CreateWeatherAgent(key);
                var plannerAgent = CreatePlannerAgent(key);
                var budgetAgent = CreateBudgetAgent(key);

                // ② 定义 Workflow(固定业务流程)
                var workflow = new Graph();
                workflow.AddTransition(Transition.Create(userAgent, weatherAgent));
                workflow.AddTransition(Transition.Create(weatherAgent, plannerAgent));
                workflow.AddTransition(Transition.Create(plannerAgent, budgetAgent));
                workflow.AddTransition(Transition.Create(budgetAgent, userAgent));

                // ③ 创建 GroupChat
                var groupChat = new GroupChat(
                    members: new[] { userAgent, weatherAgent, plannerAgent, budgetAgent },
                    workflow: workflow);

                return new GroupChatManager(groupChat);
            });
        }

        /// <summary>
        /// 移除 Session 的 GroupChat(清理资源)
        /// </summary>
        public void RemoveGroupChat(string sessionKey)
        {
            if (_managers.TryRemove(sessionKey, out _))
            {
                Console.WriteLine($"[GroupChatFactory] Removed GroupChat for Session: {sessionKey}");
            }
        }

        #region Agent 创建方法

        /// <summary>
        /// 创建用户代理(Human-in-the-loop)
        /// </summary>
        private IAgent CreateUserAgent(string sessionKey)
        {
            var userProxy = new UserProxyAgent(
                name: $"User-{sessionKey}",
                humanInputMode: HumanInputMode.NEVER);

            return userProxy
                .RegisterPrintMessage();  // ✅ 返回 MiddlewareAgent<IAgent>,隐式转换为 IAgent
        }

        /// <summary>
        /// 创建天气查询 Agent(带限流 + Polly)
        /// </summary>
        private IAgent CreateWeatherAgent(string sessionKey)
        {
            // 获取该 Session 的限流器(每 Session 独立)
            var limiter = _rateLimitingService.GetLimiter(sessionKey);

            var client = new OpenAIClient(
                new ApiKeyCredential(_apiKey),
                new OpenAIClientOptions
                {
                    Endpoint = new Uri(_endpoint)
                });

            var weatherTool = new WeatherTool(_httpClient, _amapApiKey);

            var functionContract = new FunctionContract
            {
                Name = "GetWeatherAsync",
                Description = "获取指定城市的实时天气信息",
                Parameters = new List<FunctionParameterContract>
            {
                new FunctionParameterContract
                {
                    Name = "city",
                    Description = "城市名称,如:北京、上海",
                    IsRequired = true,
                    ParameterType = typeof(string)
                }
            }
            };

            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!);
                }
            }
        };

            var functionCallMiddleware = new FunctionCallMiddleware(
                functions: new[] { functionContract },
                functionMap: functionMap);

            var agent = new OpenAIChatAgent(
                name: $"WeatherAgent-{sessionKey}",
                systemMessage: "你是专业天气预报分析师。当用户询问天气时,必须调用 GetWeatherAsync 函数获取真实数据。",
                chatClient: client.GetChatClient(_modelId));

            // ✅ 链式注册中间件(限流 + Polly)
            return agent
                .RegisterMessageConnector()
                .RegisterMiddleware(functionCallMiddleware)
                .WithRateLimiting(limiter, "GetWeatherAsync")  // ⭐ L3 工具限流
                .WithPolly(maxRetries: 3, timeoutSeconds: 30)   // ⭐ L5 Polly 策略
                .RegisterPrintMessage();
        }

        /// <summary>
        /// 创建行程规划 Agent
        /// </summary>
        private IAgent CreatePlannerAgent(string sessionKey)
        {
            var limiter = _rateLimitingService.GetLimiter(sessionKey);

            var client = new OpenAIClient(
                new ApiKeyCredential(_apiKey),
                new OpenAIClientOptions
                {
                    Endpoint = new Uri(_endpoint)
                });

            var plannerTool = new TravelPlannerTool();

            var functionContract = new FunctionContract
            {
                Name = "PlanTravel",
                Description = "根据天气情况推荐旅游行程",
                Parameters = new List<FunctionParameterContract>
            {
                new FunctionParameterContract
                {
                    Name = "city",
                    Description = "城市名称",
                    IsRequired = true,
                    ParameterType = typeof(string)
                },
                new FunctionParameterContract
                {
                    Name = "weather",
                    Description = "天气状况",
                    IsRequired = true,
                    ParameterType = typeof(string)
                },
                new FunctionParameterContract
                {
                    Name = "temperature",
                    Description = "温度(摄氏度)",
                    IsRequired = true,
                    ParameterType = typeof(int)
                }
            }
            };

            var functionMap = new Dictionary<string, Func<string, Task<string>>>
        {
            {
                functionContract.Name,
                async (args) =>
                {
                    var json = JsonDocument.Parse(args);
                    var city = json.RootElement.GetProperty("city").GetString();
                    var weather = json.RootElement.GetProperty("weather").GetString();
                    var temperature = json.RootElement.GetProperty("temperature").GetInt32();
                    return plannerTool.PlanTravel(city!, weather!, temperature);
                }
            }
        };

            var functionCallMiddleware = new FunctionCallMiddleware(
                functions: new[] { functionContract },
                functionMap: functionMap);

            var agent = new OpenAIChatAgent(
                name: $"PlannerAgent-{sessionKey}",
                systemMessage: "你是专业旅游规划师。根据天气情况推荐合适的行程。",
                chatClient: client.GetChatClient(_modelId));

            return agent
                .RegisterMessageConnector()
                .RegisterMiddleware(functionCallMiddleware)
                .WithRateLimiting(limiter, "PlanTravel")
                .WithPolly(maxRetries: 3, timeoutSeconds: 30)
                .RegisterPrintMessage();
        }

        /// <summary>
        /// 创建预算评估 Agent
        /// </summary>
        private IAgent CreateBudgetAgent(string sessionKey)
        {
            var limiter = _rateLimitingService.GetLimiter(sessionKey);

            var client = new OpenAIClient(
                new ApiKeyCredential(_apiKey),
                new OpenAIClientOptions
                {
                    Endpoint = new Uri(_endpoint)
                });

            var budgetTool = new BudgetCalculatorTool();

            var functionContract = new FunctionContract
            {
                Name = "CalculateBudget",
                Description = "计算旅行预算(交通 + 门票 + 餐饮)",
                Parameters = new List<FunctionParameterContract>
            {
                new FunctionParameterContract
                {
                    Name = "city",
                    Description = "城市名称",
                    IsRequired = true,
                    ParameterType = typeof(string)
                },
                new FunctionParameterContract
                {
                    Name = "days",
                    Description = "游玩天数",
                    IsRequired = true,
                    ParameterType = typeof(int)
                },
                new FunctionParameterContract
                {
                    Name = "people",
                    Description = "人数",
                    IsRequired = true,
                    ParameterType = typeof(int)
                }
            }
            };

            var functionMap = new Dictionary<string, Func<string, Task<string>>>
        {
            {
                functionContract.Name,
                async (args) =>
                {
                    var json = JsonDocument.Parse(args);
                    var city = json.RootElement.GetProperty("city").GetString();
                    var days = json.RootElement.GetProperty("days").GetInt32();
                    var people = json.RootElement.GetProperty("people").GetInt32();
                    return budgetTool.CalculateBudget(city!, days, people);
                }
            }
        };

            var functionCallMiddleware = new FunctionCallMiddleware(
                functions: new[] { functionContract },
                functionMap: functionMap);

            var agent = new OpenAIChatAgent(
                name: $"BudgetAgent-{sessionKey}",
                systemMessage: "你是专业预算评估师。计算旅行的交通、门票、餐饮费用。",
                chatClient: client.GetChatClient(_modelId));

            return agent
                .RegisterMessageConnector()
                .RegisterMiddleware(functionCallMiddleware)
                .WithRateLimiting(limiter, "CalculateBudget")
                .WithPolly(maxRetries: 3, timeoutSeconds: 30)
                .RegisterPrintMessage();
        }

        #endregion
    }
    #endregion
}
View Code
并发控制器(L2 系统并发控制)
全局信号量,限制同时执行的请求数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AutoGenLimit
{
    /// <summary>
    /// 并发控制器(L2 系统并发控制)
    /// 全局信号量,限制同时执行的请求数
    /// </summary>
    public static class ConcurrencyController
    {
        private static readonly SemaphoreSlim _semaphore = new(5, 5);
        private static int _currentCount = 0;

        /// <summary>
        /// 执行带并发限制的操作(无返回值)
        /// </summary>
        public static async Task ExecuteWithLimitAsync(Func<Task> action)  // ✅ 无返回值版本
        {
            await _semaphore.WaitAsync();
            var newCount = Interlocked.Increment(ref _currentCount);

            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine($"[并发控制] 进入请求,当前并发:{newCount}/5");
            Console.ResetColor();

            try
            {
                await action();
            }
            finally
            {
                var remainingCount = Interlocked.Decrement(ref _currentCount);
                _semaphore.Release();

                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine($"[并发控制] 释放请求,当前并发:{remainingCount}/5");
                Console.ResetColor();
            }
        }

        /// <summary>
        /// 执行带并发限制的操作(有返回值)
        /// </summary>
        public static async Task<T> ExecuteWithLimitAsync<T>(Func<Task<T>> action)
        {
            await _semaphore.WaitAsync();
            var newCount = Interlocked.Increment(ref _currentCount);

            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine($"[并发控制] 进入请求,当前并发:{newCount}/5");
            Console.ResetColor();

            try
            {
                return await action();
            }
            finally
            {
                var remainingCount = Interlocked.Decrement(ref _currentCount);
                _semaphore.Release();

                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine($"[并发控制] 释放请求,当前并发:{remainingCount}/5");
                Console.ResetColor();
            }
        }

        public static int GetCurrentConcurrency() => _currentCount;
        public static int GetAvailableSlots() => 5 - _currentCount;
    }
}
View Code

工具 functionCall

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace AutoGenLimit
{
    /// <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);
        }
    }


    public class BudgetCalculatorTool
    {
        // ✅ 提取为静态常量
        private static readonly string[] FirstTierCities =
        {
        "北京", "上海", "广州", "深圳"
    };

        private static readonly int BaseMinBudget = 300;   // 基础最低预算/人/天
        private static readonly int BaseMaxBudget = 1000;  // 基础最高预算/人/天
        private static readonly int FirstTierMinBudget = 500;   // 一线城市最低预算
        private static readonly int FirstTierMaxBudget = 1500;  // 一线城市最高预算

        public string CalculateBudget(string city, int days, int people)
        {
            // ✅ 使用 LINQ 判断
            var isFirstTier = FirstTierCities.Any(city.Contains);

            var minBudget = isFirstTier ? FirstTierMinBudget : BaseMinBudget;
            var maxBudget = isFirstTier ? FirstTierMaxBudget : BaseMaxBudget;

            var minMoney = people * days * minBudget;
            var maxMoney = people * days * maxBudget;

            return $"大约花费{minMoney}~{maxMoney}元";
        }
    }
}
View Code

Main.cs

using AutoGen;
using AutoGen.Core;
using AutoGenLimit.Middleware;
using Microsoft.Extensions.Configuration;

namespace AutoGenLimit
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.OutputEncoding = System.Text.Encoding.Unicode;
            Console.InputEncoding = System.Text.Encoding.Unicode;

            Console.WriteLine("🤖 AutoGen Workflow 多 Agent 协作系统 - 高并发限流版");
            Console.WriteLine("=====================================================\n");

            

            // ② 初始化 L1 入口限流服务(令牌桶)
            var rateLimitingService = new RateLimitingService();
            Console.WriteLine($"✅ RateLimitingService 初始化完成"); 

            // ③ 初始化 L3 Session 隔离工厂
            var groupChatFactory = new GroupChatFactory(rateLimitingService);

            Console.WriteLine("========================================");
            Console.WriteLine("🌍 旅行咨询智能体已就绪!");
            Console.WriteLine("💬 输入旅行计划,如:");
            Console.WriteLine(" - 我想明天去北京玩 3 天,有什么建议?");
            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;
                }

                // ⑤ 生成 Session ID(每用户独立)
                var sessionId = Guid.NewGuid().ToString("N")[..8];  // 8 位短 ID

                Console.WriteLine($"[Session] {sessionId}\n");

                try
                {
                    // ⑥ L1 入口限流检查
                    if (!await rateLimitingService.TryAcquireAsync(sessionId))
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("🚫 限流:请求太多,请稍后重试");
                        Console.ResetColor();
                        continue;
                    }

                    // ⑦ L2 并发控制执行
                    // L2 并发控制执行
                    await ConcurrencyController.ExecuteWithLimitAsync(async () =>
                    {
                        var groupChatManager = groupChatFactory.GetOrCreateGroupChat(sessionId);

                        Console.WriteLine("\n🔄 智能体正在协作处理...\n");

                        var userProxy = new UserProxyAgent(
                            name: $"User-{sessionId}",
                            humanInputMode: HumanInputMode.NEVER);

                        var chatHistory = new List<IMessage>
                            {
                                new TextMessage(Role.User, input, from: $"User-{sessionId}")
                            };

                        var response = await userProxy.InitiateChatAsync(
                            receiver: groupChatManager,
                            message: input,
                            maxRound: 4);

                        Console.WriteLine("\n========================================");
                        Console.WriteLine("💬 对话记录:");
                        Console.WriteLine("========================================\n");

                        foreach (var message in response)
                        {
                            Console.WriteLine($"【{message.From}】: {message.GetContent()}\n");
                        }

                        Console.WriteLine("\n✅ 处理完成\n");
                    });
                }
                catch (RateLimitExceededException ex)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine($"🚫 限流异常:{ex.Message}\n");
                    Console.ResetColor();
                }
                catch (Exception ex)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine($"❌ 异常:{ex.Message}\n");
                    Console.ResetColor();
                }
            }
        }
    }
}
View Code
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>
 

    <ItemGroup>
        <Compile Include="..\..\openClawTest\ConsoleApp1\ConstParm.cs" Link="ConstParm.cs" />
    </ItemGroup>

    <ItemGroup>
        <PackageReference Include="AutoGen" Version="0.2.3" />
        <PackageReference Include="AutoGen.OpenAI" Version="0.2.3" />
        <PackageReference Include="Polly" Version="8.4.0" />
        <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
        <PackageReference Include="System.Threading.RateLimiting" Version="8.0.0" />
        <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
        <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
    </ItemGroup>

</Project>
 

 

posted @ 2026-08-19 11:00  天才卧龙  阅读(3)  评论(0)    收藏  举报