Wybór funkcji kontekstualnej przy pomocy agentów

Ważne

Ta funkcja znajduje się na etapie eksperymentalnym. Funkcje na tym etapie są aktywnie rozwijane i mogą ulec znacznej zmianie przed przejściem do etapu wersji zapoznawczej lub wersji kandydującej do wydania.

Przegląd

Wybór funkcji kontekstowej to zaawansowana funkcja w strukturze agenta jądra semantycznego, która umożliwia agentom dynamiczne wybieranie i anonsowania tylko najbardziej odpowiednich funkcji na podstawie bieżącego kontekstu konwersacji. Zamiast uwidaczniać wszystkie dostępne funkcje w modelu sztucznej inteligencji, ta funkcja używa funkcji Retrieval-Augmented Generation (RAG) do filtrowania i prezentowania tylko tych funkcji, które są najbardziej istotne dla żądania użytkownika.

Takie podejście rozwiązuje wyzwanie związane z wyborem funkcji podczas pracy z dużą liczbą dostępnych funkcji, gdzie modele sztucznej inteligencji mogą w przeciwnym razie mieć trudności z wybraniem odpowiedniej funkcji, co prowadzi do nieporozumień i nieoptymalnej wydajności.

Ostrzeżenie

W przypadku korzystania z ContextualFunctionProvider, ustawienie agenta musi być ustawione na UseImmutableKernel, ponieważ funkcja wymaga sklonowania jądra podczas wywoływania agenta. Należy pamiętać, że ustawienie UseImmutableKernel na true oznacza, że wszelkie modyfikacje danych jądra wykonywane podczas wywołania agenta przez np. wtyczki zostaną utracone po zakończeniu wywołania.

Jak działa wybór funkcji kontekstowej

Gdy agent jest skonfigurowany z wyborem funkcji kontekstowej, wykorzystuje magazyn wektorów i generator osadzania, aby semantycznie dopasować bieżący kontekst konwersacji (w tym poprzednie komunikaty i dane wejściowe użytkownika) z opisami i nazwami dostępnych funkcji. Najbardziej odpowiednie funkcje, do określonego limitu, są następnie anonsowane do modelu sztucznej inteligencji na potrzeby wywołania.

Ten mechanizm jest szczególnie przydatny w przypadku agentów, którzy mają dostęp do szerokiego zestawu wtyczek lub narzędzi, zapewniając, że w każdym kroku są uwzględniane tylko odpowiednie akcje kontekstowe.

Przykład użycia

W poniższym przykładzie pokazano, jak można skonfigurować agenta do korzystania z wyboru funkcji kontekstowej. Agent jest skonfigurowany do podsumowywania recenzji klientów, ale tylko najbardziej odpowiednie funkcje są przekazywane modelowi sztucznej inteligencji dla każdego wywołania. Metoda GetAvailableFunctions celowo zawiera zarówno istotne, jak i nieistotne funkcje, aby podkreślić zalety wyboru kontekstowego.

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

Magazyn wektorów

Dostawca jest zaprojektowany głównie do współpracy z pamięciowymi magazynami wektorów, które oferują prostotę. Jeśli jednak są używane inne typy magazynów wektorów, należy pamiętać, że odpowiedzialność za obsługę synchronizacji danych i spójności spada na aplikację hostingu.

Synchronizacja jest konieczna za każdym razem, gdy lista funkcji ulegnie zmianie lub gdy źródło osadzania funkcji zostanie zmodyfikowane. Jeśli na przykład agent początkowo ma trzy funkcje (f1, f2, f3), które są wektoryzowane i przechowywane w magazynie wektorów w chmurze, a później f3 jest usuwany z listy funkcji agenta, magazyn wektorów musi zostać zaktualizowany tak, aby odzwierciedlał tylko bieżące funkcje agenta (f1 i f2). Niezaktualizowanie magazynu wektorów może skutkować zwróceniem nieistotnych funkcji jako wyników. Podobnie, jeśli dane używane do wektoryzacji, takie jak nazwy funkcji, opisy itp., ulegną zmianie, magazyn wektorów powinien zostać usunięty i ponownie wypełniony nowymi osadzeniami na podstawie zaktualizowanych informacji.

Zarządzanie synchronizacją danych w zewnętrznych lub rozproszonych magazynach wektorów może być złożone i podatne na błędy, szczególnie w aplikacjach rozproszonych, w których różne usługi lub wystąpienia mogą działać niezależnie i wymagać spójnego dostępu do tych samych danych. Natomiast użycie magazynu w pamięci upraszcza ten proces: po zmianie listy funkcji lub źródła wektoryzacji magazyn w pamięci można łatwo odtworzyć przy użyciu nowego zestawu funkcji i ich osadzania, zapewniając spójność przy minimalnym nakładzie pracy.

Określanie funkcji

Dostawca funkcji kontekstowej musi być dostarczany z listą funkcji, z których może wybrać najbardziej odpowiednie na podstawie bieżącego kontekstu. Jest to realizowane przez podanie listy funkcji do parametru functions konstruktora ContextualFunctionProvider.

Oprócz funkcji należy również określić maksymalną liczbę odpowiednich funkcji do zwrócenia przy użyciu parametru maxNumberOfFunctions . Ten parametr określa, ile funkcji dostawca rozważy podczas wybierania najbardziej odpowiednich funkcji dla bieżącego kontekstu. Określona liczba nie ma być dokładna; zamiast tego służy jako górny limit, który zależy od konkretnego scenariusza.

Ustawienie tej wartości zbyt małej może uniemożliwić agentowi dostęp do wszystkich niezbędnych funkcji w scenariuszu, co potencjalnie prowadzi do awarii scenariusza. Z drugiej strony ustawienie zbyt wysokie może spowodować przeciążenie agenta zbyt wieloma funkcjami, co może spowodować halucynacje, nadmierne użycie tokenu wejściowego i nieoptymalną wydajność.

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

Opcje dostawcy funkcji kontekstowych

Dostawcę można skonfigurować przy użyciu ContextualFunctionProviderOptions klasy , która umożliwia dostosowanie różnych aspektów działania dostawcy:

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

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

Rozmiar kontekstu

Rozmiar kontekstu określa, ile ostatnich komunikatów z poprzednich wywołań agenta jest uwzględnianych podczas tworzenia kontekstu dla nowego wywołania. Dostawca zbiera wszystkie komunikaty z poprzednich wywołań, maksymalnie do określonej liczby i poprzedza je nowymi komunikatami w celu utworzenia kontekstu.

Używanie ostatnich wiadomości wraz z nowymi wiadomościami jest szczególnie przydatne w przypadku zadań wymagających informacji z wcześniejszych kroków konwersacji. Na przykład, jeśli agent aprowizuje zasób w jednym wywołaniu, a wdraża go w następnym, krok wdrożenia może uzyskać dostęp do szczegółów z kroku aprowizacji, aby uzyskać informacje o zaaprowizowanym zasobie dla wdrożenia.

Wartość domyślna liczby ostatnich komunikatów w kontekście wynosi 2, ale można ją skonfigurować zgodnie z potrzebami, określając właściwość w elemecie NumberOfRecentMessagesInContextContextualFunctionProviderOptions:

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

Wartość źródłowa osadzania kontekstu

Aby wykonać wybór funkcji kontekstowej, dostawca musi wektoryzować bieżący kontekst, aby można było porównać go z dostępnymi funkcjami w magazynie wektorów. Domyślnie dostawca tworzy osadzenie kontekstu, łącząc wszystkie niepuste najnowsze i nowe komunikaty w jeden ciąg, który jest następnie wektoryzowany i używany do wyszukiwania odpowiednich funkcji.

W niektórych scenariuszach możesz dostosować to zachowanie do następujących elementów:

  • Skoncentruj się na określonych typach komunikatów (np. tylko wiadomości użytkownika)
  • Wyklucz pewne informacje z kontekstu
  • Wstępne przetwarzanie lub podsumowywanie kontekstu przed wektoryzacją (np. stosowanie przepisania zapytania)

W tym celu możesz przypisać delegata niestandardowego do ContextEmbeddingValueProvider. Ten delegat odbiera ostatnie i nowe komunikaty i zwraca wartość ciągu, która ma być używana jako źródło osadzania kontekstu:

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

Dostosowywanie osadzania kontekstu może poprawić trafność wyboru funkcji, zwłaszcza w złożonych lub wysoce wyspecjalizowanych scenariuszach agentów programowych.

Wartość źródłowa osadzania funkcji

Dostawca musi wektoryzować każdą dostępną funkcję, aby porównać ją z kontekstem i wybrać najbardziej odpowiednie. Domyślnie dostawca tworzy funkcję osadzania, łącząc nazwę i opis funkcji w jeden ciąg, który jest następnie wektoryzowany i przechowywany w magazynie wektorów.

To zachowanie można dostosować przy użyciu EmbeddingValueProvider właściwości ContextualFunctionProviderOptions. Ta właściwość umożliwia określenie wywołania zwrotnego odbierającego funkcję i token anulowania oraz zwraca ciąg, który ma być używany jako źródło osadzania funkcji. Jest to przydatne, jeśli chcesz:

  • Dodawanie dodatkowych metadanych funkcji do źródła osadzania
  • Wstępne przetwarzanie, filtrowanie lub ponowne formatowanie informacji funkcji przed wektoryzacją
ContextualFunctionProviderOptions options = new()
{
    EmbeddingValueProvider = async (function, cancellationToken) =>
    {
        // Example: Use only the function name for embedding
        return function.Name;
    }
};

Dostosowywanie funkcji osadzania wartości źródłowej może poprawić dokładność wyboru funkcji, zwłaszcza gdy funkcje mają rozbudowane, kontekstowe metadane lub gdy chcesz skupić wyszukiwanie na określonych aspektach każdej funkcji.

Dalsze kroki

Eksplorowanie przykładów wyboru funkcji kontekstowych

Wkrótce

Więcej informacji można znaleźć wkrótce.

Wkrótce

Więcej informacji można znaleźć wkrótce.