找回密码
 立即注册
首页 业界区 业界 MAF快速入门(10)循环工作流

MAF快速入门(10)循环工作流

求几少 5 天前
大家好,我是Edison。
最近我一直在跟着圣杰的《.NET+AI智能体开发进阶》课程学习MAF的开发技巧,我强烈推荐你也上车跟我一起出发!
上一篇,我们学习了MAF中如何进行switch-case类型的多条件路由。本篇,我们来了解下在MAF中如何实现循环(自我修正)工作流。
1 循环与自我修正

在实际业务场景中,往往需要在工作流中设置一些循环与自我修正的机制,构建出一个“生成→审核→修复”的闭环,来确保AI产出的内容能够满足企业级质量标准。
在MAF中,我们可以使用 Loop Edge 即 循环边 来实现这个目的,如下代码片段所示:
  1. var workflow = new WorkflowBuilder(draftExecutor)
  2.     .AddEdge(draftExecutor, qcExecutor)
  3.     .AddEdge(qcExecutor, draftExecutor)
  4.     .WithOutputFrom(qcExecutor)
  5.     .Build();
复制代码
可以看到,我们添加了两个边关联关系,这样就形成了一个循环。
2 循环工作流实验案例

假设我们是一个电商平台的客服中心,每天需要处理产生的大量客服工单进行回复。这里我们希望AI助手先帮我们生成一个回复草稿,然后经过多维度的质检(礼貌度、准确性、合规性),不合格的则自动进行改进,直到满足标准 或者是 转给人工处理。因此,我们的目标是:配置一个自动迭代的循环“生成→审核→修复”,达标即可退出循环,否则转人工处理。
2.1 关键依赖包引入

在今天的这个案例中,我们仍然创建了一个.NET控制台应用程序,安装了以下NuGet包:

  • Microsoft.Agents.AI.OpenAI
  • Microsoft.Agents.AI.Workflows
  • Microsoft.Extensions.AI.OpenAI
2.2 定义数据传输模型

首先,我们定义一下在这个工作流中需要生成传递的数据模型:
(1)QualityReportDto :质检结果输出模型DTO
  1. // 质检结果的结构化输出模型
  2. internal class QualityReportDto
  3. {
  4.     [JsonPropertyName("politenessScore")]
  5.     public int PolitenessScore { get; set; }
  6.     [JsonPropertyName("accuracyScore")]
  7.     public int AccuracyScore { get; set; }
  8.     [JsonPropertyName("compliancePassed")]
  9.     public bool CompliancePassed { get; set; }
  10.     [JsonPropertyName("issues")]
  11.     public List<QualityIssueDto> Issues { get; set; } = new();
  12. }
  13. internal class QualityIssueDto
  14. {
  15.     [JsonPropertyName("type")]
  16.     public string Type { get; set; } = string.Empty;
  17.     [JsonPropertyName("description")]
  18.     public string Description { get; set; } = string.Empty;
  19.     [JsonPropertyName("scoreImpact")]
  20.     public int ScoreImpact { get; set; }
  21. }
复制代码
(2)一些值对象,不赘述了
  1. internal record ReplyDraft(
  2.     string TicketId,
  3.     string Content,
  4.     int Attempt);
  5. internal record TicketRequest(
  6.     string Id,
  7.     string Query,
  8.     string Category,
  9.     string Priority);
  10. internal record TicketOutcome(
  11.     string TicketId,
  12.     string Status,
  13.     int Attempts,
  14.     QualityReport FinalReport);
  15. internal sealed record QualityScoreTimelineItem(
  16.     int Attempt,
  17.     int PolitenessScore,
  18.     int AccuracyScore,
  19.     string ComplianceStatus);
  20. internal record QualityIssue(
  21.     string Type,
  22.     string Description,
  23.     int ScoreImpact);
  24. internal record QualityReport(
  25.     string TicketId,
  26.     int PolitenessScore,
  27.     int AccuracyScore,
  28.     bool CompliancePassed,
  29.     IReadOnlyList<QualityIssue> Issues);
复制代码
(3)一些常量:用于定义一些阈值标准
  1. public static class QualityCheckConstants
  2. {
  3.     // 质检标准:礼貌度 ≥ 85,准确性 ≥ 90,合规性必须 100%
  4.     // 注意:阈值设置较高,配合第一次生成简化版本,确保能体现循环改进过程
  5.     public const int PolitenessThreshold = 85;
  6.     public const int AccuracyThreshold = 90;
  7. }
  8. internal enum QualityCheckSignal
  9. {
  10.     Init,
  11.     Revise
  12. }
复制代码
2.3 定义自定义工作流事件

其次,我们定义一下在这个工作流中需要产生的自定义事件:
(1)AdaptiveQualityScoreEvent :质检评分已完成事件
  1. internal sealed class AdaptiveQualityScoreEvent : WorkflowEvent
  2. {
  3.     public AdaptiveQualityScoreEvent(string ticketId,
  4.         int attempt,
  5.         int politenessScore,
  6.         int accuracyScore,
  7.         bool compliancePassed)
  8.         : base(new { TicketId = ticketId, Attempt = attempt, PolitenessScore = politenessScore, AccuracyScore = accuracyScore, CompliancePassed = compliancePassed })
  9.     {
  10.     }
  11. }
复制代码
(2)AdaptiveMaxAttemptsReachedEvent :质检超过最大次数事件
  1. internal sealed class AdaptiveMaxAttemptsReachedEvent : WorkflowEvent
  2. {
  3.     public AdaptiveMaxAttemptsReachedEvent(string ticketId, int maxAttempts)
  4.         : base(new { TicketId = ticketId, MaxAttempts = maxAttempts })
  5.     {
  6.     }
  7. }
复制代码
2.4 定义Agents

(1)回复生成:模这里通过执行器的方式包裹一个回复生成的Agent,假设其用于客服工单的自动回复:
[code]internal sealed class AdaptiveReplyDraftExecutor : Executor{    private readonly TicketRequest _ticket;    private readonly IChatClient _chatClient;    public AdaptiveReplyDraftExecutor(TicketRequest ticket, IChatClient chatClient) : base("AdaptiveReplyDraft")    {        _ticket = ticket;        _chatClient = chatClient;    }    public override async ValueTask HandleAsync(QualityCheckSignal message, IWorkflowContext context, CancellationToken cancellationToken = default)    {        int attempt = await context.ReadOrInitStateAsync("attempt", () => 0, cancellationToken);        attempt++;        await context.QueueStateUpdateAsync("attempt", attempt, cancellationToken);        // 使用 AI 生成客服回复(渐进式生成策略)        var prompt = attempt == 1            ? $"""            你是一位电商客服。请针对以下客户问题生成一条简短回复(刻意保持简短、缺少礼貌用语):            客户问题:{_ticket.Query}            产品类别:{_ticket.Category}            要求:            1. 只用1-2句话回答,不要称呼语和感谢语            2. 只说结论,不提供具体处理时间            3. 字数控制在30字以内            直接返回回复内容,不要添加任何前缀或说明。            """            : $"""            你是一位专业的电商客服。请针对以下客户问题生成一条改进后的回复:            客户问题:{_ticket.Query}            产品类别:{_ticket.Category}            优先级:{_ticket.Priority}            要求:            1. 语气亲和、专业,使用恰当的称呼和感谢语            2. 提供具体的解决方案或处理时间            3. 符合客服规范,不包含敏感词            4. 字数控制在80-100字            直接返回回复内容,不要添加任何前缀或说明。            """;        var response = await _chatClient.GetResponseAsync(prompt, cancellationToken: cancellationToken);        var content = response.Text ?? "抱歉,我们会尽快处理您的问题。";        Console.WriteLine($"✍️ 第 {attempt} 次生成回复草稿 (策略: {(attempt == 1 ? "简化版" : "完整版")})");        Console.WriteLine($"
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册