前言
最近有空的时候在学习Microsoft Agent Framework,在这个框架中目前Workflows分为了Sequential、Concurrent、Handoffs以及Groupchat四种模式,今天让我们来了解一下这四种不同的模式。
首先需要以下两个包:
Sequential 模式
在开始介绍之前,先看下它的效果:
首先需要先构建一个IChatClient:
csharp
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();
现在通过这个函数方便构建不同的翻译代理:
csharp
/// <summary>为指定目标语言创建翻译代理。</summary>
private static ChatClientAgent GetTranslationAgent(string targetLanguage, IChatClient chatClient) =>
new(chatClient,
$"你是一个翻译助手,只使用{targetLanguage}回应。对于任何输入," +
$"首先输出输入语言的名称,然后将输入翻译成{targetLanguage}。");
构建顺序工作流:
csharp
// 创建顺序工作流
var workflow = AgentWorkflowBuilder.BuildSequential(
from lang in (string[])["French", "Spanish", "English"]
select GetTranslationAgent(lang, client)
);
参数就是一组AIAgent,然后工作流会将这些AIAgent按顺序组合起来。
运行这个工作流:
csharp
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 += "\n\n工作流完成!";
return output.As<List<ChatMessage>>()!;
}
}
return [];
}
与直觉不一样的地方是只有在传入TurnToken的时候才会开始运行:
csharp
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
然后通过WorkflowEvent来进行不同操作。
这个例子看最后的输入就是这样的:
Concurrent 模式
还是先来看下效果:
Concurrent就是并发工作流,对同一个输入,不同的AI Agent同时响应。
看一下怎么构建:
csharp
// 创建并发工作流
var workflow = AgentWorkflowBuilder.BuildConcurrent(
from lang in (string[])["French", "Spanish", "English"]
select GetTranslationAgent(lang, client)
);
Handoffs 模式
Handoffs就是交接模式,跟之前的不太一样,首先我们先创建3个不同的AI Agent:
csharp
// 创建专门的代理
ChatClientAgent historyTutor = new(client,
"你提供历史查询方面的帮助。清晰地解释重要事件和背景。只回应历史相关内容。",
"history_tutor",
"历史问题的专业代理");
ChatClientAgent mathTutor = new(client,
"你提供数学问题方面的帮助。在每一步解释你的推理过程并包含示例。只回应数学相关内容。",
"math_tutor",
"数学问题的专业代理");
ChatClientAgent triageAgent = new(client,
"你根据用户的作业问题确定使用哪个代理。总是将任务交接给另一个代理。",
"triage_agent",
"将消息路由到适当的专业代理");
看下如何构建:
csharp
// 创建交接工作流
var workflow = AgentWorkflowBuilder.CreateHandoffBuilderWith(triageAgent)
.WithHandoffs(triageAgent, [mathTutor, historyTutor])
.WithHandoffs([mathTutor, historyTutor], triageAgent)
.Build();
来看下效果:
这次会到这个地方:
内部有一个FunctionCall交接给了对应的代理。
看一下最终的结果:
再问一个数学相关的问题看看效果:
看一下最终的结果:
Groupchat 模式
Groupchat模式就是开启一个AI群聊,我拿辩论举个例子。
csharp
ChatClientAgent chatClientAgent1 = new(client, "你是辩论正方");
ChatClientAgent chatClientAgent2 = new(client, "你是辩论反方");
// 创建群聊工作流
var workflow = AgentWorkflowBuilder.CreateGroupChatBuilderWith(agents => new RoundRobinGroupChatManager(agents) { MaximumIterationCount = 5 })
.AddParticipants([chatClientAgent1, chatClientAgent2])
.Build();
效果: