前言
最近有空的时候在学习Microsoft Agent Framework,在这个框架中目前Workflows分为了Sequential、Concurrent、Handoffs以及Groupchat四种模式,今天让我们来了解一下这四种不同的模式。
首先需要以下两个包:

Sequential 模式
在开始介绍之前,先看下它的效果:

首先需要先构建一个IChatClient:
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("未设置环境变量:OPENAI_API_KEY"); //var model = Environment.GetEnvironmentVariable("OPENAI_MODEL") ?? "gpt-4o-mini"; var model = "moonshotai/Kimi-K2-Instruct-0905"; var baseUrl = Environment.GetEnvironmentVariable("OPENAI_BASEURL") ?? throw new InvalidOperationException("未设置环境变量:OPENAI_BASEURL"); ApiKeyCredential apiKeyCredential = new ApiKeyCredential(apiKey); OpenAIClientOptions openAIClientOptions = new OpenAIClientOptions(); openAIClientOptions.Endpoint = new Uri(baseUrl); var client = new OpenAIClient(apiKeyCredential, openAIClientOptions).GetChatClient(model).AsIChatClient();
现在通过这个函数方便构建不同的翻译代理:
/// <summary>为指定目标语言创建翻译代理。</summary> private static ChatClientAgent GetTranslationAgent(string targetLanguage, IChatClient chatClient) => new(chatClient, $"你是一个翻译助手,只使用{targetLanguage}回应。对于任何输入," + $"首先输出输入语言的名称,然后将输入翻译成{targetLanguage}。");
构建顺序工作流:
// 创建顺序工作流 var workflow = AgentWorkflowBuilder.BuildSequential( from lang in (string[])["French", "Spanish", "English"] select GetTranslationAgent(lang, client) );

参数就是一组AIAgent,然后工作流会将这些AIAgent按顺序组合起来。
运行这个工作流:
List<ChatMessage> messages = [new(ChatRole.User, InputText)]; await RunWorkflowAsync(workflow, messages); private async Task<List<ChatMessage>> RunWorkflowAsync(Workflow workflow, List<ChatMessage> messages) { string? lastExecutorId = null; await using StreamingRun run = await InProcessExecution.StreamAsync(workflow, messages); await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); await foreach (WorkflowEvent evt in run.WatchStreamAsync()) { if (evt is AgentRunUpdateEvent e) { if (e.ExecutorId != lastExecutorId) { OutputText += "n"; lastExecutorId = e.ExecutorId; OutputText += $"{e.ExecutorId}:n"; } OutputText += e.Update.Text; if (e.Update.Contents.OfType<FunctionCallContent>().FirstOrDefault() is FunctionCallContent call) { OutputText += "n"; OutputText += $"[调用函数 '{call.Name}',参数: {JsonSerializer.Serialize(call.Arguments)}]"; } } else if (evt is WorkflowOutputEvent output) { OutputText += "nn工作流完成!"; return output.As<List<ChatMessage>>()!; } } return []; }
与直觉不一样的地方是只有在传入TurnToken的时候才会开始运行:
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
然后通过WorkflowEvent来进行不同操作。
这个例子看最后的输入就是这样的:

Concurrent 模式
还是先来看下效果:

Concurrent就是并发工作流,对同一个输入,不同的AI Agent同时响应。
看一下怎么构建:
// 创建并发工作流 var workflow = AgentWorkflowBuilder.BuildConcurrent( from lang in (string[])["French", "Spanish", "English"] select GetTranslationAgent(lang, client) );
Handoffs 模式
Handoffs就是交接模式,跟之前的不太一样,首先我们先创建3个不同的AI Agent:
// 创建专门的代理 ChatClientAgent historyTutor = new(client, "你提供历史查询方面的帮助。清晰地解释重要事件和背景。只回应历史相关内容。", "history_tutor", "历史问题的专业代理"); ChatClientAgent mathTutor = new(client, "你提供数学问题方面的帮助。在每一步解释你的推理过程并包含示例。只回应数学相关内容。", "math_tutor", "数学问题的专业代理"); ChatClientAgent triageAgent = new(client, "你根据用户的作业问题确定使用哪个代理。总是将任务交接给另一个代理。", "triage_agent", "将消息路由到适当的专业代理");
看下如何构建:
// 创建交接工作流 var workflow = AgentWorkflowBuilder.CreateHandoffBuilderWith(triageAgent) .WithHandoffs(triageAgent, [mathTutor, historyTutor]) .WithHandoffs([mathTutor, historyTutor], triageAgent) .Build();
来看下效果:

这次会到这个地方:


内部有一个FunctionCall交接给了对应的代理。
看一下最终的结果:

再问一个数学相关的问题看看效果:

看一下最终的结果:

Groupchat 模式
Groupchat模式就是开启一个AI群聊,我拿辩论举个例子。
ChatClientAgent chatClientAgent1 = new(client, "你是辩论正方"); ChatClientAgent chatClientAgent2 = new(client, "你是辩论反方"); // 创建群聊工作流 var workflow = AgentWorkflowBuilder.CreateGroupChatBuilderWith(agents => new RoundRobinGroupChatManager(agents) { MaximumIterationCount = 5 }) .AddParticipants([chatClientAgent1, chatClientAgent2]) .Build();
效果:

