Compartilhar via


Orquestração de Chat em Grupo

Importante

Os recursos de Orquestração de Agente no Agent Framework estão em estágio experimental. Eles estão em desenvolvimento ativo e podem mudar significativamente antes de avançar para o estágio de prévia ou release candidate.

A orquestração de chat em grupo modela uma conversa colaborativa entre agentes, incluindo opcionalmente um participante humano. Um gerenciador de chat em grupo coordena o fluxo, determinando qual agente deve responder em seguida e quando solicitar a entrada humana. Esse padrão é poderoso para simular reuniões, debates ou sessões colaborativas de solução de problemas.

Para saber mais sobre o padrão, como quando usar o padrão ou quando evitar o padrão em sua carga de trabalho, consulte Orquestração de chat em grupo.

Casos de uso comuns

Agentes que representam diferentes departamentos discutem uma proposta de negócios, com um agente gerente moderando a conversa e envolvendo um humano quando necessário:

diagrama

O que você vai aprender

  • Como definir agentes com funções diferentes para um chat em grupo
  • Como usar um gerenciador de chat em grupo para controlar o fluxo de conversa
  • Como envolver um participante humano na conversa
  • Como observar a conversa e coletar o resultado final

Definir seus agentes

Cada agente no chat em grupo tem uma função específica. Neste exemplo, definimos um redator e um revisor.

Dica

O ChatCompletionAgent é usado aqui, mas você pode usar qualquer tipo de agente.

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.Orchestration;
using Microsoft.SemanticKernel.Agents.Orchestration.GroupChat;
using Microsoft.SemanticKernel.Agents.Runtime.InProcess;

// Create a kernel with an AI service
Kernel kernel = ...;

ChatCompletionAgent writer = new ChatCompletionAgent {
    Name = "CopyWriter",
    Description = "A copy writer",
    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.",
    Kernel = kernel,
};

ChatCompletionAgent editor = new ChatCompletionAgent {
    Name = "Reviewer",
    Description = "An editor.",
    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.",
    Kernel = kernel,
};

Opcional: Observar respostas do agente

Você pode criar um retorno de chamada para capturar respostas do agente conforme a sequência progride por meio da propriedade ResponseCallback.

ChatHistory history = [];

ValueTask responseCallback(ChatMessageContent response)
{
    history.Add(response);
    return ValueTask.CompletedTask;
}

Configurar a orquestração do bate-papo em grupo

Crie um objeto GroupChatOrchestration, passando os agentes, um gerenciador de chat em grupo (aqui, um RoundRobinGroupChatManager) e a função de retorno de chamada para resposta. O gerente controla o fluxo — aqui, ele alterna de maneira alternada para um número definido de rodadas.

GroupChatOrchestration orchestration = new GroupChatOrchestration(
    new RoundRobinGroupChatManager { MaximumInvocationCount = 5 },
    writer,
    editor)
{
    ResponseCallback = responseCallback,
};

Iniciar o Runtime

Um runtime é necessário para gerenciar a execução de agentes. Aqui, usamos InProcessRuntime e o iniciamos previamente à invocação da orquestração.

InProcessRuntime runtime = new InProcessRuntime();
await runtime.StartAsync();

Invocar a Orquestração

Invoque a orquestração com sua tarefa inicial (por exemplo, "Criar um slogan para um novo SUV elétrico..."). Os agentes se revezarão respondendo, refinando o resultado final.

var result = await orchestration.InvokeAsync(
    "Create a slogan for a new electric SUV that is affordable and fun to drive.",
    runtime);

Coletar Resultados

Aguarde até que a orquestração seja concluída e recupere o resultado final.

string output = await result.GetValueAsync(TimeSpan.FromSeconds(60));
Console.WriteLine($"\n# RESULT: {text}");
Console.WriteLine("\n\nORCHESTRATION HISTORY");
foreach (ChatMessageContent message in history)
{
    this.WriteAgentChatMessage(message);
}

Opcional: interromper o runtime

Após a conclusão do processamento, interrompa o runtime para limpar os recursos.

await runtime.RunUntilIdleAsync();

Saída de exemplo

# RESULT: “Affordable Adventure: Drive Electric, Drive Fun.”


ORCHESTRATION HISTORY

# Assistant - CopyWriter: “Charge Ahead: Affordable Thrills, Zero Emissions.”

# Assistant - Reviewer: The slogan is catchy but it could be refined to better ...

# Assistant - CopyWriter: “Electrify Your Drive: Fun Meets Affordability.”

# Assistant - Reviewer: The slogan captures the essence of electric driving and ...

# Assistant - CopyWriter: “Affordable Adventure: Drive Electric, Drive Fun.”

Dica

O código de exemplo completo está disponível aqui

Definir seus agentes

Cada agente no chat em grupo tem uma função específica. Neste exemplo:

  • Escritor: cria e edita conteúdo baseado em feedback.
  • Revisor: revisa o conteúdo e fornece comentários sobre melhorias.

Dica

O ChatCompletionAgent recurso é usado aqui com o Azure OpenAI, no entanto, você pode usar qualquer tipo de agente ou serviço de modelo.

from semantic_kernel.agents import Agent, ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion

def get_agents() -> list[Agent]:
    writer = ChatCompletionAgent(
        name="Writer",
        description="A content writer.",
        instructions=(
            "You are an excellent content writer. You create new content and edit contents based on the feedback."
        ),
        service=AzureChatCompletion(),
    )
    reviewer = ChatCompletionAgent(
        name="Reviewer",
        description="A content reviewer.",
        instructions=(
            "You are an excellent content reviewer. You review the content and provide feedback to the writer."
        ),
        service=AzureChatCompletion(),
    )
    return [writer, reviewer]

Observar respostas do agente

Você pode definir um retorno de chamada para imprimir a mensagem de cada agente à medida que a conversa progride.

from semantic_kernel.contents import ChatMessageContent

def agent_response_callback(message: ChatMessageContent) -> None:
    print(f"**{message.name}**\n{message.content}")

Configurar a orquestração do bate-papo em grupo

Crie um objeto GroupChatOrchestration, passando os agentes, um gerenciador de chat em grupo (neste caso, um RoundRobinGroupChatManager) e o callback de resposta. O gerente controla o fluxo — aqui, ele alterna de maneira alternada para um número definido de rodadas.

from semantic_kernel.agents import GroupChatOrchestration, RoundRobinGroupChatManager

agents = get_agents()
group_chat_orchestration = GroupChatOrchestration(
    members=agents,
    manager=RoundRobinGroupChatManager(max_rounds=5),  # Odd number so writer gets the last word
    agent_response_callback=agent_response_callback,
)

Iniciar o Runtime

Inicie o runtime para gerenciar a execução do agente.

from semantic_kernel.agents.runtime import InProcessRuntime

runtime = InProcessRuntime()
runtime.start()

Invocar a Orquestração

Invoque a orquestração com sua tarefa inicial (por exemplo, "Criar um slogan para um novo SUV elétrico..."). Os agentes se revezarão respondendo, refinando o resultado final.

orchestration_result = await group_chat_orchestration.invoke(
    task="Create a slogan for a new electric SUV that is affordable and fun to drive.",
    runtime=runtime,
)

Coletar Resultados

Aguarde a conclusão da orquestração.

value = await orchestration_result.get()
print(f"***** Final Result *****\n{value}")

Opcional: interromper o runtime

Após a conclusão do processamento, interrompa o runtime para limpar os recursos.

await runtime.stop_when_idle()

Saída de exemplo

**Writer**
"Drive Tomorrow: Affordable Adventure Starts Today!"
**Reviewer**
This slogan, "Drive Tomorrow: Affordable Adventure Starts Today!", effectively communicates the core attributes...
**Writer**
"Embrace the Future: Your Affordable Electric Adventure Awaits!"
**Reviewer**
This revised slogan, "Embrace the Future: Your Affordable Electric Adventure Awaits!", further enhances the message...
**Writer**
"Feel the Charge: Adventure Meets Affordability in Your New Electric SUV!"
***** Result *****
"Feel the Charge: Adventure Meets Affordability in Your New Electric SUV!"

Dica

O código de exemplo completo está disponível aqui.

Observação

A orquestração do agente ainda não está disponível no SDK do Java.

Personalizar o Gerenciador de Chat de Grupo

Você pode personalizar o fluxo de chat em grupo implementando seu próprio GroupChatManager. Isso permite que você controle como os resultados são filtrados, como o próximo agente é selecionado e quando solicitar a entrada do usuário ou encerrar o chat.

Por exemplo, você pode criar um gerenciador personalizado herdando GroupChatManager e substituindo seus métodos abstratos:

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." });
    }
}

Em seguida, você pode usar seu gerente personalizado na orquestração:

GroupChatOrchestration orchestration = new (new CustomGroupChatManager { MaximumInvocationCount = 5 }, ...);

Dica

Um exemplo completo de um gerenciador de chat de grupo personalizado está disponível aqui

Você pode personalizar o fluxo de chat em grupo implementando seu próprio GroupChatManager. Isso permite que você controle como os resultados são filtrados, como o próximo agente é selecionado e quando solicitar a entrada do usuário ou encerrar o chat.

Por exemplo, você pode criar um gerenciador personalizado herdando GroupChatManager e substituindo seus métodos abstratos:

from semantic_kernel.agents import GroupChatManager, BooleanResult, StringResult, MessageResult
from semantic_kernel.contents import ChatMessageContent, ChatHistory

class CustomGroupChatManager(GroupChatManager):
    async def filter_results(self, chat_history: ChatHistory) -> MessageResult:
        # Custom logic to filter or summarize chat results
        summary = "Summary of the discussion."
        return MessageResult(result=ChatMessageContent(role="assistant", content=summary), reason="Custom summary logic.")

    async def select_next_agent(self, chat_history: ChatHistory, participant_descriptions: dict[str, str]) -> StringResult:
        # Randomly select an agent from the participants
        import random
        next_agent = random.choice(list(participant_descriptions.keys()))
        return StringResult(result=next_agent, reason="Custom selection logic.")

    async def should_request_user_input(self, chat_history: ChatHistory) -> BooleanResult:
        # Custom logic to decide if user input is needed
        return BooleanResult(result=False, reason="No user input required.")

    async def should_terminate(self, chat_history: ChatHistory) -> BooleanResult:
        # Optionally call the base implementation to check for default termination logic
        base_result = await super().should_terminate(chat_history)
        if base_result.result:
            return base_result
        # Custom logic to determine if the chat should terminate
        should_end = len(chat_history.messages) > 10  # Example: end after 10 messages
        return BooleanResult(result=should_end, reason="Custom termination logic.")

Em seguida, você pode usar seu gerente personalizado na orquestração:

from semantic_kernel.agents import GroupChatOrchestration

group_chat_orchestration = GroupChatOrchestration(manager=CustomGroupChatManager(max_rounds=5), ...)

Dica

Um exemplo completo de um gerenciador de chat de grupo personalizado está disponível aqui

Observação

A orquestração do agente ainda não está disponível no SDK do Java.

Ordem das chamadas de função do Gerenciador de Chat em Grupo

Ao orquestrar um chat em grupo, os métodos do gerenciador de chat de grupo são chamados em uma ordem específica para cada rodada da conversa:

  1. ShouldRequestUserInput: verifica se a entrada do usuário (humana) é necessária antes que o próximo agente fale. Se for verdadeiro, a orquestração pausa para entrada do usuário. A entrada do usuário é então adicionada ao histórico de chat do gerente e enviada a todos os agentes.
  2. ShouldTerminate: determina se o chat em grupo deve terminar (por exemplo, se um número máximo de rodadas for atingido ou se uma condição personalizada for atendida). Se for verdadeiro, a orquestração prosseguirá para a filtragem de resultados.
  3. FilterResults: Chamado somente se o chat estiver terminando, para resumir ou processar os resultados finais da conversa.
  4. SelectNextAgent: se o chat não estiver sendo encerrado, selecione o próximo agente a responder na conversa.

Essa ordem garante que as condições de entrada do usuário e de término sejam verificadas antes de avançar na conversa, sendo que os resultados são filtrados apenas ao final da conversa. Você pode personalizar a lógica para cada etapa substituindo os métodos correspondentes em seu gerenciador de chat de grupo personalizado.

Próximas etapas