次の方法で共有


エージェントを使用したコンテキスト関数の選択

Von Bedeutung

この機能は実験段階にあります。 この段階の機能は現在開発中であり、プレビューまたはリリース候補ステージに進む前に大幅に変更される可能性があります。

概要

コンテキスト関数の選択は、セマンティック カーネル エージェント フレームワークの高度な機能です。これにより、エージェントは現在の会話コンテキストに基づいて最も関連性の高い関数のみを動的に選択してアドバタイズできます。 この機能では、使用可能なすべての関数を AI モデルに公開する代わりに、Retrieval-Augmented Generation (RAG) を使用して、ユーザーの要求に最も関連する関数のみをフィルター処理して表示します。

このアプローチは、多数の使用可能な関数を処理する場合の関数選択の課題に対処します。AI モデルでは、適切な関数の選択に苦労し、混乱と最適でないパフォーマンスが生じる可能性があります。

コンテキスト関数の選択のしくみ

エージェントがコンテキスト関数の選択を使用して構成されると、ベクター ストアと埋め込みジェネレーターを利用して、現在の会話コンテキスト (以前のメッセージやユーザー入力を含む) と使用可能な関数の説明と名前を意味的に一致させます。 その後、指定された制限を超える最も関連性の高い関数が、呼び出しのために AI モデルにアドバタイズされます。

このメカニズムは、さまざまなプラグインまたはツールにアクセスできるエージェントに特に役立ちます。これにより、各ステップでコンテキストに応じた適切なアクションのみが考慮されます。

使用例

次の例では、コンテキスト関数の選択を使用するようにエージェントを構成する方法を示します。 エージェントは顧客のレビューを要約するように設定されていますが、呼び出しごとに最も関連性の高い関数のみが AI モデルにアドバタイズされます。 GetAvailableFunctionsメソッドには、コンテキスト選択の利点を強調するために、関連する関数と無関係な関数の両方が意図的に含まれています。

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

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

ベクター ストア

このプロバイダーは、主にメモリ内ベクター ストアを操作するように設計されており、わかりやすくなっています。 ただし、他の種類のベクター ストアを使用する場合は、データの同期と整合性を処理する責任がホスティング アプリケーションにかかうことに注意することが重要です。

関数の一覧が変更されたとき、または関数の埋め込みのソースが変更されるたびに、同期が必要です。 たとえば、エージェントが最初に 3 つの関数 (f1、f2、f3) を持ち、それがベクトル化されてクラウド ベクター ストアに格納され、後の f3 がエージェントの関数の一覧から削除された場合、ベクター ストアは、エージェントが持つ現在の関数 (f1 および f2) のみを反映するように更新する必要があります。 ベクター ストアを更新しないと、結果として無関係な関数が返される可能性があります。 同様に、関数名、説明などのベクター化に使用されるデータが変更された場合、ベクター ストアを消去し、更新された情報に基づいて新しい埋め込みを再作成する必要があります。

外部または分散ベクター ストアでのデータ同期の管理は複雑になり、特に異なるサービスまたはインスタンスが独立して動作し、同じデータへの一貫したアクセスを必要とする分散アプリケーションでは、エラーが発生しやすくなります。 一方、インメモリ ストアを使用すると、このプロセスが簡略化されます。関数リストまたはベクター化ソースが変更されると、新しい関数セットとその埋め込みによってメモリ内ストアを簡単に再作成できるため、最小限の労力で一貫性を確保できます。

関数の指定

コンテキスト関数プロバイダーには、現在のコンテキストに基づいて最も関連性の高いものを選択できる関数の一覧を指定する必要があります。 これは、ContextualFunctionProvider コンストラクターの functions パラメーターに関数の一覧を提供することによって実現されます。

関数に加えて、 maxNumberOfFunctions パラメーターを使用して返す関連する関数の最大数も指定する必要があります。 このパラメーターは、現在のコンテキストに最も関連するものを選択するときにプロバイダーが考慮する関数の数を決定します。 指定された数値は正確ではありません。むしろ、特定のシナリオに依存する上限として機能します。

この値を低く設定すると、エージェントがシナリオに必要なすべての機能にアクセスできなくなる可能性があり、シナリオが失敗する可能性があります。 逆に、この値を高く設定すると、多すぎる関数でエージェントが圧倒される可能性があり、その結果、幻覚、過剰な入力トークンの消費、最適でないパフォーマンスが発生する可能性があります。

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

コンテキスト関数プロバイダーのオプション

プロバイダーは、 ContextualFunctionProviderOptions クラスを使用して構成できます。これにより、プロバイダーの動作のさまざまな側面をカスタマイズできます。

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

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

コンテキスト サイズ

コンテキスト サイズは、新しい呼び出しのコンテキストを形成するときに、以前のエージェント呼び出しからの最近のメッセージの数を決定します。 プロバイダーは、前の呼び出しから指定した数までのメッセージをすべて収集し、新しいメッセージの先頭に追加してコンテキストを形成します。

最近のメッセージを新しいメッセージと共に使用することは、会話の前の手順の情報を必要とするタスクに特に役立ちます。 たとえば、エージェントが 1 回の呼び出しでリソースをプロビジョニングし、次の呼び出しでそれをデプロイする場合、デプロイ手順でプロビジョニング手順の詳細にアクセスして、デプロイのプロビジョニングされたリソース情報を取得できます。

コンテキスト内の最近のメッセージの数の既定値は 2 ですが、ContextualFunctionProviderOptionsNumberOfRecentMessagesInContext プロパティを指定することで、必要に応じて構成できます。

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

コンテキスト埋め込みソース値

コンテキスト関数の選択を実行するには、プロバイダーが現在のコンテキストをベクター化して、ベクター ストアで使用可能な関数と比較できるようにする必要があります。 既定では、プロバイダーは、空でない最近のメッセージと新しいメッセージをすべて 1 つの文字列に連結することで、このコンテキスト埋め込みを作成します。このメッセージはベクター化され、関連する関数を検索するために使用されます。

一部のシナリオでは、この動作を次のようにカスタマイズできます。

  • 特定のメッセージの種類 (ユーザー メッセージのみなど) に焦点を当てる
  • コンテキストから特定の情報を除外する
  • ベクター化の前にコンテキストを前処理または要約する (例: プロンプトの書き換えを適用する)

これを行うには、 ContextEmbeddingValueProviderにカスタム デリゲートを割り当てることができます。 このデリゲートは、最近のメッセージと新しいメッセージを受け取り、コンテキスト埋め込みのソースとして使用される文字列値を返します。

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

コンテキスト埋め込みをカスタマイズすると、特に複雑または高度に特殊化されたエージェント のシナリオで、関数の選択の関連性を向上させることができます。

関数埋め込みソース値

プロバイダーは、コンテキストと比較し、最も関連性の高いものを選択するために、使用可能な各関数をベクター化する必要があります。 既定では、プロバイダーは関数の名前と説明を 1 つの文字列に連結して関数埋め込みを作成します。この文字列はベクター化され、ベクター ストアに格納されます。

この動作は、ContextualFunctionProviderOptionsEmbeddingValueProvider プロパティを使用してカスタマイズできます。 このプロパティを使用すると、関数とキャンセル トークンを受け取り、関数埋め込みのソースとして使用される文字列を返すコールバックを指定できます。 これは、次の場合に便利です。

  • 埋め込みソースに関数メタデータを追加する
  • ベクター化の前に関数情報を前処理、フィルター処理、または再フォーマットする
ContextualFunctionProviderOptions options = new()
{
    EmbeddingValueProvider = async (function, cancellationToken) =>
    {
        // Example: Use only the function name for embedding
        return function.Name;
    }
};

関数埋め込みソース値をカスタマイズすると、関数の選択の精度が向上します。特に、関数にコンテキストに関連する豊富なメタデータがある場合や、各関数の特定の側面に焦点を当てたい場合です。

次のステップ

コンテキスト関数の選択サンプルを調べる

間もなく公開

詳細については、近日公開予定です。

間もなく公開

詳細については、近日公開予定です。