MAF 自动处理邮件

using Microsoft.Agents.AI.Workflows;
using Microsoft.Agents.AI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
using System.Text.Json;
using OpenAI.Chat;
using ChatResponseFormat = Microsoft.Extensions.AI.ChatResponseFormat;

namespace ConsoleApp1.WorksFolw
{

    // 参考地址   https://www.cnblogs.com/edisontalk/p/-/quick-start-on-maf-chatper08

    public static class Test2
    {

        public static async Task Test正常邮件()
        {
           var conditionalWorkflow = await CreateWorkflowB();
            var scenarioName1 = "正常咨询 → EmailAssistant 分支";
            var emailContent1 = @"客服团队你好,我想确认上周提交的采购订单是否已经发货,如果还有缺少信息请告知。";
            await RunConditionalWorkflowAsync(conditionalWorkflow, scenarioName1, emailContent1);
            Console.WriteLine("✅ 正常邮件路径验证完成");
        }
        public static async Task Test垃圾邮件()
        {
            var conditionalWorkflow = await CreateWorkflowB();
            var scenarioName2 = "垃圾邮件 → HandleSpam 分支";
            var emailContent2 = @"令人惊喜的投资机会!只需支付保证金即可在 24 小时内获得 10 倍收益,点击可疑链接领取奖励。";
            await RunConditionalWorkflowAsync(conditionalWorkflow,scenarioName2, emailContent2);
            Console.WriteLine("✅ 垃圾邮件路径验证完成");
        }
        public static async Task RunConditionalWorkflowAsync( Workflow conditionalWorkflow,string scenarioName,string emailContent, CancellationToken cancellationToken = default)
        {
            Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
            Console.WriteLine($"测试场景:{scenarioName}");
            Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
            var chatMessage = new Microsoft.Extensions.AI.ChatMessage(ChatRole.User, emailContent);
            await using var run = await InProcessExecution.RunStreamingAsync(conditionalWorkflow, chatMessage);
            await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
            await foreach (WorkflowEvent evt in run.WatchStreamAsync())
            {
                switch (evt)
                {
                    case ExecutorCompletedEvent completedEvent:
                        Console.WriteLine($" {completedEvent.ExecutorId} 完成");
                        break;
                    case WorkflowOutputEvent outputEvent:
                        Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
                        Console.WriteLine(" 工作流执行完成");
                        Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
                        Console.WriteLine($"{outputEvent.Data}");
                        break;
                    //case WorkflowErrorEvent errorEvent:
                    //    Console.WriteLine(" 收到 Workflow Error Event:");
                    //    Console.WriteLine($"{errorEvent.Data}");
                    //    break;
                    default:
                        break;
                }
            }
        }
        public static async Task<Workflow> CreateWorkflowB()
        {
            AIService chatClient = new AIService();
            var param = new ChatClientAgentOptions
            {
                Name = "ttt",
                ChatOptions = new()
                {
                    Instructions = "您是一名垃圾邮件检测助手,可以用原因标记垃圾邮件",
                    ResponseFormat = ChatResponseFormat.ForJsonSchema<DetectionResult>()
                }
            };
            var spamDetectionAgent = chatClient.GetAIAgentByParms(param);
            var param2 = new ChatClientAgentOptions
            {
                Name = "tt2222",
                ChatOptions = new()
                {
                    Instructions = "您是一名企业电子邮件助理。您可以为用户提供专业的中文回复。",
                    ResponseFormat = ChatResponseFormat.ForJsonSchema<EmailResponse>()
                }
            };
            var emailAssistantAgent = chatClient.GetAIAgentByParms(param2);


            //垃圾邮件检测助手   邮件检测执行器
            var spamDetectionExecutor = new SpamDetectionExecutor(spamDetectionAgent);
            //邮件助手执行器q
            var emailAssistantExecutor = new EmailAssistantExecutor(emailAssistantAgent);
            // 发送邮件执行器
            var sendEmailExecutor = new EmailSendingExecutor();
            //垃圾邮件处理执行器
            var handleSpamExecutor = new SpamHandlingExecutor();


           // Func<object?, bool> BuildCondition(bool expectedSpamFlag) => detection => detection is DetectionResult dr && dr.IsSpam == expectedSpamFlag;
            Func<object?, bool> BuildCondition(bool expectedSpamFlag)
            {
                // 返回一个匿名方法/委托实例--传递上一个
                return delegate (object? detection)
                {
                    // 将模式匹配拆解为显式的类型检查 + 转换 + 字段比较
                    if (detection is DetectionResult)
                    {
                        DetectionResult dr = (DetectionResult)detection;
                        if (dr.IsSpam == expectedSpamFlag)//是垃圾邮件
                        {
                            return true;
                        }
                    }
                    return false;
                };
            }
            var conditionalWorkflow = new WorkflowBuilder(spamDetectionExecutor)
                .AddEdge(spamDetectionExecutor, emailAssistantExecutor, condition: BuildCondition(false))// 引擎从 spamDetectionExecutor 的输出中取出值,作为 detection 传入条件委托。
                .AddEdge(emailAssistantExecutor, sendEmailExecutor)
                .AddEdge(spamDetectionExecutor, handleSpamExecutor, condition: BuildCondition(true))
                .WithOutputFrom(handleSpamExecutor, sendEmailExecutor)
                .Build();
            Console.OutputEncoding = Encoding.UTF8;
            Console.WriteLine(" Conditional Workflow 构建完成");
            return conditionalWorkflow;
        }
   
    
    
    }





    #region 实体
            /// <summary>
            /// 邮件检测结果
            /// </summary>
    public sealed class DetectionResult
    {
        [JsonPropertyName("is_spam")]
        public bool IsSpam { get; set; }
        [JsonPropertyName("reason")]
        public string Reason { get; set; } = string.Empty;
        [JsonIgnore]
        public string EmailId { get; set; } = string.Empty;
    }
    internal static class EmailStateConstants
    {
        public const string EmailStateScope = "EmailState";
    }


    internal sealed class EmailMessage
    {
        [JsonPropertyName("email_id")]
        public string EmailId { get; set; } = string.Empty;

        [JsonPropertyName("email_content")]
        public string EmailContent { get; set; } = string.Empty;
    }

    public sealed class EmailResponse
    {
        [JsonPropertyName("response")]
        public string Response { get; set; } = string.Empty;
    }

    #endregion


    #region  Executor

    //1   这个垃圾邮件检测是本流程的核心节点,它接收用户邮件内容并调用LLM做检测,最后生成该邮件的唯一ID并将邮件原文写入工作流共享状态存储区,返回唯一ID供下游节点使用
    /// <summary>
    /// 垃圾邮件检测执行器
    /// </summary>
    internal sealed class SpamDetectionExecutor : Executor<Microsoft.Extensions.AI.ChatMessage, DetectionResult>
    {
        //接收我们如下所示定义好的Agent来实现
        //var spamDetectionAgent = new ChatClientAgent(
        //    chatClient, 
        //new ChatClientAgentOptions(instructions: "You are a spam detection assistant that labels spam emails with reasons.")
        //    {
        //        ChatOptions = new()
        //        {
        //            ResponseFormat = ChatResponseFormat.ForJsonSchema<DetectionResult>()
        //        }
        //});


        private readonly AIAgent _agent;
        private  AgentSession mAgeSession;

        public SpamDetectionExecutor(AIAgent agent) : base("SpamDetectionExecutor")
        {
            // 创建 Agent 和对话线程
            this._agent = agent;
            //this._thread = await this._agent.CreateSessionAsync();
        }

        public override async ValueTask<DetectionResult> HandleAsync(Microsoft.Extensions.AI.ChatMessage message, IWorkflowContext context, CancellationToken cancellationToken = default)
        {
            if (mAgeSession == null)
            {
                mAgeSession = await _agent.CreateSessionAsync();
            }
            var trackedEmail = new EmailMessage
            {
                EmailId = Guid.NewGuid().ToString("N"),
                EmailContent = message.Text
            };
            //邮件的唯一ID并将邮件原文写入工作流共享状态存储区,返回唯一ID供下游节点使用
            await context.QueueStateUpdateAsync(trackedEmail.EmailId, trackedEmail, scopeName: EmailStateConstants.EmailStateScope, cancellationToken);
            
            var agentResponse = await _agent.RunAsync(message, cancellationToken: cancellationToken);
            var detectionResult = JsonSerializer.Deserialize<DetectionResult>(agentResponse.Text)
                ?? throw new InvalidOperationException("无法解析 Spam Detection 响应。");
            detectionResult.EmailId = trackedEmail.EmailId;
            //if (detectionResult != null)
            //{
            //    Console.WriteLine($"邮件垃圾检测助手,检测出邮件是否是垃圾{detectionResult.IsSpam},描述{detectionResult.Reason}");
            //}
            return detectionResult;
        }
    }

    //下游节点A:正常邮件处理+发送   邮件处理:读取共享状态区的原文,然后调用Agent输出JSON回复
    /// <summary>
    /// 正常邮件处理+发送
    /// </summary>
    internal sealed class EmailAssistantExecutor : Executor<DetectionResult, EmailResponse>
    {
    //    var emailAssistantAgent = new ChatClientAgent(
    //chatClient,
    //new ChatClientAgentOptions(instructions: "You are an enterprise email assistant. You can provide professional Chinese responses to user.")
    //{
    //    ChatOptions = new()
    //    {
    //        ResponseFormat = ChatResponseFormat.ForJsonSchema<EmailResponse>()
    //    }
    //});

        private readonly AIAgent _agent;
        private  AgentSession mAgeSession;

        public EmailAssistantExecutor(AIAgent agent) : base("EmailAssistantExecutor")
        {
            // 创建 Agent 和对话线程
            this._agent = agent;
            //this._thread = this._agent.GetNewThread();
        }

        public override async ValueTask<EmailResponse> HandleAsync(DetectionResult message, IWorkflowContext context, CancellationToken cancellationToken = default)
        {

            if (mAgeSession == null)
            {
                mAgeSession = await _agent.CreateSessionAsync();
            }
            if (message.IsSpam)
                throw new InvalidOperationException("Spam 邮件不应进入 EmailAssistantExecutor。");

            var email = await context.ReadStateAsync<EmailMessage>(message.EmailId, scopeName: EmailStateConstants.EmailStateScope, cancellationToken)
                ?? throw new InvalidOperationException("找不到对应 Email 内容。");
           
            var agentResponse = await _agent.RunAsync(email.EmailContent, mAgeSession, cancellationToken: cancellationToken);
            var emailResponse = JsonSerializer.Deserialize<EmailResponse>(agentResponse.Text)
                ?? throw new InvalidOperationException("无法解析 Email Assistant 响应。");
            return emailResponse;
        }
    }
    //邮件转发:模拟邮件转发到具体的客服,这里仅仅使用YieldOutputAsync完成工作流输出消息内容
    /// <summary>
    /// 邮件转发
    /// </summary>
    internal sealed class EmailSendingExecutor() : Executor<EmailResponse>("EmailSendingExecutor")
    {
        public override async ValueTask HandleAsync(EmailResponse message, IWorkflowContext context, CancellationToken cancellationToken = default)
        {
            Console.WriteLine($" Email 已发送:{message.Response}");
            await context.YieldOutputAsync($" Email 已发送:{message.Response}", cancellationToken);
        }
    }


    //下游节点B:垃圾邮件处理
    //当判断到是垃圾邮件时,转交给该执行器处理,这里模拟输出了一段风险提示,实际中可能是上报人工跟进等等操作
    /// <summary>
    /// 垃圾邮件处理
    /// </summary>
    internal sealed class SpamHandlingExecutor() : Executor<DetectionResult>("SpamHandlingExecutor")
    {
        public override async ValueTask HandleAsync(DetectionResult message, IWorkflowContext context, CancellationToken cancellationToken = default)
        {
            if (!message.IsSpam)
                throw new InvalidOperationException("非垃圾邮件不应进入 SpamHandlingExecutor。");

            Console.WriteLine($" 垃圾邮件:{message.Reason}", cancellationToken);
            await context.YieldOutputAsync($" 垃圾邮件:{message.Reason}", cancellationToken);
        }
    }

    #endregion


}

 

posted @ 2026-09-15 15:51  陌念  阅读(5)  评论(0)    收藏  举报