態(tài)群聊:從 Admin 智能選角到 Graph 工作流編排)
AutoGen.NET GroupChat 動(dòng)態(tài)群聊從 Admin 智能選角到 Graph 工作流編排【免費(fèi)下載鏈接】autogenA programming framework for agentic AI項(xiàng)目地址: https://gitcode.com/GitHub_Trending/au/autogen在 AutoGen.NET 中AutoGen.Core.GroupChat提供了讓多個(gè)智能體協(xié)作解決復(fù)雜任務(wù)的群聊容器它既可以完全依賴 admin 智能體基于對(duì)話上下文“角色扮演”式地決定下一個(gè)發(fā)言者也可以結(jié)合AutoGen.Core.Graph工作流來(lái)約束和控制對(duì)話走向是“動(dòng)態(tài)”與“可控”兼顧的下一步發(fā)言者選擇方案。讀完本文你能掌握GroupChat的三種編排模式及其源碼級(jí)實(shí)現(xiàn)原理并能完整復(fù)現(xiàn)官方“代碼解釋器”示例——由 admin、coder、reviewer、runner 四個(gè)智能體協(xié)作計(jì)算第 39 個(gè) Fibonacci 數(shù)。一、GroupChat 的三種編排模式GroupChat的構(gòu)造函數(shù)見(jiàn) GroupChat.cs決定了群聊由哪個(gè)編排器IOrchestrator負(fù)責(zé)挑選下一個(gè)發(fā)言者。從源碼結(jié)構(gòu)看選擇邏輯非常明確傳入?yún)?shù)組合使用的編排器下一步發(fā)言者如何確定傳了admin可選同時(shí)傳workflowRolePlayOrchestratoradmin 通過(guò)角色扮演提示詞從候選中選擇只傳workflowWorkflowOrchestrator完全由 Graph 中的轉(zhuǎn)移條件決定兩者都不傳RoundRobinOrchestrator按成員列表順序輪詢對(duì)應(yīng)的核心構(gòu)造邏輯如下// dotnet/src/AutoGen.Core/GroupChat/GroupChat.cs節(jié)選 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(); }構(gòu)造函數(shù)同時(shí)做了三項(xiàng)校驗(yàn)GroupChat.cs所有智能體必須有名字、名字必須唯一、且工作流中出現(xiàn)的智能體必須都在群聊成員之中。Admin 的“角色扮演”選角機(jī)制RolePlayOrchestratorRolePlayOrchestrator.cs的選擇流程分兩步候選收窄如果配置了workflow先調(diào)用workflow.TransitToNextAvailableAgentsAsync(currentSpeaker, chatHistory)從當(dāng)前發(fā)言者出發(fā)得到可達(dá)智能體列表。若只剩 1 個(gè)候選直接返回不調(diào)用 admin若超過(guò) 1 個(gè)才進(jìn)入第 2 步。admin 角色扮演把候選名字拼進(jìn)如下系統(tǒng)提示詞并把整段對(duì)話歷史改寫(xiě)為From {名字}: ... eof_msg round # {i}的形式發(fā)給 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 {第一個(gè)候選名字}: //your message//.請(qǐng)求參數(shù)被刻意收緊為確定性輸出Temperature 0、MaxToken 128、StopSequence [:]RolePlayOrchestrator.cs并要求 admin 的回復(fù)形如From coder:編排器隨后截取冒號(hào)后的名字name.Substring(5)在候選中做大小寫(xiě)不敏感匹配匹配失敗會(huì)拋出帶詳細(xì)信息的ArgumentException。官方文檔特別提示當(dāng)群聊僅由 admin 決定下一個(gè)發(fā)言者沒(méi)有 Graph 約束時(shí)建議使用能力更強(qiáng)的模型如gpt-4以獲得最佳體驗(yàn)因?yàn)榇藭r(shí)選角質(zhì)量完全依賴 admin 的上下文理解能力。Graph 工作流Transition 與轉(zhuǎn)移條件Graph與Transition定義在 Graph.cs 中。Graph本質(zhì)是一個(gè)轉(zhuǎn)移邊集合TransitToNextAvailableAgentsAsync(fromAgent, messages)會(huì)篩出所有From fromAgent的邊并逐條調(diào)用其CanTransitionAsync(messages)謂詞把滿足條件的目標(biāo)智能體作為“下一可達(dá)候選”返回Graph.cs。Transition.Create提供三個(gè)重載Graph.cs// 1. 無(wú)條件轉(zhuǎn)移恒為 true Transition.Create(admin, coder); // 2. 帶轉(zhuǎn)移條件根據(jù)消息歷史返回 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) ...);這意味著工作流是“條件化”的同一個(gè) from 智能體可以連出多條邊例如 reviewer 既能轉(zhuǎn) runner 也能轉(zhuǎn) coder由邊上的謂詞依據(jù)最近消息內(nèi)容決定實(shí)際走哪條路。WorkflowOrchestratorWorkflowOrchestrator.cs則是純工作流模式它取最后一條消息的發(fā)送者為當(dāng)前發(fā)言者查 Graph 得到下一可達(dá)集合若集合為空則返回null群聊終止若恰好 1 個(gè)則直接返回若出現(xiàn)多于 1 個(gè)候選會(huì)拋出異?!醇児ぷ髁髂J较旅總€(gè)狀態(tài)點(diǎn)必須能唯一確定下一跳。二、群聊的運(yùn)行循環(huán)與終止信號(hào)群聊主循環(huán)在GroupChat.CallAsyncGroupChat.cs中每一輪先由編排器選出下一發(fā)言者調(diào)用其GenerateReplyAsync(conversationHistory)把回復(fù)追加進(jìn)歷史若回復(fù)是群聊終止消息則立即返回完整歷史否則消耗maxRound默認(rèn) 10配額。終止與清理信號(hào)由 GroupChatExtension.cs 定義消息內(nèi)容包含TERMINATE即判定為終止消息IsGroupChatTerminateMessage包含CLEAR_MESSAGES時(shí)由MessageToKeep截?cái)鄽v史。對(duì)外使用的流式擴(kuò)展方法SendAsync會(huì)循環(huán)調(diào)用CallAsync(..., maxRound: 1)逐條yield return最新消息直到終止消息或輪次耗盡這讓調(diào)用方可以在消費(fèi)消息流的過(guò)程中隨時(shí)檢測(cè)任務(wù)完成并提前break下面示例正是這么做的。此外還有介紹消息擴(kuò)展GroupChatExtension.cs// 為智能體發(fā)送自我介紹作為群聊的初始上下文initializeMessages public static void SendIntroduction(this IAgent agent, string message, IGroupChat groupChat);官方文檔提示用SendIntroduction為群聊設(shè)置初始上下文能幫助 admin 更好地組織對(duì)話流程。三、實(shí)戰(zhàn)示例四智能體“代碼解釋器”群聊官方示例 Example07_Dynamic_GroupChat_Calculate_Fibonacci.cs 構(gòu)建了一個(gè)計(jì)算“第 39 個(gè) Fibonacci 數(shù)”正確答案 63245986的動(dòng)態(tài)群聊成員及職責(zé)如下admin為群組創(chuàng)建任務(wù)并在任務(wù)完成時(shí)終止對(duì)話coder會(huì)寫(xiě) dotnet 代碼的智能體reviewer代碼審查者檢查 coder 的代碼是否滿足只有一個(gè) C# 代碼塊、使用頂層語(yǔ)句、是 dotnet 代碼、把結(jié)果打印到控制臺(tái)runner代碼執(zhí)行者運(yùn)行 coder 寫(xiě)出的代碼并打印結(jié)果。對(duì)話結(jié)構(gòu)可概括為3.1 創(chuàng)建動(dòng)態(tài)群聊純 admin 驅(qū)動(dòng)示例的RunAsync中創(chuàng)建群聊的核心代碼源碼create_group_chat區(qū)域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)) { // 當(dāng) runner 的消息中包含答案時(shí)終止群聊 if (message.From runner message.GetContent().Contains(the39thFibonacciNumber.ToString())) { Console.WriteLine($The 39th of fibonacci number is {the39thFibonacciNumber}); break; } }注意這里沒(méi)有傳workflow因此按前文的構(gòu)造邏輯群聊完全由 admin 通過(guò)角色扮演提示詞驅(qū)動(dòng)——這也正是官方建議使用強(qiáng)模型的典型場(chǎng)景。3.2 四個(gè)智能體的實(shí)現(xiàn)拆解admincreate_admin區(qū)域L123-L135就是一個(gè)temperature: 0的OpenAIChatAgent疊加RegisterMessageConnector()把 AutoGen 消息轉(zhuǎn)換為 Chat Completions 格式和RegisterPrintMessage()打印消息兩個(gè)擴(kuò)展。codercreate_coder區(qū)域L52-L80temperature: 0.4f的OpenAIChatAgent其系統(tǒng)提示詞把“代碼規(guī)范”寫(xiě)成硬約束——代碼放在csharp圍欄中、使用頂層語(yǔ)句、避免using可釋放對(duì)象、結(jié)果必須打印到控制臺(tái)、需要 NuGet 包時(shí)用nuget塊聲明、出錯(cuò)后根據(jù) runner 的報(bào)錯(cuò)修復(fù)代碼重發(fā)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區(qū)域L137-L227這是示例中最有技術(shù)含量的部分展示了 AutoGen.NET 的類型安全函數(shù)調(diào)用機(jī)制。先用[Function]特性標(biāo)注一個(gè)普通方法配套的reviewer_function區(qū)域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函數(shù)契約供模型側(cè)使用與ReviewCodeBlockWrapper參數(shù)序列化/反序列化的調(diào)用包裝詳見(jiàn) 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 次直到模型真正發(fā)起 ReviewCodeBlock 工具調(diào)用 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()); // 逐項(xiàng)檢查多代碼塊 / 非 dotnet / 非頂層語(yǔ)句 / 未打印結(jié)果 // 有問(wèn)題則匯總成 Therere some comments from code reviewer, please fix these comments // 無(wú)問(wèn)題則返回 The code looks good, please ask runner to run the code for you. } else { // 模型沒(méi)走函數(shù)調(diào)用提示詞引導(dǎo)它把內(nèi)容轉(zhuǎn)成函數(shù)參數(shù)再試一次 reply await innerAgent.SendAsync(prompt, msgs, ct); } } throw new Exception(Failed to review code block); }) .RegisterPrintMessage();可以看到 reviewer 通過(guò)**中間件middleware**在 LLM 調(diào)用外層實(shí)現(xiàn)了“校驗(yàn)—重試—給出結(jié)構(gòu)化審查意見(jiàn)”的確定性控制審查結(jié)論是布爾結(jié)構(gòu)體而非自由文本四條檢查項(xiàng)分別對(duì)應(yīng)不同的修復(fù)提示這使 coder 的修復(fù)方向明確可預(yù)期。runnercreate_runner區(qū)域L82-L121不是 LLM 智能體而是DefaultReplyAgent 自定義中間件構(gòu)成的“工具型智能體”。它只關(guān)心來(lái)自coder的最后一條消息用ExtractCodeBlock(csharp, )抽出代碼交給 AutoGen.DotnetInteractive 的 dotnet interactive kernel 執(zhí)行內(nèi)置執(zhí)行能力說(shuō)明見(jiàn) 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();執(zhí)行結(jié)果被包上[RUNNER_RESULT]標(biāo)記返回失敗時(shí)錯(cuò)誤信息會(huì)直接成為 coder 修復(fù)代碼的輸入形成 coder ? reviewer ? runner 的閉環(huán)。3.3 進(jìn)階用 Graph 工作流控制對(duì)話流程同一個(gè)示例還提供了RunWorkflowAsyncL229-L330展示如何用Graph把隱式流程變成顯式狀態(tài)機(jī)。轉(zhuǎn)移邊定義create_workflow區(qū)域如下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 說(shuō)“代碼沒(méi)問(wèn)題”才允許進(jìn)入 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 有審查意見(jiàn)時(shí)回到 coder 修復(fù) 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(); // 運(yùn)行報(bào)錯(cuò)時(shí)回到 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同時(shí)傳給GroupChatcreate_group_chat_with_workflow區(qū)域var groupChat new GroupChat( admin: admin, workflow: workflow, members: [admin, coder, runner, reviewer]);這種“admin workflow”組合對(duì)應(yīng)RolePlayOrchestrator的完整行為優(yōu)先按 Graph 收窄候選本例中每條轉(zhuǎn)移條件互斥幾乎總能唯一確定下一跳因此很少真正調(diào)用 admin只有當(dāng) Graph 給出多個(gè)候選時(shí)才交給 admin 仲裁。相比純 admin 模式這種寫(xiě)法把“reviewer 通過(guò) → runner”“reviewer 打回 → coder”“運(yùn)行報(bào)錯(cuò) → coder”等關(guān)鍵流轉(zhuǎn)固化成了代碼對(duì)話走向更可預(yù)測(cè)、可測(cè)試。四、關(guān)鍵要點(diǎn)回顧GroupChat構(gòu)造時(shí)按admin/workflow的組合自動(dòng)選擇編排器admin →RolePlayOrchestrator角色扮演提示詞Temperature0、MaxToken128、以:停止、要求輸出From 名字:格式僅 workflow →WorkflowOrchestrator唯一下一跳多候選直接報(bào)錯(cuò)都不傳 →RoundRobinOrchestrator輪詢。相關(guān)實(shí)現(xiàn)見(jiàn) GroupChat.cs、Orchestrator 目錄。純 admin 驅(qū)動(dòng)時(shí)建議用強(qiáng)模型官方 NOTE 建議如gpt-4示例當(dāng)前使用LLMConfiguration.GetOpenAIGPT4o_mini()。SendIntroduction提供群聊初始上下文SendAsync流式返回消息配合TERMINATE終止信號(hào)可提前結(jié)束群聊。Transition.Create的canTransitionAsync謂詞讓工作流“條件化”Graph.TransitToNextAvailableAgentsAsync負(fù)責(zé)按當(dāng)前發(fā)言者求下一可達(dá)集合。示例展示了完整的工程組合拳類型安全函數(shù)調(diào)用[Function] Source Generator、中間件實(shí)現(xiàn)的審查重試邏輯、dotnet interactive 內(nèi)核執(zhí)行代碼片段。群聊/編排器的單元測(cè)試可參考 Orchestrator 測(cè)試 與 GroupChat 測(cè)試。相關(guān)文檔Group-chat-overview.md、Roundrobin-chat.md、Use-graph-in-group-chat.md、Create-type-safe-function-call.md、Run-dotnet-code.md。【免費(fèi)下載鏈接】autogenA programming framework for agentic AI項(xiàng)目地址: https://gitcode.com/GitHub_Trending/au/autogen創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考