大家好,我是Edison。
上一篇我们学习了Semantic Kernel中的顺序编排模式,它非常适合如文档审阅、数据处理管道等工作流类型任务场景。今天,我们学习新的模式:群聊编排。
群聊编排模式简介
在群聊编排模式中,各个Agent就像加入了一个微信群,由群管理员协调进行群聊对话。这种模式非常适合于模拟会议、辩论或协作解决问题的会议类型场景。
下图展示了一个讨论业务建议的用例,由一个Chat Manager负责主持对话,依次让三个参与对话的Agent进行建议发表。这个Chat Manager就像是群管理员,它不仅负责主持对话,也会在必要时引入人工干预。
实现群聊编排模式
这里我们来实现一个和上一节类似的DEMO,我们定义2个Agent:广告文案写手(CopyWriter) 和 编辑/审稿人(Editor),假设他们是一个小Team,在承接广告文案的创作。假设每个文案都需要审稿人审核,可以有多轮审核,直到审核确认OK才能交付。
为了简单地实现这个功能,我们还是创建一个.NET控制台项目,然后安装以下包:- Microsoft.SemanticKernel.Agents.Core
- Microsoft.SemanticKernel.Agents.OpenAI (Preview版本)
- Microsoft.SemanticKernel.Agents.Orchestration (Preview版本)
- Microsoft.SemanticKernel.Agents.Runtime.InProcess (Preview版本)
复制代码 需要注意的是,由于Semantic Kernel的较多功能目前还处于实验预览阶段,所以建议在该项目的csproj文件中加入以下配置,统一取消警告:- <PropertyGroup>
- <NoWarn>$(NoWarn);CA2007;IDE1006;SKEXP0001;SKEXP0110;OPENAI001</NoWarn>
- </PropertyGroup>
复制代码 创建一个appsettings.json配置文件,填入以下关于LLM API的配置,其中API_KEY请输入你自己的:- {
- "LLM": {
- "BASE_URL": "https://api.siliconflow.cn",
- "API_KEY": "******************************",
- "MODEL_ID": "Qwen/Qwen2.5-32B-Instruct"
- }
- }
复制代码 这里我们使用SiliconCloud提供的 Qwen2.5-32B-Instruct 模型,你可以通过这个URL注册账号:https://cloud.siliconflow.cn/i/DomqCefW 获取大量免费的Token来进行本次实验。
有了LLM API,我们可以创建一个Kernel供后续使用,这也是老面孔了:- Console.WriteLine("Now loading the configuration...");
- var config = new ConfigurationBuilder()
- .AddJsonFile($"appsettings.json", optional: false, reloadOnChange: true)
- .Build();
- Console.WriteLine("Now loading the chat client...");
- var chattingApiConfiguration = new OpenAiConfiguration(
- config.GetSection("LLM:MODEL_ID").Value,
- config.GetSection("LLM:BASE_URL").Value,
- config.GetSection("LLM:API_KEY").Value);
- var openAiChattingClient = new HttpClient(new OpenAiHttpHandler(chattingApiConfiguration.EndPoint));
- var kernel = Kernel.CreateBuilder()
- .AddOpenAIChatCompletion(chattingApiConfiguration.ModelId, chattingApiConfiguration.ApiKey, httpClient: openAiChattingClient)
- .Build();
复制代码 接下来,我们就一步一步地来看看核心的代码。
定义Agent
这里我们来定义2个Agent:Writer,Editor
(1)Writer 文案写手- var writerAgent = new ChatCompletionAgent()
- {
- Name = "CopyWriter",
- Instructions = """
- You are a copywriter with ten years of experience and are known for brevity and a dry humor.
- The goal is to refine and decide on the single best copy as an expert in the field.
- Only provide a single proposal per response.
- You're laser focused on the goal at hand.
- Don't waste time with chit chat.
- Consider suggestions when refining an idea.
- """,
- Description = "A copy writer.",
- Kernel = kernel
- };
复制代码 (2)Editor 审核编辑- var editorAgent = new ChatCompletionAgent()
- {
- Name = "Reviewer",
- Instructions = """
- You are an art director who has opinions about copywriting born of a love for David Ogilvy.
- The goal is to determine if the given copy is acceptable to print.
- If so, state that it is approved.
- If not, provide insight on how to refine suggested copy without example.
- """,
- Description = "An editor.",
- Kernel = kernel
- };
复制代码 选择编排模式
这里我们选择的是群聊编排模式:GroupChatOrchestration,将需要编排的2个Agent作为参数传递给它。
需要注意的是:这里我们选择Semantic Kernel预定义好的群管理员类 RoundRobinGroupChatManager,顾名思义,它的策略就是轮流让参与的群成员发言,没有特殊的指定逻辑。- // Set up the GroupChat Orchestration
- ChatHistory history = [];
- ValueTask responseCallback(ChatMessageContent response)
- {
- history.Add(response);
- return ValueTask.CompletedTask;
- }
- // Use RoundRobinGroupChatManager to manage the conversation flow
- const string topic = "Create a slogan for a new electric SUV that is affordable and fun to drive.";
- var orchestration = new GroupChatOrchestration(
- new RoundRobinGroupChatManager { MaximumInvocationCount = 5 }, // Maximum 5 rounds of conversation
- writerAgent,
- editorAgent)
- {
- ResponseCallback = responseCallback
- };
复制代码 启动运行时
在Semantic Kernel中,需要运行时(Runtime)才能管理Agent的执行,因此这里我们需要在正式开始前使用InProcessRuntime并启动起来。- // Start the Runtime
- var runtime = new InProcessRuntime();
- await runtime.StartAsync();
复制代码 调用编排 并 收集结果
准备工作差不多了,现在我们可以开始调用编排了。
这也是老面孔代码了,不过多解释。- // Start the Chat
- Console.WriteLine($"# INPUT: {topic}{Environment.NewLine}");
- try
- {
- // Invoke the Orchestration
- var result = await orchestration.InvokeAsync(topic, runtime);
- // Collect Results from multi Agents
- var output = await result.GetValueAsync(TimeSpan.FromSeconds(10 * 3));
- // Print the Results
- Console.WriteLine($"{Environment.NewLine}# RESULT: {output}");
- Console.WriteLine($"{Environment.NewLine}#ORCHESTRATION HISTORY:{Environment.NewLine}");
- foreach (var message in history)
- {
- Console.WriteLine($"#{message.Role} - {message.AuthorName}:");
- Console.WriteLine($"{message.Content}{Environment.NewLine}");
- }
- }
- catch (HttpOperationException ex)
- {
- Console.WriteLine($"Exception: {ex.Message}");
- }
- finally
- {
- await runtime.RunUntilIdleAsync();
- Console.ResetColor();
- Console.WriteLine();
- }
复制代码 上面的代码示例中主动输出了编排过程中每个Agent的生成结果历史记录,便于我们一会儿查看。
效果展示
用户输入问题:"Create a slogan for a new electric SUV that is affordable and fun to drive."
假设客户公司有一个新产品:一辆新的电动SUV汽车,它性价比高,且驾驶乐趣足。
最终经过2个Agent的多轮对话,结果显示如下:
可以看到:
第一轮对话:Agent1-文案写手根据用户需求写了一个初稿,Agent2-审核员对这个初稿进行了初步审核。
第二轮对话:Agent1-文案写手并没有着急修改而是让审核员确认是否需要进一步完善,Agent2-审核员则在这次对话给出了一些修改建议。
第三轮对话:Agent1-文案写手根据修改建议给出了第二版,这次Agent2-审核员确认OK也没有再给出其他建议,群聊对话也就此为止结束了。
自定义群管理员
除了预定好的群管理员之外,我们还可以通过继承 GroupChatManager 来创建自定义的群管理员类,如下所示:- using Microsoft.SemanticKernel.Agents.Orchestration.GroupChat;
- using Microsoft.SemanticKernel.ChatCompletion;
- using System.Threading;
- using System.Threading.Tasks;
- public class CustomGroupChatManager : GroupChatManager
- {
- public override ValueTask<GroupChatManagerResult<string>> FilterResults(ChatHistory history, CancellationToken cancellationToken = default)
- {
- // Custom logic to filter or summarize chat results
- return ValueTask.FromResult(new GroupChatManagerResult<string>("Summary") { Reason = "Custom summary logic." });
- }
- public override ValueTask<GroupChatManagerResult<string>> SelectNextAgent(ChatHistory history, GroupChatTeam team, CancellationToken cancellationToken = default)
- {
- // Randomly select an agent from the team
- var random = new Random();
- int index = random.Next(team.Members.Count);
- string nextAgent = team.Members[index].Id;
- return ValueTask.FromResult(new GroupChatManagerResult<string>(nextAgent) { Reason = "Custom selection logic." });
- }
- public override ValueTask<GroupChatManagerResult<bool>> ShouldRequestUserInput(ChatHistory history, CancellationToken cancellationToken = default)
- {
- // Custom logic to decide if user input is needed
- return ValueTask.FromResult(new GroupChatManagerResult<bool>(false) { Reason = "No user input required." });
- }
- public override ValueTask<GroupChatManagerResult<bool>> ShouldTerminate(ChatHistory history, CancellationToken cancellationToken = default)
- {
- // Optionally call the base implementation to check for default termination logic
- var baseResult = base.ShouldTerminate(history, cancellationToken).Result;
- if (baseResult.Value)
- {
- // If the base logic says to terminate, respect it
- return ValueTask.FromResult(baseResult);
- }
- // Custom logic to determine if the chat should terminate
- bool shouldEnd = history.Count > 10; // Example: end after 10 messages
- return ValueTask.FromResult(new GroupChatManagerResult<bool>(shouldEnd) { Reason = "Custom termination logic." });
- }
- }
复制代码 定义好之后,只需要在使用群聊编排模式的时候使用这个自定义管理器即可,如下所示:- GroupChatOrchestration orchestration
- = new (new CustomGroupChatManager { MaximumInvocationCount = 5 }, ...);
复制代码 AgentChat
对于多Agent群聊来说,Semantic Kernel还提供了AgentChat的具体实现AgentGroupChat,它使用基于策略的方法来管理聊天的动态,具体实现上就是自己定义两个Strategy:SelectionStrategy 和 TerminationStrategy。- // Initialize AgentGroupChat
- var groupChat = new AgentGroupChat(reviewerAgent, writerAgent)
- {
- ExecutionSettings = new AgentGroupChatSettings()
- {
- SelectionStrategy = new KernelFunctionSelectionStrategy(selectionFunction, kernel)
- {
- InitialAgent = reviewerAgent,
- HistoryReducer = historyReducer,
- HistoryVariableName = KernelFunctionTerminationStrategy.DefaultHistoryVariableName,
- ResultParser = (result) =>
- {
- var val = result.GetValue<string>() ?? ReviewerAgent.AgentName;
- return val.ReplaceLineEndings("\n").Trim();
- }
- },
- TerminationStrategy = new KernelFunctionTerminationStrategy(terminationFunction, kernel)
- {
- Agents = [reviewerAgent],
- HistoryReducer = historyReducer,
- HistoryVariableName = KernelFunctionTerminationStrategy.DefaultHistoryVariableName,
- MaximumIterations = 10,
- ResultParser = (result) =>
- {
- var val = result.GetValue<string>() ?? string.Empty;
- return val.Contains(TerminationToken, StringComparison.OrdinalIgnoreCase);
- }
- }
- }
- };
复制代码 更多详细内容,请阅读《多Agent协作入门:AgentGroupChat》
小结
本文介绍了群聊编排模式的基本概念,然后通过一个案例介绍了如何实现一个群聊编排模式,相信通过这个案例你能够有个感性的认识。
下一篇,我们将学习移交(Handoff)编排模式,它特别适合于动态工作流、专家交接方案等应用场景。
参考资料
Microsoft Learn: https://learn.microsoft.com/zh-cn/semantic-kernel/frameworks/agent/agent-orchestration
推荐学习
圣杰:《.NET+AI | Semantic Kernel入门到精通》
作者:爱迪生
出处:https://edisontalk.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |