
AutoGen.NET GroupChat 动态群聊从 Admin 智能选角到 Graph 工作流编排【免费下载链接】autogenA programming framework for agentic AI项目地址: https://gitcode.com/GitHub_Trending/au/autogen在 AutoGen.NET 中AutoGen.Core.GroupChat提供了让多个智能体协作解决复杂任务的群聊容器它既可以完全依赖 admin 智能体基于对话上下文“角色扮演”式地决定下一个发言者也可以结合AutoGen.Core.Graph工作流来约束和控制对话走向是“动态”与“可控”兼顾的下一步发言者选择方案。读完本文你能掌握GroupChat的三种编排模式及其源码级实现原理并能完整复现官方“代码解释器”示例——由 admin、coder、reviewer、runner 四个智能体协作计算第 39 个 Fibonacci 数。一、GroupChat 的三种编排模式GroupChat的构造函数见 GroupChat.cs决定了群聊由哪个编排器IOrchestrator负责挑选下一个发言者。从源码结构看选择逻辑非常明确传入参数组合使用的编排器下一步发言者如何确定传了admin可选同时传workflowRolePlayOrchestratoradmin 通过角色扮演提示词从候选中选择只传workflowWorkflowOrchestrator完全由 Graph 中的转移条件决定两者都不传RoundRobinOrchestrator按成员列表顺序轮询对应的核心构造逻辑如下// dotnet/src/AutoGen.Core/GroupChat/GroupChat.cs节选 if (admin is not null) { this.orchestrator new RolePlayOrchestrator(admin, workflow); } else if (workflow is not null) { this.orchestrator new WorkflowOrchestrator(workflow); } else { this.orchestrator new RoundRobinOrchestrator(); }构造函数同时做了三项校验GroupChat.cs所有智能体必须有名字、名字必须唯一、且工作流中出现的智能体必须都在群聊成员之中。Admin 的“角色扮演”选角机制RolePlayOrchestratorRolePlayOrchestrator.cs的选择流程分两步候选收窄如果配置了workflow先调用workflow.TransitToNextAvailableAgentsAsync(currentSpeaker, chatHistory)从当前发言者出发得到可达智能体列表。若只剩 1 个候选直接返回不调用 admin若超过 1 个才进入第 2 步。admin 角色扮演把候选名字拼进如下系统提示词并把整段对话历史改写为From {名字}: ... eof_msg round # {i}的形式发给 adminYou are in a role play game. Carefully read the conversation history and carry on the conversation. The available roles are: {候选智能体名字列表} Each message will start with From name:, e.g: From {第一个候选名字}: //your message//.请求参数被刻意收紧为确定性输出Temperature 0、MaxToken 128、StopSequence [:]RolePlayOrchestrator.cs并要求 admin 的回复形如From coder:编排器随后截取冒号后的名字name.Substring(5)在候选中做大小写不敏感匹配匹配失败会抛出带详细信息的ArgumentException。官方文档特别提示当群聊仅由 admin 决定下一个发言者没有 Graph 约束时建议使用能力更强的模型如gpt-4以获得最佳体验因为此时选角质量完全依赖 admin 的上下文理解能力。Graph 工作流Transition 与转移条件Graph与Transition定义在 Graph.cs 中。Graph本质是一个转移边集合TransitToNextAvailableAgentsAsync(fromAgent, messages)会筛出所有From fromAgent的边并逐条调用其CanTransitionAsync(messages)谓词把满足条件的目标智能体作为“下一可达候选”返回Graph.cs。Transition.Create提供三个重载Graph.cs// 1. 无条件转移恒为 true Transition.Create(admin, coder); // 2. 带转移条件根据消息历史返回 true/false Transition.Create( from: reviewer, to: runner, canTransitionAsync: async (from, to, messages) { var lastMessage messages.Last(); return lastMessage is TextMessage t t.Content.ToLower().Contains(the code looks good); }); // 3. 额外支持 CancellationToken 的重载 Transition.Create(from, to, (from, to, messages, ct) ...);这意味着工作流是“条件化”的同一个 from 智能体可以连出多条边例如 reviewer 既能转 runner 也能转 coder由边上的谓词依据最近消息内容决定实际走哪条路。WorkflowOrchestratorWorkflowOrchestrator.cs则是纯工作流模式它取最后一条消息的发送者为当前发言者查 Graph 得到下一可达集合若集合为空则返回null群聊终止若恰好 1 个则直接返回若出现多于 1 个候选会抛出异常——即纯工作流模式下每个状态点必须能唯一确定下一跳。二、群聊的运行循环与终止信号群聊主循环在GroupChat.CallAsyncGroupChat.cs中每一轮先由编排器选出下一发言者调用其GenerateReplyAsync(conversationHistory)把回复追加进历史若回复是群聊终止消息则立即返回完整历史否则消耗maxRound默认 10配额。终止与清理信号由 GroupChatExtension.cs 定义消息内容包含TERMINATE即判定为终止消息IsGroupChatTerminateMessage包含CLEAR_MESSAGES时由MessageToKeep截断历史。对外使用的流式扩展方法SendAsync会循环调用CallAsync(..., maxRound: 1)逐条yield return最新消息直到终止消息或轮次耗尽这让调用方可以在消费消息流的过程中随时检测任务完成并提前break下面示例正是这么做的。此外还有介绍消息扩展GroupChatExtension.cs// 为智能体发送自我介绍作为群聊的初始上下文initializeMessages public static void SendIntroduction(this IAgent agent, string message, IGroupChat groupChat);官方文档提示用SendIntroduction为群聊设置初始上下文能帮助 admin 更好地组织对话流程。三、实战示例四智能体“代码解释器”群聊官方示例 Example07_Dynamic_GroupChat_Calculate_Fibonacci.cs 构建了一个计算“第 39 个 Fibonacci 数”正确答案 63245986的动态群聊成员及职责如下admin为群组创建任务并在任务完成时终止对话coder会写 dotnet 代码的智能体reviewer代码审查者检查 coder 的代码是否满足只有一个 C# 代码块、使用顶层语句、是 dotnet 代码、把结果打印到控制台runner代码执行者运行 coder 写出的代码并打印结果。对话结构可概括为3.1 创建动态群聊纯 admin 驱动示例的RunAsync中创建群聊的核心代码源码create_group_chat区域Example07...csvar reviewer await CreateReviewerAgentAsync(gpt4o); var coder await CreateCoderAgentAsync(gpt4o); var runner await CreateRunnerAgentAsync(kernel); var admin await CreateAdminAsync(gpt4o); var groupChat new GroupChat( admin: admin, members: [ coder, runner, reviewer, ]); coder.SendIntroduction(I will write dotnet code to resolve task, groupChat); reviewer.SendIntroduction(I will review dotnet code, groupChat); runner.SendIntroduction(I will run dotnet code once the review is done, groupChat); var task Whats the 39th of fibonacci number?; var taskMessage new TextMessage(Role.User, task); await foreach (var message in groupChat.SendAsync([taskMessage], maxRound: 10)) { // 当 runner 的消息中包含答案时终止群聊 if (message.From runner message.GetContent().Contains(the39thFibonacciNumber.ToString())) { Console.WriteLine($The 39th of fibonacci number is {the39thFibonacciNumber}); break; } }注意这里没有传workflow因此按前文的构造逻辑群聊完全由 admin 通过角色扮演提示词驱动——这也正是官方建议使用强模型的典型场景。3.2 四个智能体的实现拆解admincreate_admin区域L123-L135就是一个temperature: 0的OpenAIChatAgent叠加RegisterMessageConnector()把 AutoGen 消息转换为 Chat Completions 格式和RegisterPrintMessage()打印消息两个扩展。codercreate_coder区域L52-L80temperature: 0.4f的OpenAIChatAgent其系统提示词把“代码规范”写成硬约束——代码放在csharp围栏中、使用顶层语句、避免using可释放对象、结果必须打印到控制台、需要 NuGet 包时用nuget块声明、出错后根据 runner 的报错修复代码重发var coder new OpenAIChatAgent( chatClient: client, name: coder, systemMessage: You act as dotnet coder, you write dotnet code to resolve task. Once you finish writing code, ask runner to run the code for you. Herere some rules to follow on writing dotnet code: - put code between csharp and - Avoid adding using keyword when creating disposable object. e.g var httpClient new HttpClient() - Try to use var instead of explicit type. - Try avoid using external library, use .NET Core library instead. - Use top level statement to write code. - Always print out the result to console. Dont write code that doesnt print out anything. ... If your code is incorrect, runner will tell you the error message. Fix the error and send the code again., temperature: 0.4f) .RegisterMessageConnector() .RegisterPrintMessage();reviewercreate_reviewer区域L137-L227这是示例中最有技术含量的部分展示了 AutoGen.NET 的类型安全函数调用机制。先用[Function]特性标注一个普通方法配套的reviewer_function区域L17-L50public struct CodeReviewResult { public bool HasMultipleCodeBlocks { get; set; } public bool IsTopLevelStatement { get; set; } public bool IsDotnetCodeBlock { get; set; } public bool IsPrintResultToConsole { get; set; } } [Function] public async Taskstring ReviewCodeBlock( bool hasMultipleCodeBlocks, bool isTopLevelStatement, bool isDotnetCodeBlock, bool isPrintResultToConsole) { var obj new CodeReviewResult { ... }; return JsonSerializer.Serialize(obj); }[Function]特性由 AutoGen.SourceGenerator 在编译期生成ReviewCodeBlockFunctionContract函数契约供模型侧使用与ReviewCodeBlockWrapper参数序列化/反序列化的调用包装详见 Create-type-safe-function-call.md。reviewer 用FunctionCallMiddleware把契约挂给模型var functionCallMiddleware new FunctionCallMiddleware( functions: [functions.ReviewCodeBlockFunctionContract], functionMap: new Dictionarystring, Funcstring, Taskstring() { { nameof(functions.ReviewCodeBlock), functions.ReviewCodeBlockWrapper }, }); var reviewer new OpenAIChatAgent(chatClient: chatClient, name: code_reviewer, systemMessage: You review code block from coder) .RegisterMessageConnector() .RegisterStreamingMiddleware(functionCallMiddleware) .RegisterMiddleware(async (msgs, option, innerAgent, ct) { // 最多重试 3 次直到模型真正发起 ReviewCodeBlock 工具调用 var maxRetry 3; var reply await innerAgent.GenerateReplyAsync(msgs, option, ct); while (maxRetry-- 0) { if (reply.GetToolCalls() is var toolCalls toolCalls.Count 1 toolCalls[0].FunctionName nameof(ReviewCodeBlock)) { var reviewResultObj JsonSerializer.DeserializeCodeReviewResult(reply.GetContent()); // 逐项检查多代码块 / 非 dotnet / 非顶层语句 / 未打印结果 // 有问题则汇总成 Therere some comments from code reviewer, please fix these comments // 无问题则返回 The code looks good, please ask runner to run the code for you. } else { // 模型没走函数调用提示词引导它把内容转成函数参数再试一次 reply await innerAgent.SendAsync(prompt, msgs, ct); } } throw new Exception(Failed to review code block); }) .RegisterPrintMessage();可以看到 reviewer 通过**中间件middleware**在 LLM 调用外层实现了“校验—重试—给出结构化审查意见”的确定性控制审查结论是布尔结构体而非自由文本四条检查项分别对应不同的修复提示这使 coder 的修复方向明确可预期。runnercreate_runner区域L82-L121不是 LLM 智能体而是DefaultReplyAgent 自定义中间件构成的“工具型智能体”。它只关心来自coder的最后一条消息用ExtractCodeBlock(csharp, )抽出代码交给 AutoGen.DotnetInteractive 的 dotnet interactive kernel 执行内置执行能力说明见 Run-dotnet-code.mdvar runner new DefaultReplyAgent(name: runner, defaultReply: No code available.) .RegisterMiddleware(async (msgs, option, agent, _) { if (msgs.Any() || msgs.All(msg msg.From ! coder)) { return new TextMessage(Role.Assistant, No code available. Coder please write code); } else { var coderMsg msgs.Last(msg msg.From coder); if (coderMsg.ExtractCodeBlock(csharp, ) is string code) { var codeResult await kernel.RunSubmitCodeCommandAsync(code, csharp); return new TextMessage(Role.Assistant, $ [RUNNER_RESULT] {codeResult} ) { From runner }; } ... } }) .RegisterPrintMessage();执行结果被包上[RUNNER_RESULT]标记返回失败时错误信息会直接成为 coder 修复代码的输入形成 coder ↔ reviewer ↔ runner 的闭环。3.3 进阶用 Graph 工作流控制对话流程同一个示例还提供了RunWorkflowAsyncL229-L330展示如何用Graph把隐式流程变成显式状态机。转移边定义create_workflow区域如下var admin2CoderTransition Transition.Create(admin, coder); var coder2ReviewerTransition Transition.Create(coder, reviewer); var reviewer2RunnerTransition Transition.Create( from: reviewer, to: runner, canTransitionAsync: async (from, to, messages) { var lastMessage messages.Last(); // reviewer 说“代码没问题”才允许进入 runner return lastMessage is TextMessage textMessage textMessage.Content.ToLower().Contains(the code looks good, please ask runner to run the code for you.); }); var reviewer2CoderTransition Transition.Create( from: reviewer, to: coder, canTransitionAsync: async (from, to, messages) { var lastMessage messages.Last(); // reviewer 有审查意见时回到 coder 修复 return lastMessage is TextMessage textMessage textMessage.Content.ToLower().Contains(therere some comments from code reviewer, please fix these comments); }); var runner2CoderTransition Transition.Create( from: runner, to: coder, canTransitionAsync: async (from, to, messages) { var lastMessage messages.Last(); // 运行报错时回到 coder return lastMessage is TextMessage textMessage textMessage.Content.ToLower().Contains(error); }); var runner2AdminTransition Transition.Create(runner, admin); var workflow new Graph( [ admin2CoderTransition, coder2ReviewerTransition, reviewer2RunnerTransition, reviewer2CoderTransition, runner2CoderTransition, runner2AdminTransition, ]);然后把workflow与admin同时传给GroupChatcreate_group_chat_with_workflow区域var groupChat new GroupChat( admin: admin, workflow: workflow, members: [admin, coder, runner, reviewer]);这种“admin workflow”组合对应RolePlayOrchestrator的完整行为优先按 Graph 收窄候选本例中每条转移条件互斥几乎总能唯一确定下一跳因此很少真正调用 admin只有当 Graph 给出多个候选时才交给 admin 仲裁。相比纯 admin 模式这种写法把“reviewer 通过 → runner”“reviewer 打回 → coder”“运行报错 → coder”等关键流转固化成了代码对话走向更可预测、可测试。四、关键要点回顾GroupChat构造时按admin/workflow的组合自动选择编排器admin →RolePlayOrchestrator角色扮演提示词Temperature0、MaxToken128、以:停止、要求输出From 名字:格式仅 workflow →WorkflowOrchestrator唯一下一跳多候选直接报错都不传 →RoundRobinOrchestrator轮询。相关实现见 GroupChat.cs、Orchestrator 目录。纯 admin 驱动时建议用强模型官方 NOTE 建议如gpt-4示例当前使用LLMConfiguration.GetOpenAIGPT4o_mini()。SendIntroduction提供群聊初始上下文SendAsync流式返回消息配合TERMINATE终止信号可提前结束群聊。Transition.Create的canTransitionAsync谓词让工作流“条件化”Graph.TransitToNextAvailableAgentsAsync负责按当前发言者求下一可达集合。示例展示了完整的工程组合拳类型安全函数调用[Function] Source Generator、中间件实现的审查重试逻辑、dotnet interactive 内核执行代码片段。群聊/编排器的单元测试可参考 Orchestrator 测试 与 GroupChat 测试。相关文档Group-chat-overview.md、Roundrobin-chat.md、Use-graph-in-group-chat.md、Create-type-safe-function-call.md、Run-dotnet-code.md。【免费下载链接】autogenA programming framework for agentic AI项目地址: https://gitcode.com/GitHub_Trending/au/autogen创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。