Udostępnij przez


Eksplorowanie jądra semantycznego ChatCompletionAgent

Wskazówka

Szczegółowa dokumentacja interfejsu API związana z tą dyskusją jest dostępna pod adresem:

Wskazówka

Szczegółowa dokumentacja interfejsu API związana z tą dyskusją jest dostępna pod adresem:

Wskazówka

Szczegółowa dokumentacja interfejsu API związana z tą dyskusją jest dostępna pod adresem:

Kompletowanie czatu w jądrze semantycznym

Ukończenie czatu jest zasadniczo protokołem interakcji opartej na czacie z modelem sztucznej inteligencji, w którym historia czatów jest utrzymywana i przedstawiana modelowi z każdym żądaniem. Usługi sztucznej inteligencji Semantycznego Jądra oferują ujednoliconą platformę do integracji funkcji automatycznego uzupełniania czatów różnych modeli sztucznej inteligencji.

Element ChatCompletionAgent może wykorzystać dowolną z tych usług sztucznej inteligencji do generowania odpowiedzi, niezależnie od tego, czy jest kierowana do użytkownika, czy innego agenta.

Przygotowywanie środowiska projektowego

Aby kontynuować tworzenie ChatCompletionAgent, skonfiguruj środowisko programistyczne za pomocą odpowiednich pakietów.

Dodaj pakiet Microsoft.SemanticKernel.Agents.Core do projektu:

dotnet add package Microsoft.SemanticKernel.Agents.Core --prerelease

semantic-kernel Zainstaluj pakiet:

pip install semantic-kernel

Ważne

W zależności od usługi sztucznej inteligencji, której używasz w ramach ChatCompletionAgent, może być konieczne zainstalowanie dodatkowych pakietów. Sprawdź, czy wymagane dodatkowe informacje znajdują się na poniższej stronie

<dependency>
    <groupId>com.microsoft.semantic-kernel</groupId>
    <artifactId>semantickernel-agents-core</artifactId>
    <version>[LATEST]</version>
</dependency>

Tworzenie ChatCompletionAgent

ChatCompletionAgent jest zasadniczo oparty na usługach sztucznej inteligencji. W związku z tym utworzenie ChatCompletionAgent rozpoczyna się od stworzenia instancji Kernel, która zawiera co najmniej jedną usługę uzupełniania czatu, a następnie instancjowanie agenta z odwołaniem do tej instancji Kernel.

// Initialize a Kernel with a chat-completion service
IKernelBuilder builder = Kernel.CreateBuilder();

builder.AddAzureOpenAIChatCompletion(/*<...configuration parameters>*/);

Kernel kernel = builder.Build();

// Create the agent
ChatCompletionAgent agent =
    new()
    {
        Name = "SummarizationAgent",
        Instructions = "Summarize user input",
        Kernel = kernel
    };

Istnieją dwa sposoby tworzenia ChatCompletionAgent:

1. Poprzez bezpośrednie udostępnienie usługi uzupełniania czatu

from semantic_kernel.agents import ChatCompletionAgent

# Create the agent by directly providing the chat completion service
agent = ChatCompletionAgent(
    service=AzureChatCompletion(),  # your chat completion service instance
    name="<agent name>",
    instructions="<agent instructions>",
)

2. Najpierw tworząc jądro, dodając do niej usługę, a następnie podając jądro

# Define the kernel
kernel = Kernel()

# Add the chat completion service to the kernel
kernel.add_service(AzureChatCompletion())

# Create the agent using the kernel
agent = ChatCompletionAgent(
  kernel=kernel, 
  name="<agent name>", 
  instructions="<agent instructions>",
)

Pierwsza metoda jest przydatna, gdy masz już gotową usługę uzupełniania czatu. Druga metoda jest przydatna, gdy potrzebujesz jądra, które zarządza wieloma usługami lub dodatkowymi funkcjami.

// Initialize a Kernel with a chat-completion service
var chatCompletion = OpenAIChatCompletion.builder()
        .withOpenAIAsyncClient(client) // OpenAIAsyncClient with configuration parameters
        .withModelId(MODEL_ID)
        .build();

var kernel = Kernel.builder()
        .withAIService(ChatCompletionService.class, chatCompletion)
        .build();

// Create the agent
var agent = ChatCompletionAgent.builder()
        .withKernel(kernel)
        .build();

Wybór usługi sztucznej inteligencji

Nie różni się od bezpośredniego używania usług jądra semantycznego AI, ChatCompletionAgent obsługuje specyfikację selektora usług. Selektor usług identyfikuje, którą usługi sztucznej inteligencji należy wybrać jako cel, gdy Kernel zawiera więcej niż jedną.

Uwaga / Notatka

Jeśli istnieje wiele usług sztucznej inteligencji i nie podano selektora usług, stosowana jest ta sama logika domyślna dla agenta, jaką stosuje się podczas korzystania z usług sztucznej inteligencji poza Agent Framework

IKernelBuilder builder = Kernel.CreateBuilder();

// Initialize multiple chat-completion services.
builder.AddAzureOpenAIChatCompletion(/*<...service configuration>*/, serviceId: "service-1");
builder.AddAzureOpenAIChatCompletion(/*<...service configuration>*/, serviceId: "service-2");

Kernel kernel = builder.Build();

ChatCompletionAgent agent =
    new()
    {
        Name = "<agent name>",
        Instructions = "<agent instructions>",
        Kernel = kernel,
        Arguments = // Specify the service-identifier via the KernelArguments
          new KernelArguments(
            new OpenAIPromptExecutionSettings() 
            { 
              ServiceId = "service-2" // The target service-identifier.
            })
    };
from semantic_kernel.connectors.ai.open_ai import (
    AzureChatCompletion,
    AzureChatPromptExecutionSettings,
)

# Define the Kernel
kernel = Kernel()

# Add the AzureChatCompletion AI Service to the Kernel
kernel.add_service(AzureChatCompletion(service_id="service1"))
kernel.add_service(AzureChatCompletion(service_id="service2"))

settings = AzureChatPromptExecutionSettings(service_id="service2")

# Create the agent
agent = ChatCompletionAgent(
  kernel=kernel, 
  name="<agent name>", 
  instructions="<agent instructions>",
  arguments=KernelArguments(settings=settings)
)

Funkcja jest obecnie niedostępna w języku Java.

Rozmowa z ChatCompletionAgent

Rozmowa z ChatCompletionAgent opiera się na instancji ChatHistory i nie różni się od interakcji z usługą uzupełniania czatu AI.

Agenta można po prostu wywołać za pomocą komunikatu użytkownika.

// Define agent
ChatCompletionAgent agent = ...;

// Generate the agent response(s)
await foreach (ChatMessageContent response in agent.InvokeAsync(new ChatMessageContent(AuthorRole.User, "<user input>")))
{
  // Process agent response(s)...
}

Możesz również użyć elementu AgentThread , aby porozmawiać z agentem. W tym miejscu używamy elementu ChatHistoryAgentThread.

Obiekt ChatHistoryAgentThread może również przyjmować opcjonalny ChatHistory obiekt jako dane wejściowe za pośrednictwem jego konstruktora, jeśli wznawiasz poprzednią konwersację. (nie pokazano)

// Define agent
ChatCompletionAgent agent = ...;

AgentThread thread = new ChatHistoryAgentThread();

// Generate the agent response(s)
await foreach (ChatMessageContent response in agent.InvokeAsync(new ChatMessageContent(AuthorRole.User, "<user input>"), thread))
{
  // Process agent response(s)...
}

Istnieje wiele sposobów, by porozmawiać z ChatCompletionAgent.

Najłatwiej jest zadzwonić i poczekać na get_response:

# Define agent
agent = ChatCompletionAgent(...)

# Generate the agent response
response = await agent.get_response(messages="user input")
# response is an `AgentResponseItem[ChatMessageContent]` object

Jeśli chcesz, aby agent zachowywał historię konwersacji między wywołaniami, możesz przekazać mu ChatHistoryAgentThread w następujący sposób:


# Define agent
agent = ChatCompletionAgent(...)

# Generate the agent response(s)
response = await agent.get_response(messages="user input")

# Generate another response, continuing the conversation thread from the first response.
response2 = await agent.get_response(messages="user input", thread=response.thread)
# process agent response(s)

Wywołanie metody invoke zwraca AsyncIterable wartości typu AgentResponseItem[ChatMessageContent].

# Define agent
agent = ChatCompletionAgent(...)

# Define the thread
thread = ChatHistoryAgentThread()

# Generate the agent response(s)
async for response in agent.invoke(messages="user input", thread=thread):
  # process agent response(s)

ChatCompletionAgent obsługuje również przesyłanie strumieniowe, w którym metoda invoke_stream zwraca AsyncIterable, StreamingChatMessageContent:

# Define agent
agent = ChatCompletionAgent(...)

# Define the thread
thread = ChatHistoryAgentThread()

# Generate the agent response(s)
async for response in agent.invoke_stream(messages="user input", thread=thread):
  # process agent response(s)
ChatCompletionAgent agent = ...;

// Generate the agent response(s)
agent.invokeAsync(new ChatMessageContent<>(AuthorRole.USER, "<user input>")).block();

Możesz również użyć elementu AgentThread , aby porozmawiać z agentem. W tym miejscu używamy elementu ChatHistoryAgentThread.

Obiekt ChatHistoryAgentThread może również przyjmować obiekt ChatHistory jako argument wejściowy przez jego konstruktor, jeśli wznawiasz poprzednią konwersację. (nie pokazano)

// Define agent
ChatCompletionAgent agent = ...;

AgentThread thread = new ChatHistoryAgentThread();

// Generate the agent response(s)
agent.invokeAsync(new ChatMessageContent<>(AuthorRole.USER, "<user input>"), thread).block();

Obsługa komunikatów pośrednich za pomocą ChatCompletionAgent

Jądro ChatCompletionAgent semantyczne jest przeznaczone do wywoływania agenta, który spełnia zapytania użytkownika lub pytania. Podczas wywołania agent może wykonywać narzędzia, aby uzyskać ostateczną odpowiedź. Aby uzyskać dostęp do komunikatów pośrednich generowanych podczas tego procesu, dzwoniący mogą dostarczyć funkcję zwrotną, która obsługuje wystąpienia FunctionCallContent lub FunctionResultContent.

Dokumentacja wywołania zwrotnego dla elementu ChatCompletionAgent zostanie wkrótce udostępniona.

Skonfigurowanie wywołania zwrotnego on_intermediate_message w agent.invoke(...) lub agent.invoke_stream(...) umożliwia inicjującemu odbieranie komunikatów pośrednich generowanych podczas procesu formułowania ostatecznej odpowiedzi agenta.

import asyncio
from typing import Annotated

from semantic_kernel.agents.chat_completion.chat_completion_agent import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.open_ai.services.azure_chat_completion import AzureChatCompletion
from semantic_kernel.contents import FunctionCallContent, FunctionResultContent
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.functions import kernel_function


# Define a sample plugin for the sample
class MenuPlugin:
    """A sample Menu Plugin used for the concept sample."""

    @kernel_function(description="Provides a list of specials from the menu.")
    def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
        return """
        Special Soup: Clam Chowder
        Special Salad: Cobb Salad
        Special Drink: Chai Tea
        """

    @kernel_function(description="Provides the price of the requested menu item.")
    def get_item_price(
        self, menu_item: Annotated[str, "The name of the menu item."]
    ) -> Annotated[str, "Returns the price of the menu item."]:
        return "$9.99"


# This callback function will be called for each intermediate message
# Which will allow one to handle FunctionCallContent and FunctionResultContent
# If the callback is not provided, the agent will return the final response
# with no intermediate tool call steps.
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
    for item in message.items or []:
        if isinstance(item, FunctionCallContent):
            print(f"Function Call:> {item.name} with arguments: {item.arguments}")
        elif isinstance(item, FunctionResultContent):
            print(f"Function Result:> {item.result} for function: {item.name}")
        else:
            print(f"{message.role}: {message.content}")


async def main() -> None:
    agent = ChatCompletionAgent(
        service=AzureChatCompletion(),
        name="Assistant",
        instructions="Answer questions about the menu.",
        plugins=[MenuPlugin()],
    )

    # Create a thread for the agent
    # If no thread is provided, a new thread will be
    # created and returned with the initial response
    thread: ChatHistoryAgentThread = None

    user_inputs = [
        "Hello",
        "What is the special soup?",
        "How much does that cost?",
        "Thank you",
    ]

    for user_input in user_inputs:
        print(f"# User: '{user_input}'")
        async for response in agent.invoke(
            messages=user_input,
            thread=thread,
            on_intermediate_message=handle_intermediate_steps,
        ):
            print(f"# {response.role}: {response}")
            thread = response.thread


if __name__ == "__main__":
    asyncio.run(main())

Poniżej przedstawiono przykładowe dane wyjściowe z procesu wywołania agenta:

User: 'Hello'
AuthorRole.ASSISTANT: Hi there! How can I assist you today?
User: 'What is the special soup?'
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:> 
        Special Soup: Clam Chowder
        Special Salad: Cobb Salad
        Special Drink: Chai Tea
        for function: MenuPlugin-get_specials
AuthorRole.ASSISTANT: The special soup today is Clam Chowder. Would you like to know anything else from the menu?
User: 'How much does that cost?'
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Clam Chowder"}
Function Result:> $9.99 for function: MenuPlugin-get_item_price
AuthorRole.ASSISTANT: The Clam Chowder costs $9.99. Would you like to know more about the menu or anything else?
User: 'Thank you'
AuthorRole.ASSISTANT: You're welcome! If you have any more questions, feel free to ask. Enjoy your day!

Funkcja jest obecnie niedostępna w języku Java.

Specyfikacja deklaratywna

Dokumentacja dotycząca korzystania ze specyfikacji deklaratywnych jest dostępna wkrótce.

Ważne

Ta funkcja znajduje się na etapie eksperymentalnym. Funkcje na tym etapie są opracowywane i mogą ulec zmianie przed przejściem do etapu wersji zapoznawczej lub etapu kandydata do wydania.

Instancję ChatCompletionAgent można utworzyć bezpośrednio na podstawie specyfikacji deklaratywnej YAML. Takie podejście umożliwia zdefiniowanie podstawowych właściwości, instrukcji i dostępnych funkcji (wtyczek) agenta w sposób ustrukturyzowany i przenośny. Używając języka YAML, możesz opisać nazwę, opis agenta, monit z instrukcjami, zestaw narzędzi i parametry modelu w jednym dokumencie, dzięki czemu konfiguracja agenta jest łatwo inspekcji i powtarzalna.

Uwaga / Notatka

Wszystkie narzędzia lub funkcje określone w deklaratywnym języku YAML muszą już istnieć w wystąpieniu jądra w momencie utworzenia agenta. Moduł ładujący agenta nie tworzy nowych funkcji na podstawie specyfikacji; Zamiast tego wyszukuje przywołyne wtyczki i funkcje według ich identyfikatorów w jądrze. Jeśli wymagana wtyczka lub funkcja nie istnieje w jądrze, podczas budowy agenta zostanie zgłoszony błąd.

Przykład: tworzenie elementu ChatCompletionAgent na podstawie specyfikacji YAML

import asyncio
from typing import Annotated

from semantic_kernel import Kernel
from semantic_kernel.agents import AgentRegistry, ChatHistoryAgentThread
from semantic_kernel.agents.chat_completion.chat_completion_agent import ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.functions import kernel_function

# Define a plugin with kernel functions
class MenuPlugin:
    @kernel_function(description="Provides a list of specials from the menu.")
    def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
        return """
        Special Soup: Clam Chowder
        Special Salad: Cobb Salad
        Special Drink: Chai Tea
        """

    @kernel_function(description="Provides the price of the requested menu item.")
    def get_item_price(
        self, menu_item: Annotated[str, "The name of the menu item."]
    ) -> Annotated[str, "Returns the price of the menu item."]:
        return "$9.99"

# YAML spec for the agent
AGENT_YAML = """
type: chat_completion_agent
name: Assistant
description: A helpful assistant.
instructions: Answer the user's questions using the menu functions.
tools:
  - id: MenuPlugin.get_specials
    type: function
  - id: MenuPlugin.get_item_price
    type: function
model:
  options:
    temperature: 0.7
"""

USER_INPUTS = [
    "Hello",
    "What is the special soup?",
    "What does that cost?",
    "Thank you",
]

async def main():
    kernel = Kernel()
    kernel.add_plugin(MenuPlugin(), plugin_name="MenuPlugin")

    agent: ChatCompletionAgent = await AgentRegistry.create_from_yaml(
        AGENT_YAML, kernel=kernel, service=OpenAIChatCompletion()
    )

    thread: ChatHistoryAgentThread | None = None

    for user_input in USER_INPUTS:
        print(f"# User: {user_input}")
        response = await agent.get_response(user_input, thread=thread)
        print(f"# {response.name}: {response}")
        thread = response.thread

    await thread.delete() if thread else None

if __name__ == "__main__":
    asyncio.run(main())

Ta funkcja jest niedostępna.

Instrukcja

Aby zapoznać się z przykładem od początku do końca dla ChatCompletionAgent, zobacz:

Dalsze kroki