그룹 채팅 오케스트레이션은 여러 에이전트 간의 공동 대화를 모델로 하며, 관리자가 화자 선택 및 대화 흐름을 결정합니다. 이 패턴은 반복적인 구체화, 공동 작업 문제 해결 또는 다중 관점 분석이 필요한 시나리오에 적합합니다.
그룹 채팅과 기타 패턴의 차이점
그룹 채팅 오케스트레이션에는 다른 다중 에이전트 패턴에 비해 고유한 특성이 있습니다.
- 중앙 집중식 조정: 에이전트가 직접 제어를 전송하는 핸드오프 패턴과 달리 그룹 채팅은 관리자를 사용하여 다음에 말하는 사람을 조정합니다.
- 반복 구체화: 에이전트는 여러 번의 라운드에 걸쳐 서로의 응답을 검토하고 발전시킬 수 있습니다.
- 유연한 발표자 선택: 관리자는 다양한 전략(라운드 로빈, 프롬프트 기반 사용자 지정 논리)을 사용하여 스피커를 선택할 수 있습니다.
- 공유 컨텍스트: 모든 에이전트가 전체 대화 기록을 확인하여 공동 작업을 구체화할 수 있습니다.
학습 내용
- 그룹 공동 작업을 위한 특수 에이전트를 만드는 방법
- 화자 선택 전략을 구성하는 방법
- 반복 에이전트 구체화를 사용하여 워크플로를 빌드하는 방법
- 사용자 지정 관리자를 사용하여 대화 흐름을 사용자 지정하는 방법
Azure OpenAI 클라이언트 설정
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Extensions.AI;
using Microsoft.Agents.AI;
// Set up the Azure OpenAI client
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ??
throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
var client = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetChatClient(deploymentName)
.AsIChatClient();
에이전트 설정
그룹 대화에서 다양한 역할에 대한 특수 에이전트를 만듭니다.
// Create a copywriter agent
ChatClientAgent writer = new(client,
"You are a creative copywriter. Generate catchy slogans and marketing copy. Be concise and impactful.",
"CopyWriter",
"A creative copywriter agent");
// Create a reviewer agent
ChatClientAgent reviewer = new(client,
"You are a marketing reviewer. Evaluate slogans for clarity, impact, and brand alignment. " +
"Provide constructive feedback or approval.",
"Reviewer",
"A marketing review agent");
Round-Robin Manager를 사용하여 그룹 채팅 구성
다음을 사용하여 그룹 채팅 워크플로를 구축합니다: AgentWorkflowBuilder.
// Build group chat with round-robin speaker selection
// The manager factory receives the list of agents and returns a configured manager
var workflow = AgentWorkflowBuilder
.CreateGroupChatBuilderWith(agents =>
new RoundRobinGroupChatManager(agents)
{
MaximumIterationCount = 5 // Maximum number of turns
})
.AddParticipants(writer, reviewer)
.Build();
그룹 채팅 워크플로 실행
워크플로를 실행하고 반복 대화를 관찰합니다.
// Start the group chat
var messages = new List<ChatMessage> {
new(ChatRole.User, "Create a slogan for an eco-friendly electric vehicle.")
};
StreamingRun run = await InProcessExecution.StreamAsync(workflow, messages);
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
{
if (evt is AgentRunUpdateEvent update)
{
// Process streaming agent responses
AgentRunResponse response = update.AsResponse();
foreach (ChatMessage message in response.Messages)
{
Console.WriteLine($"[{update.ExecutorId}]: {message.Text}");
}
}
else if (evt is WorkflowOutputEvent output)
{
// Workflow completed
var conversationHistory = output.As<List<ChatMessage>>();
Console.WriteLine("\n=== Final Conversation ===");
foreach (var message in conversationHistory)
{
Console.WriteLine($"{message.AuthorName}: {message.Text}");
}
break;
}
}
샘플 상호 작용
[CopyWriter]: "Green Dreams, Zero Emissions" - Drive the future with style and sustainability.
[Reviewer]: The slogan is good, but "Green Dreams" might be a bit abstract. Consider something
more direct like "Pure Power, Zero Impact" to emphasize both performance and environmental benefit.
[CopyWriter]: "Pure Power, Zero Impact" - Experience electric excellence without compromise.
[Reviewer]: Excellent! This slogan is clear, impactful, and directly communicates the key benefits.
The tagline reinforces the message perfectly. Approved for use.
[CopyWriter]: Thank you! The final slogan is: "Pure Power, Zero Impact" - Experience electric
excellence without compromise.
채팅 클라이언트 설정
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
# Initialize the Azure OpenAI chat client
chat_client = AzureOpenAIChatClient(credential=AzureCliCredential())
에이전트 설정
고유한 역할을 사용하여 특수 에이전트를 만듭니다.
from agent_framework import ChatAgent
# Create a researcher agent
researcher = ChatAgent(
name="Researcher",
description="Collects relevant background information.",
instructions="Gather concise facts that help answer the question. Be brief and factual.",
chat_client=chat_client,
)
# Create a writer agent
writer = ChatAgent(
name="Writer",
description="Synthesizes polished answers using gathered information.",
instructions="Compose clear, structured answers using any notes provided. Be comprehensive.",
chat_client=chat_client,
)
단순 선택기를 사용하여 그룹 채팅 구성
사용자 지정 화자 선택 논리를 사용하여 그룹 채팅을 빌드합니다.
from agent_framework import GroupChatBuilder, GroupChatStateSnapshot
def select_next_speaker(state: GroupChatStateSnapshot) -> str | None:
"""Alternate between researcher and writer for collaborative refinement.
Args:
state: Contains task, participants, conversation, history, and round_index
Returns:
Name of next speaker, or None to finish
"""
round_idx = state["round_index"]
history = state["history"]
# Finish after 4 turns (researcher → writer → researcher → writer)
if round_idx >= 4:
return None
# Alternate speakers
last_speaker = history[-1].speaker if history else None
if last_speaker == "Researcher":
return "Writer"
return "Researcher"
# Build the group chat workflow
workflow = (
GroupChatBuilder()
.set_select_speakers_func(select_next_speaker, display_name="Orchestrator")
.participants([researcher, writer])
.build()
)
Agent-Based Manager를 사용하여 그룹 채팅 구성
또는 지능형 화자 선택에 에이전트 기반 관리자를 사용합니다. 관리자는 도구, 컨텍스트 및 관찰성에 대한 완전한 액세스 권한을 가지고 있습니다 ChatAgent.
# Create coordinator agent for speaker selection
coordinator = ChatAgent(
name="Coordinator",
description="Coordinates multi-agent collaboration by selecting speakers",
instructions="""
You coordinate a team conversation to solve the user's task.
Review the conversation history and select the next participant to speak.
Guidelines:
- Start with Researcher to gather information
- Then have Writer synthesize the final answer
- Only finish after both have contributed meaningfully
- Allow for multiple rounds of information gathering if needed
""",
chat_client=chat_client,
)
# Build group chat with agent-based manager
workflow = (
GroupChatBuilder()
.set_manager(coordinator, display_name="Orchestrator")
.with_termination_condition(lambda messages: sum(1 for msg in messages if msg.role == Role.ASSISTANT) >= 4)
.participants([researcher, writer])
.build()
)
그룹 채팅 워크플로 실행
워크플로를 실행하고 이벤트를 처리합니다.
from typing import cast
from agent_framework import AgentRunUpdateEvent, Role, WorkflowOutputEvent
task = "What are the key benefits of async/await in Python?"
print(f"Task: {task}\n")
print("=" * 80)
final_conversation: list[ChatMessage] = []
last_executor_id: str | None = None
# Run the workflow
async for event in workflow.run_stream(task):
if isinstance(event, AgentRunUpdateEvent):
# Print streaming agent updates
eid = event.executor_id
if eid != last_executor_id:
if last_executor_id is not None:
print()
print(f"[{eid}]:", end=" ", flush=True)
last_executor_id = eid
print(event.data, end="", flush=True)
elif isinstance(event, WorkflowOutputEvent):
# Workflow completed - data is a list of ChatMessage
final_conversation = cast(list[ChatMessage], event.data)
if final_conversation:
print("\n\n" + "=" * 80)
print("Final Conversation:")
for msg in final_conversation:
author = getattr(msg, "author_name", "Unknown")
text = getattr(msg, "text", str(msg))
print(f"\n[{author}]\n{text}")
print("-" * 80)
print("\nWorkflow completed.")
샘플 상호 작용
Task: What are the key benefits of async/await in Python?
================================================================================
[Researcher]: Async/await in Python provides non-blocking I/O operations, enabling
concurrent execution without threading overhead. Key benefits include improved
performance for I/O-bound tasks, better resource utilization, and simplified
concurrent code structure using native coroutines.
[Writer]: The key benefits of async/await in Python are:
1. **Non-blocking Operations**: Allows I/O operations to run concurrently without
blocking the main thread, significantly improving performance for network
requests, file I/O, and database queries.
2. **Resource Efficiency**: Avoids the overhead of thread creation and context
switching, making it more memory-efficient than traditional threading.
3. **Simplified Concurrency**: Provides a clean, synchronous-looking syntax for
asynchronous code, making concurrent programs easier to write and maintain.
4. **Scalability**: Enables handling thousands of concurrent connections with
minimal resource consumption, ideal for high-performance web servers and APIs.
--------------------------------------------------------------------------------
Workflow completed.
주요 개념
- 중앙 집중식 관리자: 그룹 채팅은 관리자를 사용하여 화자 선택 및 흐름을 조정합니다.
- AgentWorkflowBuilder.CreateGroupChatBuilderWith(): 관리자 팩터리 함수를 사용하여 워크플로를 만듭니다.
- RoundRobinGroupChatManager: 라운드 로빈 방식으로 스피커를 대체하는 기본 제공 관리자
- MaximumIterationCount: 종료 전 에이전트 턴의 최대 수를 제어합니다.
-
사용자 지정 관리자: 사용자 지정 논리 확장
RoundRobinGroupChatManager또는 구현 - 반복적 구체화: 에이전트는 서로의 기여도를 검토하고 개선합니다.
- 공유 컨텍스트: 모든 참가자가 전체 대화 기록을 볼 수 있습니다.
- 유연한 관리자 전략: 단순 선택기, 에이전트 기반 관리자 또는 사용자 지정 논리 중에서 선택
- GroupChatBuilder: 구성 가능한 화자 선택을 사용하여 워크플로 만들기
- set_select_speakers_func(): 스피커 선택에 대한 사용자 지정 Python 함수 정의
- set_manager(): 지능형 화자 조정을 위해 에이전트 기반 관리자 사용
- GroupChatStateSnapshot: 선택 결정에 대한 대화 상태를 제공합니다.
- 반복적인 공동 작업: 에이전트는 서로의 기여를 기반으로 합니다.
-
이벤트 스트리밍:
AgentRunUpdateEvent과WorkflowOutputEvent을 실시간으로 처리합니다. - list[ChatMessage] 출력: 모든 오케스트레이션은 채팅 메시지 목록을 반환합니다.
고급: 사용자 지정 스피커 선택
사용자 지정 그룹 채팅 관리자를 만들어 사용자 지정 관리자 논리를 구현할 수 있습니다.
public class ApprovalBasedManager : RoundRobinGroupChatManager
{
private readonly string _approverName;
public ApprovalBasedManager(IReadOnlyList<AIAgent> agents, string approverName)
: base(agents)
{
_approverName = approverName;
}
// Override to add custom termination logic
protected override ValueTask<bool> ShouldTerminateAsync(
IReadOnlyList<ChatMessage> history,
CancellationToken cancellationToken = default)
{
var last = history.LastOrDefault();
bool shouldTerminate = last?.AuthorName == _approverName &&
last.Text?.Contains("approve", StringComparison.OrdinalIgnoreCase) == true;
return ValueTask.FromResult(shouldTerminate);
}
}
// Use custom manager in workflow
var workflow = AgentWorkflowBuilder
.CreateGroupChatBuilderWith(agents =>
new ApprovalBasedManager(agents, "Reviewer")
{
MaximumIterationCount = 10
})
.AddParticipants(writer, reviewer)
.Build();
대화 상태에 따라 정교한 선택 논리를 구현할 수 있습니다.
def smart_selector(state: GroupChatStateSnapshot) -> str | None:
"""Select speakers based on conversation content and context."""
round_idx = state["round_index"]
conversation = state["conversation"]
history = state["history"]
# Maximum 10 rounds
if round_idx >= 10:
return None
# First round: always start with researcher
if round_idx == 0:
return "Researcher"
# Check last message content
last_message = conversation[-1] if conversation else None
last_text = getattr(last_message, "text", "").lower()
# If researcher asked a question, let writer respond
if "?" in last_text and history[-1].speaker == "Researcher":
return "Writer"
# If writer provided info, let researcher validate or extend
if history[-1].speaker == "Writer":
return "Researcher"
# Default alternation
return "Writer" if history[-1].speaker == "Researcher" else "Researcher"
workflow = (
GroupChatBuilder()
.set_select_speakers_func(smart_selector, display_name="SmartOrchestrator")
.participants([researcher, writer])
.build()
)
그룹 채팅을 사용하는 경우
그룹 채팅 오케스트레이션은 다음 작업에 적합합니다.
- 반복적 구체화: 여러 차례의 검토 및 개선
- 공동 작업 문제 해결: 상호 보완적인 전문 지식을 갖춘 에이전트가 함께 작동합니다.
- 콘텐츠 만들기: 문서 생성을 위한 작성자-검토자 워크플로
- 다중 관점 분석: 동일한 입력에 대한 다양한 뷰포인트 가져오기
- 품질 보증: 자동화된 검토 및 승인 프로세스
다음과 같은 경우 대안을 고려합니다.
- 엄격한 순차적 처리가 필요합니다(순차 오케스트레이션 사용)
- 에이전트는 완전히 독립적으로 작동해야 합니다(동시 오케스트레이션 사용)
- 직접 에이전트 간 핸드오프 필요(핸드오프 오케스트레이션 사용)
- 복잡한 동적 계획이 필요합니다(Magentic 오케스트레이션 사용)