Ai Agent 协调者模式 = 一个大脑(Coordinator)+ 四个手脚(Branch Agents)

🎯 一、核心原理

一句话总结

协调者模式 = 一个大脑(Coordinator)+ 四个手脚(Branch Agents)

用户输入 → 协调者分析 → 路由决策 → 分支 Agent 执行 → 返回结果

📐 二、架构图

┌─────────────────────────────────────────────────────────────┐
│                      用户输入层                              │
│                    (User Input)                              │
└─────────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────┐
│                   协调者服务层                               │
│                (CoordinatorService)                          │
│  ┌─────────────────────────────────────────────────────┐   │
│  │              CoordinatorAgentFactory                 │   │
│  │  ┌─────────────────────────────────────────────┐   │   │
│  │  │         协调者 Agent (Coordinator)           │   │   │
│  │  │  - SystemMessage: 角色定义 + Few-Shot 示例    │   │   │
│  │  │  - FunctionCall: RouteToBranch 函数契约      │   │   │
│  │  │  - JSON Schema: 输出格式约束                 │   │   │
│  │  └─────────────────────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘
                            ↓
                    ┌───────────────┐
                    │  路由决策解析  │
                    │  - next_agent │
                    │  - reason     │
                    │  - params     │
                    └───────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────┐
│                   分支 Agent 层                              │
│                  (Branch Agents)                             │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │  FETCH   │  │ ANALYZE  │  │ RESPOND  │  │  TRACK   │   │
│  │ 查询投诉  │  │ 分析优先级│  │ 生成回复  │  │ 跟踪完成  │   │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘   │
└─────────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────┐
│                     执行结果层                               │
│                   (Execution Result)                         │
└─────────────────────────────────────────────────────────────┘

🔄 三、时序图

用户     CoordinatorService    Coordinator    BranchAgent
 │              │                   │              │
 │──输入请求───→│                   │              │
 │              │                   │              │
 │              │──创建协调者─────→│              │
 │              │                   │              │
 │              │──分析意图───────→│              │
 │              │                   │              │
 │              │←─返回决策─────────│              │
 │              │   {next_agent,    │              │
 │              │    reason, params}│              │
 │              │                   │              │
 │              │──解析决策         │              │
 │              │                   │              │
 │              │──创建分支 Agent─────────────────→│
 │              │                   │              │
 │              │──执行任务───────────────────────→│
 │              │                   │              │
 │              │←─返回结果────────────────────────│
 │              │                   │              │
 │←─最终结果────│                   │              │
 │              │                   │              │

 核心代码

1、协调者工厂

协调者工厂的核心作用为:根据用户输入的语义,动态创建并选择某一个智能体,在协调者创建的过程中,我们需要明确协调者能够路由的智能体,且告知协调者下一个Agent是什么,以及选择下一个Agnet的原因!

using AutoGen.Core;
using AutoGen.OpenAI;
using AutoGen.OpenAI.Extension;
using CoordinatorS;
using OpenAI;
using OpenAI.Chat;
using System;
using System.ClientModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    /// <summary>
    /// 协调者 Agent 工厂(Function Calling + JSON Schema)
    /// </summary>
    public class CoordinatorAgentFactory
    {
        private readonly ChatClient _chatClient;
        private readonly string _systemMessage;
        private readonly ChatResponseFormat _jsonSchemaFormat;
        private readonly ComplaintTools _complaintTools;  // ✅ 字段

        public CoordinatorAgentFactory(string apiKey, string endpoint, string modelId)
        {
            var client = new OpenAIClient(new ApiKeyCredential(apiKey),
             new OpenAIClientOptions
             {
                 Endpoint = new Uri(endpoint)
             });

            _chatClient = client.GetChatClient(modelId);
            _complaintTools = new ComplaintTools();
            // ① 自动生成 SystemMessage
            _systemMessage = BuildSystemMessage();

            // ② 自动生成 JSON Schema
            var jsonSchema = JsonSchemaGenerator.BuildRouteToBranchSchema();

            // ✅ 修正:参数名是 jsonSchemaFormatName,不是 name
            _jsonSchemaFormat = ChatResponseFormat.CreateJsonSchemaFormat(
                jsonSchemaFormatName: "coordinator_decision",
                jsonSchema: BinaryData.FromString(jsonSchema),
                jsonSchemaFormatDescription: "协调者路由决策输出格式",
                jsonSchemaIsStrict: true);

            //Console.WriteLine("✅ CoordinatorAgentFactory 初始化完成");
            //Console.WriteLine($"系统消息长度:{_systemMessage.Length} 字符");
            //Console.WriteLine($"JSON Schema:\n{jsonSchema}");
        }

        /// <summary>
        /// 构建 SystemMessage
        /// </summary>
        private string BuildSystemMessage()
        {
            var sb = new StringBuilder();

            sb.AppendLine("你是协调者,负责分析用户意图并路由到合适的分支 Agent。");
            sb.AppendLine();
            sb.AppendLine(JsonSchemaGenerator.BuildAgentListDescription());
            sb.AppendLine();
            sb.AppendLine(JsonSchemaGenerator.BuildFewShotPrompt());
            sb.AppendLine();
            sb.AppendLine("【输出要求】");
            sb.AppendLine("1. 必须调用 RouteToBranch 函数");
            sb.AppendLine($"2. next_agent: 从 [{string.Join(", ", AgentConfigs.All.Select(a => $@"""{a.Code}"""))}] 中选择一个"); 
            sb.AppendLine();
            sb.AppendLine("现在请分析用户输入,调用 RouteToBranch 函数:");

            return sb.ToString();
        }

        /// <summary>
        /// 创建协调者 Agent
        /// </summary>
        public IAgent CreateCoordinator()
        {
            Console.WriteLine("🔧 创建协调者 Agent...");

            // 创建 Agent(传入 JSON Schema 约束输出)
            var agent = new OpenAIChatAgent(
                name: "Coordinator",
                systemMessage: _systemMessage,
                chatClient: _chatClient,
                responseFormat: _jsonSchemaFormat)
                .RegisterMessageConnector()
                .RegisterPrintMessage();

            Console.WriteLine("✅ 协调者 Agent 创建完成");
            return agent;
        }

        /// <summary>
        /// 创建分支 Agent
        /// </summary>
        public IAgent CreateBranchAgent(string code)
        {
            return BranchAgents.Create(code, _chatClient, _complaintTools);
        }
    }

    /// <summary>
    /// JSON Schema 生成器(用于约束协调者输出)
    /// </summary>
    public static class JsonSchemaGenerator
    {
        /// <summary>
        /// 生成 RouteToBranch 函数的 JSON Schema
        /// </summary>
        public static string BuildRouteToBranchSchema()
        {
            // 从配置中提取所有 Agent Code
            var agentCodes = AgentConfigs.All.Select(a => $@"""{a.Code}""");
            var agentCodesEnum = string.Join(", ", agentCodes);

            return $$"""
            {
              "type": "object",
              "required": ["next_agent", "reason"],
              "properties": {
                "next_agent": {
                  "type": "string",
                  "enum": [{{agentCodesEnum}}],
                  "description": "下一个要调用的 Agent 代码,必须是以下之一:{{string.Join(", ", AgentConfigs.All.Select(a => a.Code))}}"
                } ,
                "reason": {
                  "type": "string",
                  "maxLength": 100,
                  "description": "路由原因(20 字以内)"
                }
              },
              "additionalProperties": false
            }
            """;
        }

        /// <summary>
        /// 生成 Few-Shot Prompt(从配置的 Examples 自动生成)
        /// </summary>
        public static string BuildFewShotPrompt()
        {
            var sb = new StringBuilder();

            sb.AppendLine("【示例】");
            sb.AppendLine("────────────────────────────────────────");

            foreach (var config in AgentConfigs.All)
            {
                foreach (var example in config.Examples)
                {
                    sb.AppendLine($"用户:\"{example.UserInput}\"");
                    //这里指定下一个Agent
                    sb.AppendLine($"助手:RouteToBranch(next_agent=\"{example.TargetAgentCode}\", reason=\"{example.Reason}\"");
                    sb.AppendLine("────────────────────────────────────────");
                }
            }

            return sb.ToString();
        }

        /// <summary>
        /// 生成 Agent 列表描述
        /// </summary>
        public static string BuildAgentListDescription()
        {
            var sb = new StringBuilder();

            sb.AppendLine("【可用分支 Agent】");
            foreach (var config in AgentConfigs.All)
            {
                sb.AppendLine($"- {config.Code} ({config.Name}): {config.Description}");
            }

            return sb.ToString();
        }
    }
}
View Code

2、分支Agent

 2.1、AgentConfig

using AutoGen.Core;
using AutoGen.OpenAI;
using AutoGen.OpenAI.Extension;
using Microsoft.Extensions.AI;
using OpenAI;
using System;
using System.ClientModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoordinatorS
{
    /// <summary>
    /// Agent Code 枚举(全大写)
    /// </summary>
    public enum AgentCodeEnum
    {
        /// <summary>
        /// 查询投诉列表Agent Code
        /// </summary>
        查询投诉,

        /// <summary>
        /// 投诉内容分析专家智能体 Code
        /// </summary>
        分析投诉,
        /// <summary>
        /// Agent自动回复投诉智能体 Code
        /// </summary>
        回复投诉,
        /// <summary>
        /// 完结/跟踪投诉智能体 Code
        /// </summary>
        完结投诉
    }

    /// <summary>
    /// Agent 配置
    /// </summary>
    public class AgentConfig
    {
        /// <summary>
        /// Agent 代码(必须是大写字母,用于 JSON Schema enum)
        /// </summary>
        public string Code { get; set; } = "";

        /// <summary>
        /// Agent 名称(人类可读,可以和 Code 不同)
        /// </summary>
        public string Name { get; set; } = "";

        /// <summary>
        /// 职责描述
        /// </summary>
        public string Description { get; set; } = "";

        /// <summary>
        /// Agent 的 SystemMessage
        /// </summary>
        public string SystemMessage { get; set; } = "";

        /// <summary>
        /// 调用函数的相关描述
        /// </summary>
        public FunctionCallExample[] Examples { get; set; } = Array.Empty<FunctionCallExample>(); 
    }

    /// <summary>
    /// Function Calling 示例
    /// </summary>
    public class FunctionCallExample
    {
        /// <summary>
        /// 用户输入
        /// </summary>
        public string UserInput { get; set; } = "";

        /// <summary>
        /// 期望的路由 Agent 代码
        /// </summary>
        public string TargetAgentCode { get; set; } = "";

        public string Reason { get; set; } = "";
    }

    /// <summary>
    /// 所有 Agent 配置(加新 Agent 在这里改)
    /// </summary>
    public static class AgentConfigs
    {
        public static readonly List<AgentConfig> All = new()
        {
            new AgentConfig
            {
                Code = AgentCodeEnum.查询投诉.ToString(),
                Name = "ComplaintFetcher",
                Description = "查询投诉列表",
                SystemMessage = @"你是投诉查询助手,负责查询待处理的投诉列表。

【职责】
1. 调用 GetPendingComplaints 查询指定日期范围内的待处理投诉
2. 只返回 PENDING 状态的投诉单
3. 日期格式:YYYY-MM-DD,查询范围最大 30 天",
                Examples = new[]
                {
                    new FunctionCallExample
                    {
                        UserInput = "帮我查一下最近 7 天的投诉",
                        TargetAgentCode = AgentCodeEnum.查询投诉.ToString(),//当用户类似这种描述时,对应的智能体 
                        Reason = "用户需要查询近一周的投诉列表"
                    },
                    new FunctionCallExample
                    {
                        UserInput = "有待处理的投诉吗",
                        TargetAgentCode = AgentCodeEnum.查询投诉.ToString(),//当用户类似这种描述时,对应的智能体
                        Reason = "用户需要查询待处理投诉列表"
                    },
                    new FunctionCallExample
                    {
                        UserInput = "查一下 2026-08-14 到 2026-08-21 的投诉",
                        TargetAgentCode = AgentCodeEnum.查询投诉.ToString(),//当用户类似这种描述时,对应的智能体 
                         Reason = "用户需要查询指定时间段的投诉列表"
                    }
                }
            },
            new AgentConfig
            {
                Code = AgentCodeEnum.分析投诉.ToString(),
                Name = "ComplaintAnalyzer",
                Description = "分析投诉优先级",
                SystemMessage = @"你是投诉分析专家,负责分析投诉内容并判断优先级。

【优先级规则】
- need_immediate_service=true → 高优先级
- user_complaint_times>1 → 高优先级
- problem_type=REFUND → 高优先级
- user_tag_list 包含 HIGH_RISK → 高优先级

【输出格式】
- 投诉单号
- 优先级(高/中/普通)
- 建议处理方案",
                Examples = new[]
                {
                    new FunctionCallExample
                    {
                        UserInput = "分析这个投诉为什么优先级高",
                        TargetAgentCode = AgentCodeEnum.分析投诉.ToString(),
                         Reason = "用户需要分析投诉优先级" //这里的Reson 会 在协调者中用到
                    },
                    new FunctionCallExample
                    {
                        UserInput = "这个投诉紧急吗",
                        TargetAgentCode = AgentCodeEnum.分析投诉.ToString(),
                          Reason = "用户需要分析投诉紧急程度" //这里的Reson 会 在协调者中用到
                    }
                  
                }
            },
            new AgentConfig
            {
                Code = AgentCodeEnum.回复投诉.ToString(),
                Name = "ResponseGenerator",
                Description = "生成回复话术",
                SystemMessage = @"你是客服回复专家,负责生成专业的投诉回复话术。

【回复原则】
1. 态度诚恳,表达歉意
2. 说明处理方案
3. 给出合理承诺(不要过于具体)
4. 引导用户关闭服务单
5. 字数控制在 20-40 字

【禁止事项】
❌ 不要承诺具体时间(如""5 分钟内""、""2 小时内"")
❌ 不要承诺具体金额(如""赔偿 100 元"")
❌ 不要承诺具体人员(如""技术总监亲自处理"")

【推荐表达】
✅ ""尽快"" 而不是 ""5 分钟内""
✅ ""及时"" 而不是 ""2 小时内""
✅ ""专人跟进"" 而不是 ""技术总监""",
                Examples = new[]
                {
                    new FunctionCallExample
                    {
                        UserInput = "生成一个回复,要态度诚恳",
                        TargetAgentCode = AgentCodeEnum.回复投诉.ToString() ,
                         Reason = "用户需要生成诚恳的回复话术",
                    },
                    new FunctionCallExample
                    {
                        UserInput = "怎么写回复话术",
                        TargetAgentCode = AgentCodeEnum.回复投诉.ToString(),
                          Reason = "用户需要生成诚恳的回复话术",
                    },
                    new FunctionCallExample
                    {
                        UserInput = "帮我写个回复,说我们会尽快处理",
                        TargetAgentCode = AgentCodeEnum.回复投诉.ToString() ,
                          Reason = "用户需要生成诚恳的回复话术",
                    }
                }
            },
            new AgentConfig
            {
                Code = AgentCodeEnum.完结投诉.ToString(),
                Name = "CompletionTracker",
                Description = "跟踪完成状态",
                SystemMessage = @"你是投诉完成跟踪助手,负责检查 PROCESSING 状态的投诉并执行操作。

【检查流程】
1. 调用 GetComplaintDetail 查询投诉详情和状态
2. 查询协商历史,检查用户最新留言
3. 检查最后一次商户回复时间,计算是否已满 24 小时

【执行逻辑】
- 如果用户有留言且不满 → 调用 ResponseComplaint 再次回复
- 如果用户有留言且满意 → 调用 CompleteComplaint 标记完成
- 如果用户无留言且已满 24 小时 → 调用 CompleteComplaint 标记完成
- 如果用户无留言但未满 24 小时 → 返回等待提示",
                Examples = new[]
                {
                    new FunctionCallExample
                    {
                        UserInput = "标记这个投诉为完结",
                        TargetAgentCode = AgentCodeEnum.完结投诉.ToString() ,
                        Reason = "用户需要标记投诉为完结状态",
                    },
                    new FunctionCallExample
                    {
                        UserInput = "检查 24 小时等待期",
                        TargetAgentCode =AgentCodeEnum.完结投诉.ToString() ,
                        Reason = "用户需要检查 24 小时等待期,大于24小时用户无回复的,可以完结",
                    },
                    new FunctionCallExample
                    {
                        UserInput = "看看有没有可以完结的投诉",
                        TargetAgentCode = AgentCodeEnum.完结投诉.ToString(),
                        Reason = "用户需要检查可完结的投诉",
                    }
                }
            }
        };
    }
}
View Code

注:AgentConfig的Code为Agent的唯一标识,SystemMessage 为 Agent 的Promot 模版, Examples 为调用函数的相关举例!

Reason 字段为协调者说明选择下一个Agent的原因!

2.2、Agent

using AutoGen.Core;
using AutoGen.OpenAI;
using AutoGen.OpenAI.Extension;
using CoordinatorS;
using OpenAI.Chat;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace ConsoleApp3
{ 
    /// <summary>
    /// 分支 Agent 创建器(使用 FunctionHelper 自动注册)
    /// </summary>
    public static class BranchAgents
    {
        /// <summary>
        /// 根据 Code 创建对应的 Agent
        /// </summary>
        public static IAgent Create(string code, ChatClient chatClient, ComplaintTools complaintTools)
        {
            var config = AgentConfigs.All.FirstOrDefault(a => a.Code == code);
            if (config == null)
            {
                throw new ArgumentException($"未知的 Agent 代码:{code}");
            }

            Console.WriteLine($"🔧 创建分支 Agent: {code} ({config.Name})...");

            // 创建基础 Agent
            var agent = new OpenAIChatAgent(
                name: config.Name,
                systemMessage: config.SystemMessage,
                chatClient: chatClient);

            // ✅ 根据 Code 注册对应的 Function(用 FunctionHelper 自动扫描)
            if (code == AgentCodeEnum.查询投诉.ToString())
            {
                Console.WriteLine("   📦 注册 Function: GetPendingComplaints, GetComplaintDetail");

                var middleware = FunctionHelper.CreateMiddleware(
                    complaintTools,
                    "GetPendingComplaints",
                    "GetComplaintDetail");
                var agentWithConnector = agent.RegisterMessageConnector();
                var agentWithMiddleware = agentWithConnector.RegisterMiddleware(middleware);
                var finalAgent = agentWithMiddleware.RegisterPrintMessage();
                return finalAgent;
            }
            else if (code == AgentCodeEnum.回复投诉.ToString())
            {
                Console.WriteLine("   📦 注册 Function: ResponseComplaint");

                var middleware = FunctionHelper.CreateMiddleware(
                    complaintTools,
                    "ResponseComplaint");

                var agentWithConnector = agent.RegisterMessageConnector();
                var agentWithMiddleware = agentWithConnector.RegisterMiddleware(middleware);
                var finalAgent = agentWithMiddleware.RegisterPrintMessage();
                return finalAgent;
            }
            else if (code == AgentCodeEnum.完结投诉.ToString())
            {
                Console.WriteLine("   📦 注册 Function: CompleteComplaint, GetComplaintDetail, ResponseComplaint");

                var middleware = FunctionHelper.CreateMiddleware(
                    complaintTools,
                    "CompleteComplaint",
                    "GetComplaintDetail",
                    "ResponseComplaint");

                var agentWithConnector = agent.RegisterMessageConnector();
                var agentWithMiddleware = agentWithConnector.RegisterMiddleware(middleware);
                var finalAgent = agentWithMiddleware.RegisterPrintMessage();
                return finalAgent;
            }
            else
            {
                var agentWithConnector = agent.RegisterMessageConnector();
                var finalAgent = agentWithConnector.RegisterPrintMessage();
                return finalAgent;
            }
        }
    }

}
View Code

3、函数及函数帮助类

反射/函数帮助类

using AutoGen.Core;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace CoordinatorS
{
    /// <summary>
    /// Function 辅助工具(自动扫描 + 注册)
    /// </summary>
    public static class FunctionHelper
    {
        /// <summary>
        /// 从工具类自动扫描所有带 [Function] 特性的方法,创建 FunctionCallMiddleware
        /// </summary>
        /// <param name="toolsInstance">工具类实例(如 ComplaintTools)</param>
        /// <param name="functionNames">要注册的函数名列表(为空则注册全部)</param>
        public static FunctionCallMiddleware CreateMiddleware(object toolsInstance, params string[] functionNames)
        {
            var contracts = new List<FunctionContract>();
            var functionMap = new Dictionary<string, Func<string, Task<string>>>();

            var methods = toolsInstance.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance)
                .Where(m => m.GetCustomAttribute<FunctionAttribute>() != null);

            foreach (var method in methods)
            {
                var functionAttr = method.GetCustomAttribute<FunctionAttribute>();
                var functionName = functionAttr?.FunctionName ?? method.Name;

                if (functionNames.Any() && !functionNames.Contains(functionName))
                    continue;

                var contract = new FunctionContract
                {
                    Name = functionName,
                    Description = functionAttr?.Description ?? method.GetCustomAttribute<DescriptionAttribute>()?.Description ?? "",
                    Parameters = method.GetParameters()
                        .Select(p => new FunctionParameterContract
                        {
                            Name = p.Name,
                            Description = p.GetCustomAttribute<DescriptionAttribute>()?.Description ?? "",
                            IsRequired = !p.IsOptional,
                            ParameterType = p.ParameterType,
                            DefaultValue = p.DefaultValue
                        })
                        .ToArray()
                };

                contracts.Add(contract);

                // ✅ 支持任意返回类型的 functionMap
                functionMap[functionName] = async (args) =>
                {
                    try
                    {
                        var json = JsonDocument.Parse(args);
                        var parameters = new List<object?>();

                        foreach (var param in contract.Parameters)
                        {
                            if (json.RootElement.TryGetProperty(param.Name, out var elem))
                            {
                                var value = elem.Deserialize(param.ParameterType);
                                parameters.Add(value);
                            }
                            else if (param.DefaultValue != null)
                            {
                                parameters.Add(param.DefaultValue);
                            }
                            else
                            {
                                parameters.Add(null);
                            }
                        }

                        // ✅ 调用方法(不强制转 Task<string>)
                        var result = method.Invoke(toolsInstance, parameters.ToArray()) as Task;

                        if (result == null)
                        {
                            return "❌ 方法返回 null";
                        }

                        await result;

                        // ✅ 获取 Task.Result
                        var resultProperty = result.GetType().GetProperty("Result");
                        if (resultProperty == null)
                        {
                            return "❌ 找不到 Result 属性";
                        }

                        var resultValue = resultProperty.GetValue(result);

                        // ✅ 已经是 string 直接返回
                        if (resultValue is string stringValue)
                        {
                            return stringValue;
                        }

                        // ✅ 否则序列化(支持任意类型)
                        if (resultValue == null)
                        {
                            return "[]";
                        }

                        return JsonSerializer.Serialize(resultValue, JsonOptions);  // ← 用配置好的 options
                    }
                    catch (Exception ex)
                    {
                        return $"❌ 执行失败:{ex.Message}";
                    }
                };
            }

            return new FunctionCallMiddleware(
                functions: contracts,
                functionMap: functionMap);
        }

        /// <summary>
        /// 从工具类自动扫描所有带 [Function] 特性的方法,返回函数名列表
        /// </summary>
        public static string[] GetAvailableFunctions<T>()
        {
            return typeof(T).GetMethods(BindingFlags.Public | BindingFlags.Instance)
                .Where(m => m.GetCustomAttribute<FunctionAttribute>() != null)
                .Select(m => m.GetCustomAttribute<FunctionAttribute>()?.FunctionName ?? m.Name)
                .ToArray();
        }
        private static readonly JsonSerializerOptions JsonOptions = new()
        {
            Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
            WriteIndented = false  // 不格式化(节省 Token)
        };
    }
}
View Code

AI函数

using AutoGen.Core;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{ 

    /// <summary>
    /// 投诉处理工具类(供 Agent 调用)
    /// </summary>
    public class ComplaintTools
    { 

        public ComplaintTools()
        { 
        }

        /// <summary>
        /// 查询待处理投诉列表-最大查询一月时间
        /// </summary>
        [Function(functionName: "GetPendingComplaints", description: "查询指定日期范围内的待处理投诉列表,只返回 PENDING 状态的投诉单")]
        public async Task<string> GetPendingComplaints(
            [Description("开始日期(YYYY-MM-DD)")] string beginDate,
            [Description("结束日期(YYYY-MM-DD)")] string endDate,
            [Description("分页大小(默认 50)")] int limit = 50)
        {
            return "【查询待处理投诉列表】返回值";
        }

        /// <summary>
        /// 回复用户投诉(支持多次回复)
        /// </summary>
        [Function(functionName: "ResponseComplaint", description: "回复用户投诉,提交处理方案。只有 PENDING 或 PROCESSING 状态的投诉单才能回复")]
        public async Task<string> ResponseComplaint(
            [Description("投诉单号")] string complaintId,
            [Description("回复内容")] string responseContent)
        {
            return "【回复用户投诉】返回值";
        }

        /// <summary>
        /// 反馈投诉处理完成(带状态校验)
        /// 只有状态为 PROCESSING(处理中)的投诉单才能标记完成
        /// 标记完成后,状态将从 PROCESSING 变为 PROCESSED
        /// </summary>
        [Function(functionName: "CompleteComplaint", description: "反馈投诉处理完成。只有满足以下条件才能标记完成:1. 状态为 PROCESSING 2. 已回复用户 3. 回复后 24 小时内用户未继续投诉")]
        public async Task<string> CompleteComplaint(
            [Description("投诉单号")] string complaintId)
        {
            return "【反馈投诉处理完成】返回值";
        }

        /// <summary>
        /// 查询投诉详情
        /// </summary> 
        [Function(functionName: "GetComplaintDetail", description: "查询投诉详情,包含状态、投诉内容、用户联系方式等")]
        public async Task<string> GetComplaintDetail(
            [Description("投诉单号")] string complaintId)
        {
            return "【查询投诉详情】返回值";
        }
    }
}
View Code

4、main 函数 及项目引用

using Applier;
using AutoGen.Core;
using CoordinatorS;
using OpenAI;
using System.ClientModel;
using System.Text.Json;

namespace ConsoleApp3
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("╔════════════════════════════════════╗");
            Console.WriteLine("║   协调者 Agent 测试               ║");
            Console.WriteLine("╚════════════════════════════════════╝");
            Console.WriteLine();

            try
            {
                // ① 初始化 OpenAI 客户端
                Console.WriteLine("🔌 正在连接 OpenAI...");
                var client = new OpenAIClient(
      new ApiKeyCredential(ConstParm.apiKey),
      new OpenAIClientOptions
      {
          Endpoint = new Uri("https://dashscope.aliyuncs.com/compatible-mode/v1")
      });

                var chatClient = client.GetChatClient("qwen-plus");  // 通义千问
                Console.WriteLine("✅ OpenAI 连接成功");
                Console.WriteLine();
                 

                Console.WriteLine();

                var testInputs = new[]
           {
                "帮我查一下最近 7 天的投诉",
                "分析一下这个投诉为什么优先级高",
                "生成一个回复,要态度诚恳",
                "标记这个投诉为完成"
            };

               foreach(var userInput in testInputs)
                {
                    CoordinatorAgentFactory _factory = new CoordinatorAgentFactory(ConstParm.apiKey, ConstParm.endpoint, ConstParm.modelId);
                    var coordinator = _factory.CreateCoordinator();
                    var message = new TextMessage(Role.User, userInput, from: "User");

                    var result = await coordinator.GenerateReplyAsync(
                        messages: new[] { message });

                    // ✅ 方案:同时支持 TextMessage 和 ToolCallMessage
                    string nextAgent = null;
                    string reason = null;
                    string extractedParams = "{}";

                    if (result is TextMessage textMsg)
                    {
                        // AI 直接输出 JSON 文本
                        var content = textMsg.GetContent();
                        var json = JsonDocument.Parse(content);

                        nextAgent = json.RootElement.GetProperty("next_agent").GetString();  
                    }
                    else if (result is ToolCallMessage toolCall)
                    {
                        // AI 调用函数
                        var Call = JsonDocument.Parse(toolCall.ToolCalls.First().FunctionArguments);
                        nextAgent = Call.RootElement.GetProperty("next_agent").GetString();
                         
                    }

                    Console.WriteLine($"🔀用户说:{userInput} ,协调者路由决策:{nextAgent}"); 

                    // 创建分支 Agent 并执行
                    if (!string.IsNullOrEmpty(nextAgent))
                    {
                        var branchAgent = _factory.CreateBranchAgent(nextAgent);
                        var branchResult = await branchAgent.GenerateReplyAsync(
                            messages: new[] { message });

                        Console.WriteLine($"✅ 分支结果:{branchResult.GetContent()}");
                    }
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine($"❌ 主程序异常:{ex.Message}");
                Console.WriteLine($"   类型:{ex.GetType().Name}");
                Console.WriteLine($"   堆栈:{ex.StackTrace}");
            }

            Console.WriteLine();
            Console.WriteLine("按任意键退出...");
            Console.ReadLine();
        }
    }
}
View Code

项目

<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" />
        <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
        <PackageReference Include="Microsoft.Extensions.Configuration.Json" 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>
View Code

5、Ai相关参数

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

namespace Applier
{
    internal class ConstParm
    {
        /// <summary>
        /// 大模型
        /// </summary>
        public static string modelId = "qwen-plus";
        /// <summary>
        /// 
        /// </summary>
        public static string apiKey = "sk-adxxxxxxxxxxxxxxxxxxxxxx101d";
        /// <summary>
        /// 大模型URL
        /// </summary>
        public static string endpoint = "https://dashscope.aliyuncs.com/compatible-mode/v1";
        /// <summary>
        /// 高德查询天气预报的 Apikey  windows服务类型
        /// </summary>
        public static string amapApiKey = "63xxxxxxxxxxxxxxb78e4xxxxa4b9";
    }
}

 

posted @ 2026-08-24 16:47  天才卧龙  阅读(15)  评论(0)    收藏  举报