Udostępnij przez


Orkiestracja czatów grupowych

Ważne

Funkcje orkiestracji agenta w ramach struktury agenta znajdują się w fazie eksperymentalnej. Są one aktywnie opracowywane i mogą ulec znacznej zmianie przed przejściem do etapu wersji zapoznawczej lub wersji kandydującej do wydania.

Modele orkiestracji czatów grupowych odwzorowują współpracę w rozmowie między agentami, opcjonalnie włączając uczestnika ludzkiego. Menedżer czatu grupowego koordynuje przepływ, określając, który agent powinien odpowiedzieć następnie i kiedy zażądać wkładu od człowieka. Ten wzorzec jest potężny do symulowania spotkań, debat lub sesji wspólnego rozwiązywania problemów.

Aby dowiedzieć się więcej na temat wzorca, na przykład, kiedy zastosować wzorzec lub kiedy go unikać w swoim obciążeniu, zobacz Orkiestracja czatów grupowych.

Typowe przypadki użycia

Agenci reprezentujący różne działy omawiają propozycję biznesową, a agent zarządzający moderuje konwersację i włącza człowieka w razie potrzeby.

diagram

Czego nauczysz się

  • Jak zdefiniować agentów z różnymi rolami na potrzeby czatu grupowego
  • Jak kontrolować przepływ konwersacji za pomocą menedżera czatu grupy
  • Jak zaangażować człowieka w rozmowę
  • Jak obserwować konwersację i zbierać końcowy wynik

Definiowanie agentów

Każdy agent w czacie grupy ma określoną rolę. W tym przykładzie określamy copywritera i recenzenta.

Wskazówka

Parametr ChatCompletionAgent jest używany w tym miejscu, ale można użyć dowolnego typu agenta.

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,
};

Opcjonalnie: Obserwowanie odpowiedzi agenta

Za pośrednictwem właściwości ResponseCallback można utworzyć wywołanie zwrotne w celu przechwycenia odpowiedzi agenta w miarę postępu sekwencji.

ChatHistory history = [];

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

Konfigurowanie orkiestracji czatu grupowego

Utwórz obiekt GroupChatOrchestration, przekazując do niego agentów, menedżera czatu grupowego (tutaj, RoundRobinGroupChatManager) i wywołanie zwrotne odpowiedzi. Menedżer kontroluje przepływ — w tym kontekście naprzemiennie zmienia kolejkę w cyklu okrężnym dla ustalonej liczby rund.

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

Uruchamianie środowiska uruchomieniowego

Środowisko uruchomieniowe jest wymagane do zarządzania wykonywaniem agentów programowych. W tym miejscu użyjemy InProcessRuntime i uruchomimy go przed wywołaniem orkiestracji.

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

Wywołaj orkiestrację

Wywołaj orchestrację, zaczynając od zadania początkowego (np. "Utwórz hasło dla nowego elektrycznego SUV-a..."). Agenci będą reagować na zmianę, udoskonalając wynik.

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

Zbieranie wyników

Poczekaj na ukończenie aranżacji i pobierz końcowe dane wyjściowe.

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

Opcjonalnie: Zatrzymaj środowisko uruchomieniowe

Po zakończeniu przetwarzania zatrzymaj środowisko uruchomieniowe, aby wyczyścić zasoby.

await runtime.RunUntilIdleAsync();

Przykładowe dane wyjściowe

# 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.”

Wskazówka

Pełny przykładowy kod jest dostępny tutaj

Definiowanie agentów

Każdy agent w czacie grupy ma określoną rolę. W tym przykładzie:

  • Autor: tworzy i edytuje zawartość na podstawie opinii.
  • Recenzent: przegląda zawartość i udostępnia opinię na temat poprawy.

Wskazówka

Element ChatCompletionAgent jest używany w tym miejscu w usłudze Azure OpenAI, ale można użyć dowolnego typu agenta lub usługi modelu.

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]

Obserwowanie odpowiedzi agenta

W miarę postępu konwersacji można zdefiniować wywołanie zwrotne, aby wydrukować komunikat każdego agenta.

from semantic_kernel.contents import ChatMessageContent

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

Konfigurowanie orkiestracji czatu grupowego

Utwórz obiekt GroupChatOrchestration, przekazując agentów, menedżera czatu grupy (w tym przypadku RoundRobinGroupChatManager) i wywołanie zwrotne odpowiedzi. Menedżer kontroluje przepływ — w tym kontekście naprzemiennie zmienia kolejkę w cyklu okrężnym dla ustalonej liczby rund.

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,
)

Uruchamianie środowiska uruchomieniowego

Uruchom środowisko uruchomieniowe, aby zarządzać wykonywaniem agenta.

from semantic_kernel.agents.runtime import InProcessRuntime

runtime = InProcessRuntime()
runtime.start()

Wywołaj orkiestrację

Wywołaj orchestrację, zaczynając od zadania początkowego (np. "Utwórz hasło dla nowego elektrycznego SUV-a..."). Agenci będą reagować na zmianę, udoskonalając wynik.

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,
)

Zbieranie wyników

Poczekaj na ukończenie aranżacji.

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

Opcjonalnie: Zatrzymaj środowisko uruchomieniowe

Po zakończeniu przetwarzania zatrzymaj środowisko uruchomieniowe, aby wyczyścić zasoby.

await runtime.stop_when_idle()

Przykładowe dane wyjściowe

**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!"

Wskazówka

Pełny przykładowy kod jest dostępny tutaj.

Uwaga / Notatka

Orkiestracja agentów nie jest jeszcze dostępna w Java SDK.

Dostosowywanie Menedżera czatu grupy

Przepływ konwersacji grupowej można dostosować, implementując własny element GroupChatManager. Pozwala to kontrolować sposób filtrowania wyników, sposobu wybierania następnego agenta oraz żądania wprowadzenia danych przez użytkownika lub zakończenia czatu.

Można na przykład utworzyć menedżera niestandardowego, dziedzicząc z GroupChatManager i przesłaniając jego metody abstrakcyjne.

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

Następnie możesz użyć niestandardowego menedżera w orkiestracji:

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

Wskazówka

Pełny przykład niestandardowego menedżera czatu grupy jest dostępny tutaj

Przepływ konwersacji grupowej można dostosować, implementując własny element GroupChatManager. Pozwala to kontrolować sposób filtrowania wyników, sposobu wybierania następnego agenta oraz żądania wprowadzenia danych przez użytkownika lub zakończenia czatu.

Można na przykład utworzyć menedżera niestandardowego, dziedzicząc z GroupChatManager i przesłaniając jego metody abstrakcyjne.

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

Następnie możesz użyć niestandardowego menedżera w orkiestracji:

from semantic_kernel.agents import GroupChatOrchestration

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

Wskazówka

Pełny przykład niestandardowego menedżera czatu grupy jest dostępny tutaj

Uwaga / Notatka

Orkiestracja agentów nie jest jeszcze dostępna w Java SDK.

Kolejność wywołań funkcji Menedżera czatu grupowego

Podczas organizowania czatu grupowego metody menedżera czatów grupowych są wywoływane w określonej kolejności dla każdej rundy konwersacji:

  1. ShouldRequestUserInput: sprawdza, czy dane wejściowe użytkownika (człowieka) są wymagane przed rozmową z następnym agentem. Jeśli warunek jest spełniony, orkiestracja zostanie wstrzymana, aby czekać na dane wejściowe od użytkownika. Dane wejściowe użytkownika są następnie dodawane do historii czatu menedżera i wysyłane do wszystkich agentów.
  2. ShouldTerminate: określa, czy czat grupy powinien zakończyć się (na przykład jeśli zostanie osiągnięta maksymalna liczba rund lub warunek niestandardowy zostanie spełniony). Jeśli to prawda, procedura orkiestracji przechodzi do filtrowania wyników.
  3. FilterResults: wywoływane tylko wtedy, gdy czat kończy się, aby podsumować lub przetworzyć końcowe wyniki konwersacji.
  4. SelectNextAgent: jeśli czat nie zostaje zakończony, wybiera następnego agenta do odpowiedzi w rozmowie.

Ta kolejność zapewnia, że wprowadzanie danych przez użytkownika i warunki zakończenia są sprawdzane, zanim rozmowa zostanie kontynuowana, a wyniki filtrowane dopiero na końcu. Logikę dla każdego kroku można dostosować, nadpisując odpowiednie metody w niestandardowym kierowniku rozmów grupowych.

Dalsze kroki