Selección de funcionalidad contextual con agentes

Importante

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

Información general

La selección de funciones contextuales es una funcionalidad avanzada en el marco del agente de kernel semántico que permite a los agentes seleccionar y anunciar dinámicamente solo las funciones más relevantes en función del contexto de conversación actual. En lugar de exponer todas las funciones disponibles al modelo de IA, esta característica usa Retrieval-Augmented Generación (RAG) para filtrar y presentar solo las funciones más pertinentes a la solicitud del usuario.

Este enfoque aborda el desafío de la selección de funciones al tratar con un gran número de funciones disponibles, donde los modelos de IA pueden tener dificultades para elegir la función adecuada, lo que provoca confusión y rendimiento poco óptimo.

Advertencia

Cuando se usa ContextualFunctionProvider, el ajuste UseImmutableKernel en el agente debe establecerse en true ya que la característica requiere clonar el kernel al activar el agente. Tenga en cuenta que establecer UseImmutableKernel a true significa que cualquier modificación de datos del kernel realizada durante la invocación del agente, por ejemplo mediante complementos, no se conservará una vez completada la invocación.

Funcionamiento de la selección de funciones contextuales

Cuando un agente se configura con la selección de funciones contextuales, aprovecha un almacén de vectores y un generador de inserción para que coincidan semánticamente con el contexto de conversación actual (incluidos los mensajes anteriores y la entrada del usuario) con las descripciones y los nombres de las funciones disponibles. Las funciones más relevantes, hasta el límite especificado, se anuncian al modelo de IA para la invocación.

Este mecanismo es especialmente útil para los agentes que tienen acceso a un amplio conjunto de complementos o herramientas, lo que garantiza que solo se tengan en cuenta las acciones contextualmente adecuadas en cada paso.

Ejemplo de uso

En el ejemplo siguiente se muestra cómo se puede configurar un agente para usar la selección de funciones contextuales. El agente está configurado para resumir las revisiones de los clientes, pero solo las funciones más relevantes se anuncian en el modelo de IA para cada invocación. El GetAvailableFunctions método incluye intencionadamente funciones relevantes e irrelevantes para resaltar las ventajas de la selección contextual.

// Create an embedding generator for function vectorization
var embeddingGenerator = new AzureOpenAIClient(new Uri("<endpoint>"), new ApiKeyCredential("<api-key>"))
    .GetEmbeddingClient("<deployment-name>")
    .AsIEmbeddingGenerator();

// Create kernel and register AzureOpenAI chat completion service
var kernel = Kernel.CreateBuilder()
    .AddAzureOpenAIChatCompletion("<deployment-name>", "<endpoint>", "<api-key>");
    .Build();

// Create a chat completion agent
ChatCompletionAgent agent = new()
{
    Name = "ReviewGuru",
    Instructions = "You are a friendly assistant that summarizes key points and sentiments from customer reviews. For each response, list available functions.",
    Kernel = kernel,
    Arguments = new(new PromptExecutionSettings { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(options: new FunctionChoiceBehaviorOptions { RetainArgumentTypes = true }) }),
    // This setting must be set to true when using the ContextualFunctionProvider
    UseImmutableKernel = true
};

// Create the agent thread and register the contextual function provider
ChatHistoryAgentThread agentThread = new();

agentThread.AIContextProviders.Add(
    new ContextualFunctionProvider(
        vectorStore: new InMemoryVectorStore(new InMemoryVectorStoreOptions() { EmbeddingGenerator = embeddingGenerator }),
        vectorDimensions: 1536,
        functions: AvailableFunctions(),
        maxNumberOfFunctions: 3, // Only the top 3 relevant functions are advertised
        loggerFactory: LoggerFactory
    )
);


// Invoke the agent
ChatMessageContent message = await agent.InvokeAsync("Get and summarize customer review.", agentThread).FirstAsync();
Console.WriteLine(message.Content);

// Output
/*
    Customer Reviews:
    -----------------
    1. John D. - ★★★★★
       Comment: Great product and fast shipping!
       Date: 2023-10-01

    Summary:
    --------
    The reviews indicate high customer satisfaction,
    highlighting product quality and shipping speed.

    Available functions:
    --------------------
    - Tools-GetCustomerReviews
    - Tools-Summarize
    - Tools-CollectSentiments
*/

IReadOnlyList<AIFunction> GetAvailableFunctions()
{
    // Only a few functions are directly related to the prompt; the majority are unrelated to demonstrate the benefits of contextual filtering.
    return new List<AIFunction>
    {
        // Relevant functions
        AIFunctionFactory.Create(() => "[ { 'reviewer': 'John D.', 'date': '2023-10-01', 'rating': 5, 'comment': 'Great product and fast shipping!' } ]", "GetCustomerReviews"),
        AIFunctionFactory.Create((string text) => "Summary generated based on input data: key points include customer satisfaction.", "Summarize"),
        AIFunctionFactory.Create((string text) => "The collected sentiment is mostly positive.", "CollectSentiments"),

        // Irrelevant functions
        AIFunctionFactory.Create(() => "Current weather is sunny.", "GetWeather"),
        AIFunctionFactory.Create(() => "Email sent.", "SendEmail"),
        AIFunctionFactory.Create(() => "The current stock price is $123.45.", "GetStockPrice"),
        AIFunctionFactory.Create(() => "The time is 12:00 PM.", "GetCurrentTime")
    };
}

Almacén de Vectores

El proveedor está diseñado principalmente para trabajar con almacenes de vectores en memoria, que ofrecen simplicidad. Sin embargo, si se usan otros tipos de almacenes de vectores, es importante tener en cuenta que la responsabilidad de controlar la sincronización de datos y la coherencia se encuentran en la aplicación de hospedaje.

La sincronización es necesaria cada vez que cambia la lista de funciones o cuando se modifica el origen de las inscrusciones de función. Por ejemplo, si un agente inicialmente tiene tres funciones (f1, f2, f3) que se vectorizan y almacenan en un almacén de vectores de nube y, posteriormente, f3 se quita de la lista de funciones del agente, el almacén de vectores debe actualizarse para reflejar solo las funciones actuales que tiene el agente (f1 y f2). Si no se actualiza el almacén de vectores, las funciones irrelevantes se devuelven como resultados. De manera similar, si los datos utilizados para la vectorización, como los nombres de funciones, descripciones, etc., cambian, el almacén de vectores debería ser purgado y repoblado con nuevos embeddings basados en la información actualizada.

La administración de la sincronización de datos en almacenes de vectores distribuidos o externos puede ser compleja y propensa a errores, especialmente en aplicaciones distribuidas en las que diferentes servicios o instancias pueden funcionar de forma independiente y requieren acceso coherente a los mismos datos. En cambio, el uso de un almacén en memoria simplifica este proceso: cuando cambia la lista de funciones o el origen de vectorización, el almacén en memoria se puede volver a crear fácilmente con el nuevo conjunto de funciones y sus incrustaciones, lo que garantiza la coherencia con un esfuerzo mínimo.

Especificación de funciones

El proveedor de funciones contextuales debe proporcionarse con una lista de funciones desde las que puede seleccionar las más relevantes en función del contexto actual. Esto se logra proporcionando una lista de funciones al functions parámetro del ContextualFunctionProvider constructor.

Además de las funciones, también debe especificar el número máximo de funciones pertinentes para devolver mediante el maxNumberOfFunctions parámetro . Este parámetro determina cuántas funciones tendrá en cuenta el proveedor al seleccionar las más relevantes para el contexto actual. El número especificado no está diseñado para ser preciso; en su lugar, actúa como un límite superior que depende del escenario específico.

Establecer este valor demasiado bajo puede impedir que el agente acceda a todas las funciones necesarias para un escenario, lo que podría provocar un error en el escenario. Por el contrario, establecerlo demasiado alto puede sobrecargar al agente con demasiadas funciones, lo que puede dar lugar a alucinaciones, un consumo excesivo de tokens de entrada y un rendimiento poco óptimo.

// Create the provider with a list of functions and a maximum number of functions to return
ContextualFunctionProvider provider = new (
    vectorStore: new InMemoryVectorStore(new InMemoryVectorStoreOptions { EmbeddingGenerator = embeddingGenerator }),
    vectorDimensions: 1536,
    functions: [AIFunctionFactory.Create((string text) => $"Echo: {text}", "Echo"), <other functions>]
    maxNumberOfFunctions: 3 // Only the top 3 relevant functions are advertised
);

Opciones del proveedor de funciones contextuales

El proveedor se puede configurar mediante la ContextualFunctionProviderOptions clase , que le permite personalizar varios aspectos de cómo opera el proveedor:

// Create options for the contextual function provider
ContextualFunctionProviderOptions options = new ()
{
    ...
};

// Create the provider with options
ContextualFunctionProvider provider = new (
    ...
    options: options // Pass the options
);

Tamaño del contexto

El tamaño del contexto determina cuántos mensajes recientes de las invocaciones anteriores del agente se incluyen al formar el contexto para una nueva invocación. El proveedor recopila todos los mensajes de las invocaciones anteriores, hasta el número especificado y los antepone a los nuevos mensajes para formar el contexto.

El uso de mensajes recientes junto con nuevos mensajes es especialmente útil para las tareas que requieren información de los pasos anteriores en una conversación. Por ejemplo, si un agente aprovisiona un recurso en una invocación e lo implementa en el siguiente, el paso de implementación puede acceder a los detalles del paso de aprovisionamiento para obtener información de recursos aprovisionada para la implementación.

El valor predeterminado del número de mensajes recientes en contexto es 2, pero esto se puede configurar según sea necesario especificando la NumberOfRecentMessagesInContext propiedad en ContextualFunctionProviderOptions:

ContextualFunctionProviderOptions options = new ()
{
    NumberOfRecentMessagesInContext = 1 // Only the last message will be included in the context
};

Valor de origen de inserción de contexto

Para realizar la selección de funciones contextuales, el proveedor debe vectorizar el contexto actual para que se pueda comparar con las funciones disponibles en el almacén de vectores. De forma predeterminada, el proveedor crea este contexto mediante la incrustación por concatenación de todos los mensajes recientes y nuevos no vacíos en una sola cadena, que luego se vectoriza y se utiliza para buscar funciones pertinentes.

En algunos escenarios, es posible que desee personalizar este comportamiento para:

  • Céntrese en tipos de mensajes específicos (por ejemplo, solo mensajes de usuario)
  • Exclusión de cierta información del contexto
  • Preprocesar o resumir el contexto antes de la vectorización (por ejemplo, aplicar reescritura del mensaje)

Para ello, puede asignar un delegado personalizado a ContextEmbeddingValueProvider. Este delegado recibe los mensajes recientes y nuevos y devuelve un valor de cadena que se usará como origen para la inserción de contexto:

ContextualFunctionProviderOptions options = new()
{
    ContextEmbeddingValueProvider = async (recentMessages, newMessages, cancellationToken) =>
    {
        // Example: Only include user messages in the embedding
        var allUserMessages = recentMessages.Concat(newMessages)
            .Where(m => m.Role == "user")
            .Select(m => m.Content)
            .Where(content => !string.IsNullOrWhiteSpace(content));
        return string.Join("\n", allUserMessages);
    }
};

La personalización de la inserción de contexto puede mejorar la relevancia de la selección de funciones, especialmente en escenarios de agentes complejos o altamente especializados.

Valor de origen de inserción de funciones

El proveedor debe vectorizar cada función disponible para compararla con el contexto y seleccionar las más relevantes. De forma predeterminada, el proveedor crea una incrustación de funciones al concatenar el nombre y la descripción de la función en un único texto, que luego se vectoriza y almacena en el repositorio vectorial.

Puede personalizar este comportamiento mediante la EmbeddingValueProvider propiedad de ContextualFunctionProviderOptions. Esta propiedad permite especificar una devolución de llamada que recibe la función y un token de cancelación, y devuelve una cadena que se usará como origen para la inserción de la función. Esto es útil si desea:

  • Adición de metadatos de función adicionales al origen de inserción
  • Preprocesar, filtrar o volver a formatear la información de la función antes de la vectorización
ContextualFunctionProviderOptions options = new()
{
    EmbeddingValueProvider = async (function, cancellationToken) =>
    {
        // Example: Use only the function name for embedding
        return function.Name;
    }
};

La personalización del valor de origen de inserción de funciones puede mejorar la precisión de la selección de funciones, especialmente cuando las funciones tienen metadatos enriquecidos y relevantes para el contexto o cuando desea centrar la búsqueda en aspectos específicos de cada función.

Pasos siguientes

Exploración de los ejemplos de selección de funciones contextuales

Próximamente

Más información próximamente.

Próximamente

Más información próximamente.