Compartir a través de


Exploración del kernel semántico ChatCompletionAgent

Sugerencia

La documentación detallada de la API relacionada con esta discusión está disponible en:

Sugerencia

La documentación detallada de la API relacionada con esta discusión está disponible en:

Sugerencia

La documentación detallada de la API relacionada con esta discusión está disponible en:

Finalización del chat en Kernel Semántico

La finalización del chat es fundamentalmente un protocolo para una interacción basada en chat con un modelo de inteligencia artificial donde se mantiene el historial de chat y se presenta al modelo con cada solicitud. Los servicios de inteligencia artificial de kernel semántico ofrecen un marco unificado para integrar las funcionalidades de finalización de chat de varios modelos de IA.

Un ChatCompletionAgent puede aprovechar cualquiera de estos servicios de inteligencia artificial para generar respuestas, tanto si se dirige a un usuario como a otro agente.

Preparación del entorno de desarrollo

Para continuar con el desarrollo de un ChatCompletionAgent, configure el entorno de desarrollo con los paquetes adecuados.

Agregue el paquete Microsoft.SemanticKernel.Agents.Core al proyecto:

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

Instala el paquete semantic-kernel:

pip install semantic-kernel

Importante

En función del servicio de INTELIGENCIA ARTIFICIAL que use como parte de ChatCompletionAgent, es posible que tenga que instalar paquetes adicionales. Compruebe el adicional necesario en la página siguiente.

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

Creación de un ChatCompletionAgent

Un ChatCompletionAgent se basa fundamentalmente en un servicio de inteligencia artificial. Por lo tanto, la creación de un ChatCompletionAgent comienza con la creación de una instancia de Kernel que contiene uno o varios servicios de finalización de chat y, a continuación, crea una instancia del agente con una referencia a esa instancia de 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
    };

Hay dos maneras de crear un ChatCompletionAgent:

1. Al proporcionar el servicio de finalización del chat directamente

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. Al crear primero un kernel, agregar el servicio a él y luego proporcionar el kernel

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

El primer método es útil cuando ya tiene un servicio de finalización de chat listo. El segundo método es beneficioso cuando se necesita un kernel que administre varios servicios o funcionalidades adicionales.

// 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();

Selección del servicio AI

No es diferente del uso del Semantic Kernel con los servicios de IA de directamente, un ChatCompletionAgent admite la especificación de un selector de servicios. Un selector de servicios identifica qué servicio de IA debe ser el objetivo cuando el Kernel contiene más de uno.

Nota:

Si hay varios servicios de inteligencia artificial y no se proporciona ningún selector de servicios, se aplica la misma lógica predeterminada al agente que encontraría al usar servicios de inteligencia artificial fuera de . 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)
)

Característica actualmente no disponible en Java.

Conversando con ChatCompletionAgent

La conversación con el ChatCompletionAgent se basa en una instancia de ChatHistory, no es diferente de interactuar con un servicio de AI de completación de chat .

Simplemente puede invocar al agente con el mensaje de usuario.

// 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)...
}

También puede usar un AgentThread para tener una conversación con su agente. Aquí usamos un ChatHistoryAgentThread.

ChatHistoryAgentThread También puede tomar un objeto opcional ChatHistory como entrada, a través de su constructor, si reanuda una conversación anterior. (no se muestra)

// 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)...
}

Hay varias maneras de conversar con un ChatCompletionAgent.

Lo más sencillo es llamar a y esperar get_response:

# Define agent
agent = ChatCompletionAgent(...)

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

Si desea que el agente mantenga el historial de conversaciones entre invocaciones, puede pasarlo de ChatHistoryAgentThread la siguiente manera:


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

Llamar al método invoke devuelve un AsyncIterable de 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)

El ChatCompletionAgent también admite la transmisión en la que el método invoke_stream devuelve un AsyncIterable de 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();

También puede usar un AgentThread para tener una conversación con su agente. Aquí usamos un ChatHistoryAgentThread.

ChatHistoryAgentThread También puede tomar un ChatHistory objeto como entrada, a través de su constructor, si reanuda una conversación anterior. (no se muestra)

// Define agent
ChatCompletionAgent agent = ...;

AgentThread thread = new ChatHistoryAgentThread();

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

Gestión de mensajes intermedios con ChatCompletionAgent

El kernel ChatCompletionAgent semántico está diseñado para invocar un agente que cumpla las consultas o preguntas del usuario. Durante la invocación, el agente puede ejecutar herramientas para derivar la respuesta final. Para acceder a los mensajes intermedios generados durante este proceso, los autores de llamadas pueden proporcionar una función de devolución de llamada que controla las instancias de FunctionCallContent o FunctionResultContent.

La documentación del callback de ChatCompletionAgent estará disponible pronto.

La configuración de la devolución de llamada dentro de on_intermediate_message o agent.invoke(...) permite a la persona que llama recibir mensajes intermedios generados durante el proceso de formulación de la respuesta final del agente.

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

A continuación se muestra la salida de ejemplo del proceso de invocación del agente:

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!

Característica actualmente no disponible en Java.

Especificación declarativa

La documentación sobre el uso de especificaciones declarativas estará disponible próximamente.

Importante

Esta característica está en la fase experimental. Las características de esta fase están en desarrollo y están sujetas a cambios antes de avanzar a la fase de versión preliminar o candidata para lanzamiento.

El ChatCompletionAgent puede instanciarse directamente desde una especificación declarativa de YAML. Este enfoque le permite definir las propiedades principales, las instrucciones y las funciones disponibles (complementos) del agente de una manera estructurada y portátil. Con YAML, puede describir el nombre, la descripción, la solicitud de instrucciones, el conjunto de herramientas y los parámetros del modelo del agente en un solo documento, lo que hace que la configuración del agente sea fácilmente auditable y reproducible.

Nota:

Las herramientas o funciones especificadas en el YAML declarativo ya deben existir en la instancia de Kernel en el momento en que se crea el agente. El cargador de agentes no crea nuevas funciones a partir de la especificación; en su lugar, busca los complementos y funciones a los que se hace referencia por sus identificadores en el kernel. Si un complemento o una función necesarios no están presentes en el kernel, se generará un error durante la construcción del agente.

Ejemplo: Creación de un ChatCompletionAgent objeto a partir de una especificación de 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())

Esta característica no está disponible.

Procedimiento

Para obtener un ejemplo de principio a fin para una ChatCompletionAgent, consulte:

Pasos siguientes