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
}