Group Chat enables multiple agents to participate in a coordinated conversation. An orchestrator manages the conversation flow, deciding which agent speaks next based on:
using AutoGen.Core;using AutoGen.OpenAI;using AutoGen.OpenAI.Extension;using OpenAI;var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY");var openAIClient = new OpenAIClient(apiKey);var model = "gpt-4o-mini";// Create agentsvar coder = new OpenAIChatAgent( chatClient: openAIClient.GetChatClient(model), name: "coder", systemMessage: "You are a C# coder. Write code between ```csharp and ```") .RegisterMessageConnector() .RegisterPrintMessage();var reviewer = new OpenAIChatAgent( chatClient: openAIClient.GetChatClient(model), name: "reviewer", systemMessage: "You review code for correctness and best practices") .RegisterMessageConnector() .RegisterPrintMessage();var user = new DefaultReplyAgent( name: "user", defaultReply: "END") .RegisterPrintMessage();// Create admin agent to orchestratevar admin = new OpenAIChatAgent( chatClient: openAIClient.GetChatClient(model), name: "admin") .RegisterMessageConnector();// Create group chatvar group = new GroupChat( members: [coder, reviewer, user], admin: admin);// Start conversationvar chatHistory = new List<IMessage>{ new TextMessage(Role.User, "Write a C# function to calculate factorial")};var result = await group.CallAsync(chatHistory, maxRound: 10);
Uses an admin agent and optional workflow to select speakers:
var admin = new OpenAIChatAgent( chatClient: openAIClient.GetChatClient("gpt-4"), name: "admin", systemMessage: "You coordinate the team and select the next speaker") .RegisterMessageConnector();var group = new GroupChat( members: [coder, reviewer, tester], admin: admin);
public class CustomOrchestrator : IOrchestrator{ public Task<IAgent?> GetNextSpeakerAsync( OrchestrationContext context, CancellationToken cancellationToken = default) { var lastMessage = context.ChatHistory.LastOrDefault(); // Custom logic to select next speaker if (lastMessage?.From == "coder") return Task.FromResult(context.Candidates .FirstOrDefault(a => a.Name == "reviewer")); // Return null to end conversation return Task.FromResult<IAgent?>(null); }}var group = new GroupChat( members: [coder, reviewer], orchestrator: new CustomOrchestrator());
var coder = new OpenAIChatAgent( chatClient: openAIClient.GetChatClient(model), name: "coder", systemMessage: "You write C# code") .RegisterMessageConnector() .RegisterPrintMessage();var commenter = new OpenAIChatAgent( chatClient: openAIClient.GetChatClient(model), name: "commenter", systemMessage: "You add inline comments to code") .RegisterMessageConnector() .RegisterPrintMessage();var user = new DefaultReplyAgent("user", "END") .RegisterPrintMessage();
2
Define workflow
// User -> Coder -> Commenter -> Uservar workflow = new Graph();workflow.AddTransition(Transition.Create(user, coder));workflow.AddTransition(Transition.Create(coder, commenter));workflow.AddTransition(Transition.Create(commenter, user));
3
Create group chat
var group = new GroupChat( members: [coder, commenter, user], workflow: workflow);
4
Run conversation
var instruction = new TextMessage( Role.User, @"Workflow: User asks question -> Coder writes code -> Commenter adds comments -> User confirms");var question = new TextMessage( Role.User, "Write a function to check if a number is prime");var history = new List<IMessage> { instruction, question };var result = await group.CallAsync(history, maxRound: 10);
Complete example with Semantic Kernel integration:
using AutoGen.Core;using AutoGen.OpenAI;using AutoGen.OpenAI.Extension;using AutoGen.SemanticKernel;using AutoGen.SemanticKernel.Extension;using Microsoft.SemanticKernel;using OpenAI;public class DynamicGroupChatExample{ public static async Task RunAsync() { var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY"); var model = "gpt-4o-mini"; var openAIClient = new OpenAIClient(apiKey); // Create coder with OpenAI var coder = new OpenAIChatAgent( chatClient: openAIClient.GetChatClient(model), name: "coder", systemMessage: @" You are a C# coder. When writing code, put it between ```csharp and ``` ") .RegisterMessageConnector() .RegisterPrintMessage(); // Create commenter with Semantic Kernel var kernel = Kernel .CreateBuilder() .AddOpenAIChatCompletion(modelId: model, apiKey: apiKey) .Build(); var commenter = new SemanticKernelAgent( kernel: kernel, name: "commenter", systemMessage: @" You write inline comments for code. Add unit tests if necessary. ") .RegisterMessageConnector() .RegisterPrintMessage(); // Create user proxy var userProxy = new DefaultReplyAgent("user", defaultReply: "END") .RegisterPrintMessage(); // Create admin for orchestration var admin = new OpenAIChatAgent( chatClient: openAIClient.GetChatClient(model), name: "admin") .RegisterMessageConnector(); // Create group var group = new GroupChat( members: [coder, commenter, userProxy], admin: admin); // Define workflow instruction var workflowInstruction = new TextMessage( Role.User, @" Workflow: User asks question -> Coder writes code Coder writes code -> Commenter adds comments Commenter adds comments -> User ends with END "); var question = new TextMessage( Role.User, "How to calculate the 100th Fibonacci number?"); var chatHistory = new List<IMessage> { workflowInstruction, question }; // Run group chat while (true) { var replies = await group.CallAsync(chatHistory, maxRound: 1); var lastReply = replies.Last(); chatHistory.Add(lastReply); if (lastReply.From == userProxy.Name) { break; } } // Summarize conversation var summary = await coder.SendAsync( "Summarize the conversation", chatHistory: chatHistory); }}
Provide context that persists across conversations:
var contextMessages = new List<IMessage>{ new TextMessage(Role.System, "You are working on a financial application"), new TextMessage(Role.System, "Follow company coding standards"), new TextMessage(Role.System, "All currency calculations use decimal type")};var group = new GroupChat( members: agents, admin: admin, initializeMessages: contextMessages);
var history = new List<IMessage> { initialMessage };for (int i = 0; i < maxRounds; i++){ var replies = await group.CallAsync(history, maxRound: 1); var lastReply = replies.Last(); Console.WriteLine($"Round {i + 1}: {lastReply.From} said: {lastReply.GetContent()}"); history.Add(lastReply); if (ShouldTerminate(lastReply)) { break; }}