AutoGen 自由对话 及 标准模式对话(限定次数/轮次)-含中间件/响应时长、日志、Token 估算

🎯 核心功能

1️⃣ 两种对话模式

模式方法特点
自由选择模式 GenerateReplyAsync 手动管理历史,可导出记录
标准模式 InitiateChatAsync 自动管理历史,多轮对话

2️⃣ 三个中间件

中间件作用
WithTimestamp 记录请求/响应时间
WithLogging 写入日志文件
WithMessageCount 统计消息数和 Token

3️⃣ Agent 工厂

统一创建和管理 Agent,封装配置细节。


📚 核心知识点

1️⃣ 中间件机制

// 洋葱模型
agent
  .WithTimestamp()      // 外层
  .WithLogging()        // 中层
  .WithMessageCount();  // 内层

// 执行顺序:LIFO(后进先出)
请求 → MessageCount → Logging → Timestamp → Agent 核心

2️⃣ 委托签名

Func<
    IEnumerable<IMessage>,      // 消息列表
    GenerateReplyOptions?,      // 选项
    IAgent,                     // 下一个 Agent
    CancellationToken,          // 取消令牌
    Task<IMessage>              // 返回值
>

3️⃣ 调用链

var response = await nextAgent.GenerateReplyAsync(msgs, options, ct);
// ↑ 这行代码调用下一个中间件/核心 Agent

4️⃣ 扩展方法

public static MiddlewareAgent<IAgent> WithTimestamp(this IAgent agent)
{
    return agent.RegisterMiddleware(async (msgs, options, nextAgent, ct) =>
    {
        // 中间件逻辑
    });
}

🎯 学习收获

知识点掌握程度
中间件注册机制 ⭐⭐⭐⭐⭐
委托签名理解 ⭐⭐⭐⭐⭐
调用链原理 ⭐⭐⭐⭐⭐
扩展方法设计 ⭐⭐⭐⭐
Agent 类型区别 ⭐⭐⭐⭐
多轮对话管理 ⭐⭐⭐⭐

 项目代码

main

using AutoGen;
using AutoGen.Core;

namespace ConsoleApp2
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            // 👇 修复控制台编码(必须在第一行!)-- 在控制台输入的内容,传到千问可能乱码
            Console.OutputEncoding = System.Text.Encoding.Unicode;
            Console.InputEncoding = System.Text.Encoding.Unicode;
            Console.WriteLine("🤖 AutoGen 第 2 课实战");
            Console.WriteLine("==============================================\n");

            Console.WriteLine("选择模式:");
            Console.WriteLine("1 - 自由选择 Agent(学习模式)");
            Console.WriteLine("2 - 人机对话(标准模式)");
            Console.WriteLine("0 - 退出\n");

            var mode = Console.ReadLine();

            if (mode == "1")
            {
                await RunFreeMode();
            }
            else if (mode == "2")
            {
                await RunStandardMode();
            }
            else
            {
                Console.WriteLine("👋 再见!");
            }
        }

        // 自由选择模式
        static async Task RunFreeMode()
        {
            var factory = new AgentFactory();
            var openAIAgent = factory.CreateOpenAIChatAgent()
                .WithTimestamp()
                .WithLogging()
                .WithMessageCount();

            // ✅ history 在循环外创建
            var history = new List<IMessage>();

            Console.WriteLine("\n🤖 AutoGen 第 2 课实战 - 简单对话");
            Console.WriteLine("==============================================");
            Console.WriteLine("输入 'exit' 或 '退出' 结束对话\n");

            while (true)
            {
                Console.Write("你:");
                var userInput = Console.ReadLine();

                if (string.IsNullOrWhiteSpace(userInput))
                    continue;

                if (userInput.ToLower() == "exit" || userInput == "退出")
                {
                    Console.WriteLine("👋 再见!");
                    break;
                }

                var userMessage = new TextMessage(Role.User, userInput, from: "user");
                history.Add(userMessage);

                var response = await openAIAgent.GenerateReplyAsync(
                    messages: history,
                    cancellationToken: CancellationToken.None);

                history.Add(response);

                //Console.WriteLine($"\n小助手:{response.GetContent()}\n");
            }
        }

        // 标准模式(InitiateChatAsync)
        static async Task RunStandardMode()
        {
            var factory = new AgentFactory();
             
            var userProxyAgent = factory.CreateUserProxyAgent();

            var openAIAgent = factory.CreateOpenAIChatAgent()
                .WithTimestamp()
                .WithLogging()
                .WithMessageCount();

            Console.WriteLine("\n🤖 人机对话模式 - 最多 5 轮");
            Console.WriteLine("==============================================\n");

            var rs = await userProxyAgent.InitiateChatAsync(
         receiver: openAIAgent,
         message: "你好,请介绍一下你自己",  //默认的message不算一次
         maxRound: 5);//最多问答5次,六爷提问+1,小助手回答+1

            // ✅ 带轮次编号
            int round = 0;
            foreach (var item in rs)
            {
                var content = item?.GetContent();
                if (item.From == "六爷")
                {
                    round++;
                    Console.WriteLine($"\n📍 第{round}轮 - 六爷问了:{content}");
                }
                if (item.From == "小助手")
                { 
                    Console.WriteLine($"\n📍 第{round}轮 - 小助手回复:{content}");
                }
            }

            Console.WriteLine("\n✅ 5轮对话结束!");
        }
    }
}

中间件

using AutoGen.Core;
using Google.Protobuf.WellKnownTypes;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace ConsoleApp2
{ 
    /// <summary>
    /// Agent 中间件扩展方法
    /// </summary>
    public static class AgentMiddlewareExtensions
    {
        /// <summary>
        /// 注册时间戳中间件
        /// </summary>
        public static MiddlewareAgent<IAgent> WithTimestamp(this IAgent agent)
        {
            var middlewareAgent = agent.RegisterMiddleware<IAgent>(async (msgs, options, nextAgent, ct) =>
            {
                var timestampRequest = DateTime.Now;

                // 前置处理
                //Console.ForegroundColor = ConsoleColor.Gray;
                //Console.WriteLine($"[{timestampRequest.ToString("HH:mm:ss.fff")}] ⬇️  {nextAgent.Name} 收到 {msgs.Count()} 条消息");
                //Console.ResetColor();

                // 调用下一个中间件(核心:调用 nextAgent 就是继续执行链)
                var response = await nextAgent.GenerateReplyAsync(msgs, options, ct);

                // 后置处理
                var timestampResponse = DateTime.Now;
                Console.ForegroundColor = ConsoleColor.Gray;
                //Console.WriteLine($"[{timestampResponse.ToString("HH:mm:ss.fff")}] ⬆️  {nextAgent.Name} 发送响应");

                 Console.WriteLine($"响应时长:{(timestampResponse - timestampRequest).TotalSeconds}秒。");
                Console.ResetColor();

                return response;
            });
            return middlewareAgent;
        }

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

                var stopwatch = System.Diagnostics.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>
        /// 注册消息计数中间件
        /// </summary>
        public static MiddlewareAgent<IAgent> WithMessageCount(this IAgent agent)
        {
            // 注意:闭包变量,用于累计统计
            int totalMessages = 0;
            int totalTokens = 0;

            return agent.RegisterMiddleware(async (msgs, options, nextAgent, ct) =>
            {
                var inputTokens = msgs.Sum(m => EstimateTokens(m.GetContent()));

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

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

                totalMessages++;
                totalTokens += inputTokens + outputTokens;
 

                return response;
            });
        }

        /// <summary>
        /// Token 估算(中文按字,英文按词)
        /// </summary>
        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;
        }
    }
}

Agent工厂

using Applier;
using AutoGen;
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.Threading.Tasks;

namespace ConsoleApp2
{

    /// <summary>
    /// Agent 工厂类 - 统一创建和管理 Agent
    /// 参考博客:https://www.cnblogs.com/chenwolong/p/22527694
    /// </summary> 
    public class AgentFactory
    {
        private readonly OpenAIClient _client;

        public AgentFactory()
        {
            // ① 创建 OpenAI 客户端(兼容阿里云百炼)
            _client = new OpenAIClient(
                new ApiKeyCredential(ConstParm.apiKey),
                new OpenAIClientOptions
                {
                    Endpoint = new Uri(ConstParm.endpoint)
                });

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

        /// <summary>
        /// 创建 OpenAIChatAgent(调用 LLM)
        /// 用途:核心对话 Agent,负责调用大模型
        /// </summary>
        public IAgent CreateOpenAIChatAgent(
            string systemMessage = "你是一个热情友好的 AI 助手,用中文回答用户问题",
            string agentName = "小助手")
        {
            Console.WriteLine($"🔧 创建 OpenAIChatAgent: {agentName}");

            var agent = new OpenAIChatAgent(
                name: agentName,
                systemMessage: systemMessage,
                chatClient: _client.GetChatClient(ConstParm.modelId));

            // ✅ OpenAIChatAgent 使用专属的 RegisterMessageConnector
            return agent
                   .RegisterMessageConnector()
            .RegisterPrintMessage(); 
        }

        /// <summary>
        /// 创建 UserProxyAgent(人工介入)
        /// 用途:人机交互接口,等待用户输入
        /// </summary>
        public IAgent CreateUserProxyAgent(
            string agentName = "六爷",
            HumanInputMode humanInputMode = HumanInputMode.ALWAYS)
        {
            Console.WriteLine($"🔧 创建 UserProxyAgent: {agentName} (模式:{humanInputMode})");

            var agent = new UserProxyAgent(
                name: agentName,
                humanInputMode: humanInputMode,
                defaultReply: "");

            // ✅ UserProxyAgent 不需要 RegisterMessageConnector,直接用 RegisterPrintMessage
            return agent.RegisterPrintMessage(); 
        }

        
    }


    /// <summary>
    /// Agent 类型枚举
    /// 用于工厂方法模式创建不同类型的 Agent
    /// </summary>
    public enum AgentType
    {
        /// <summary>
        /// OpenAIChatAgent - 调用 LLM
        /// </summary>
        OpenAIChat,

        /// <summary>
        /// UserProxyAgent - 人工介入
        /// </summary>
        UserProxy,

        /// <summary>
        /// AssistantAgent - 通用助手
        /// </summary>
        Assistant
    }
}

项目引用

<Project Sdk="Microsoft.NET.Sdk">

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

    <ItemGroup>
      <Compile Remove="ConversationHistory.cs" />
    </ItemGroup>

    <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" />
    </ItemGroup>

</Project>

 

posted @ 2026-08-18 14:38  天才卧龙  阅读(6)  评论(0)    收藏  举报