共用方式為


使用代理程式進行情境函數選擇

這很重要

這項功能處於實驗階段。 此階段的功能處於作用中開發階段,在前進至預覽或發行候選階段之前可能會大幅變更。

概觀

關係型函式選取是語意核心代理程式架構中的進階功能,可讓代理程式根據目前的交談內容動態選取及公告最相關的函式。 這項功能不會向 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")
    };
}

向量存放區

提供者主要是設計來使用記憶體內部向量存放區,以提供簡單性。 不過,如果使用其他類型的向量存放區,請務必注意,處理資料的同步性和一致性的責任落在主機應用程式上。

每當函式清單變更或修改函式內嵌的來源時,都需要同步處理。 例如,如果代理程式一開始有三個函式 (f1, f2, f3) 是向量化並儲存在雲端向量存放區,而稍後 f3 會從代理程式的函式清單中移除,則必須更新向量存放區,只反映代理程式擁有的目前函式 (f1 和 f2)。 未更新向量存放區可能會導致不相關的函式作為結果被返回。 同樣地,如果用於向量化的數據,例如函式名稱、描述等變更,則應該根據更新的資訊清除向量存放區,並以新的內嵌重新填入。

在外部或分散式向量存放區中管理數據同步處理可能會複雜且容易發生錯誤,特別是在不同服務或實例可以獨立運作的分散式應用程式中,而且需要對相同數據的一致存取。 相反地,使用記憶體內部存放區可簡化此程式:當函式清單或向量化來源變更時,可以使用新的函式集及其內嵌來輕鬆地重新建立記憶體內部存放區,確保以最少的努力保持一致性。

指定函式

關係型函式提供者必須提供一份函式清單,以便根據目前內容選取最相關的函式。 這可藉由提供函式清單給 functions 建構函式的參數 ContextualFunctionProvider 來完成。

除了函式之外,您還必須指定使用 maxNumberOfFunctions 參數傳回的相關函式數目上限。 此參數會決定提供者在選取目前內容最相關的函式時,會考慮多少個函式。 指定的數字並非精確;相反地,它會作為取決於特定案例的上限。

將此值設定得太低,可能會導致代理程式無法存取案例的所有必要函式,可能會導致案例失敗。 相反地,設定太高可能會讓代理程式因為太多函式而不知所措,這可能會導致錯誤的反應、過多輸入 token 的消耗,以及效能不佳。

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

上下文大小

上下文大小決定在形成新調用的上下文時,會包含來自先前代理調用的最近訊息數目。 提供者會從之前的呼叫收集所有訊息,最多到指定的數量,並將這些訊息添加到新訊息之前以形成內容。

將最近的訊息與新訊息搭配使用,對於需要交談中先前步驟資訊的工作特別有用。 例如,如果代理程式在一個調用中布建資源,並在下一個叫用中部署資源,部署步驟就可以從布建步驟存取詳細數據,以取得部署的已布建資源資訊。

內容中最近訊息數目的預設值為 2,但您可以視需要在 中ContextualFunctionProviderOptions指定 NumberOfRecentMessagesInContext 屬性來設定此值:

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

內容內嵌來源值

若要執行內容函式選取,提供者必須向量化目前的內容,以便與向量存放區中的可用函式進行比較。 根據預設,提供者會建立此內容內嵌,方法是將所有非空白的最近和新訊息串連成單一字串,然後向量化並用來搜尋相關的函式。

在某些情況下,您可能想要自定義此行為以:

  • 專注於特定訊息類型(例如,只有使用者訊息)
  • 從內容中排除特定資訊
  • 在向量化之前預先處理或摘要內容(例如,套用提示重寫)

若要這樣做,您可以將自訂委派指派給 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);
    }
};

自定義內容內嵌可以改善函式選取的相關性,特別是在複雜或高度特製化的代理程式案例中。

函數嵌入來源值

提供者必須向量化每個可用的函式,才能將其與內容進行比較,並選取最相關的函式。 根據預設,提供者會建立函式內嵌,方法是將函式的名稱和描述串連成單一字串,然後向量化並儲存在向量存放區中。

您可以使用EmbeddingValueProviderContextualFunctionProviderOptions屬性來自定義此行為。 這個屬性可讓您指定一個回調函式,該回調函式會接收函式和取消標記,並傳回作為函式嵌入來源的字串。 這在以下情況很有用,如果您想要:

  • 將其他函式元數據新增至內嵌來源
  • 在向量化之前,前置處理、篩選或重新格式化函式資訊
ContextualFunctionProviderOptions options = new()
{
    EmbeddingValueProvider = async (function, cancellationToken) =>
    {
        // Example: Use only the function name for embedding
        return function.Name;
    }
};

自定義函式內嵌來源值可以改善函式選取的精確度,特別是當您的函式具有豐富、內容相關的元數據,或當您想要將搜尋焦點放在每個函式的特定層面時。

後續步驟

探索關係型函式選取範例

即將推出

更多信息即將推出。

即將推出

更多信息即將推出。