共用方式為


開始使用 Azure AI 個人化服務工具的多插槽

重要

從 2023 年 9 月 20 日起,您將無法建立新的個人化工具資源。 個人化工具服務將於 2026 年 10 月 1 日淘汰。

多位置個人化 (預覽) 可讓您在網頁版面配置、浮動切換和清單中設定內容目標,並向使用者顯示其中的多個動作 (例如一項產品或一段內容)。 使用個人化工具多位置 API,您可以讓個人化工具中的 AI 模型了解哪些使用者內容和產品會驅動特定行為,以及考慮其在使用者介面中的位置並從中學習。 例如,個人化工具可能會學到,某些產品或內容作為側邊欄或頁尾,會比作為頁面上的主要醒目提示獲得更多點擊次數。

在本指南中,您將了解如何使用個人化工具多位置 API。

參考文件 | 程式庫原始程式碼 | 套件 (NuGet) | 多位置概念 | 範例

必要條件

  • Azure 訂用帳戶 - 建立免費帳戶
  • 最新版 .NET Core
  • 擁有 Azure 訂閱之後,在 Azure 入口網站中建立個人化工具資源,以取得您的金鑰和端點。 在其部署後,選取 [前往資源]
    • 您需要來自所建立資源的金鑰和端點,以將應用程式連線至個人化工具 API。 稍後會在快速入門中將金鑰和端點貼到下列程式碼中。
    • 您可以使用免費定價層 (F0) 來試用服務,之後可升級至付費層以用於實際執行環境。

設定

將個人化工具執行個體升級為多位置

注意

多位置個人化 (預覽) 會影響個人化工具服務的其他功能。 這項變更無法復原。 啟用多位置個人化之前,請參閱多位置個人化 (預覽)

  1. 停用自動最佳化。在 Azure 入口網站的個人化工具資源中,於 [資源管理] 下的 [Model and learning settings] \(模型和學習設定\) 頁面上,關閉自動最佳化並儲存。

注意

除非您停用自動最佳化,否則多位置個人化將無法運作。 未來將會支援多位置個人化的自動最佳化。

  1. 將個人化服務工具更新為多插槽。在 Azure 入口網站的個人化服務工具資源中,於 [資源管理] 下的 [模型和學習設定] 頁面上,選取 [匯出學習設定]。 已下載 JSON 檔案中的 [引數] 欄位會以 --cb_explore_adf 開頭。 請將此變更為 --ccb_explore_adf 並儲存檔案。 CB (Contextual Bandit) 和 CCB (Conditional Contextual Bandit) 是個人化工具針對單一位置個人化和多位置個人化分別使用的演算法。 ADF (動作相依功能) 表示動作是以功能表示/識別。

變更前的學習設定

變更後的學習設定

在入口網站的相同索引標籤中,於 [import learning settings] \(匯入學習設定\) 下,瀏覽並找到您最近修改的 JSON 檔案,然後將其上傳。 這會將您的個人化工具執行個體更新為「多位置」個人化工具,現在會支援多位置排名和獎勵呼叫。

變更模型更新頻率

在 Azure 入口網站中,前往個人化服務工具資源的 [設定] 頁面,將 [模型更新頻率] 變更為 30 秒。 這個較短的時間將會快速定型模型,讓您可以查看建議的動作會如何針對每個反覆項目變更。

變更模型更新頻率

變更奬勵等待時間

在 Azure 入口網站中,前往個人化服務工具資源的 [設定] 頁面,將 [奬勵等待時間] 變更為 10 分鐘。 這會決定模型在傳送建議之後等候的時間長度,以接收來自該建議的獎勵意見反應。 直到獎勵等候時間過後,才會進行定型。

變更奬勵等待時間

建立新的 C# 應用程式

在您慣用的編輯器或 IDE 中,建立新的 .NET Core 應用程式。

在主控台視窗中 (例如 cmd、PowerShell 或 Bash),使用 dotnet new 命令建立名為 personalizer-quickstart 的新主控台應用程式。 此命令會建立簡單的 "Hello World" C# 專案,內含單一原始程式檔:Program.cs

dotnet new console -n personalizer-quickstart

將目錄變更為新建立的應用程式資料夾。 您可以使用下列命令來建置應用程式:

dotnet build

建置輸出應該不會有警告或錯誤。

...
Build succeeded.
 0 Warning(s)
 0 Error(s)
...

安裝用戶端程式庫

在應用程式目錄中,使用下列命令安裝適用於 .NET 的個人化工具用戶端程式庫:

dotnet add package Azure.AI.Personalizer --version 2.0.0-beta.2

從專案目錄,在慣用的編輯器或 IDE 中開啟 Program.cs 檔案。 新增下列 using 指示詞:

using System;
using Azure;
using Azure.AI.Personalizer;
using System.Collections.Generic;
using System.Linq;

物件模型

個人化工具用戶端是一種 PersonalizerClient 物件,會使用含有金鑰的 Azure.AzureKeyCredential 向 Azure 進行驗證。

若要取得每個位置內容的單一最佳項目,請建立 PersonalizerRankMultiSlotOptions 物件,然後將其傳遞至 PersonalizerClient.RankMultiSlot。 RankMultiSlot 方法會傳回 PersonalizerMultiSlotRankResult

若要將獎勵分數傳送給個人化工具,請建立 PersonalizerRewardMultiSlotOptions,然後將其傳至 PersonalizerClient.RewardMultiSlot 方法以及對應的事件識別碼。

本快速入門中的獎勵評分很簡單。 在生產系統中,判斷影響獎勵分數的因素及影響程度可能是複雜的程序,您可能會隨著時間做出變更決定。 此設計決策應該是您個人化工具架構中的其中一個主要決策。

程式碼範例

這些程式碼片段會示範如何使用適用於 .NET 的個人化工具用戶端程式庫來執行下列工作:

驗證用戶端

在本節中,您將執行兩個動作:

  • 指定您的金鑰和端點
  • 建立個人化工具用戶端

首先,將下列幾行新增至您的 Program 類別。 務必從您的個人化工具資源新增金鑰和端點。

重要

前往 Azure 入口網站。 如果您在 [必要條件] 區段中建立的個人化工具資源成功部署,請按一下 [後續步驟] 底下的 [前往資源] 按鈕。 您可以在 [資源管理] 底下的 [金鑰和端點] 頁面中找到金鑰和端點。

完成時,請記得從程式碼中移除金鑰,且不要公開張貼金鑰。 在生產環境中,請考慮使用安全的方式來儲存及存取您的認證。 例如,Azure金鑰保存庫

private const string ServiceEndpoint  = "https://REPLACE-WITH-YOUR-PERSONALIZER-RESOURCE-NAME.cognitiveservices.azure.com";
private const string ResourceKey = "<REPLACE-WITH-YOUR-PERSONALIZER-KEY>";

接下來,建構排名和獎勵 URL。

static PersonalizerClient InitializePersonalizerClient(Uri url)
{
    return new PersonalizerClient(url, new AzureKeyCredential(ResourceKey));
}

取得以動作表示的內容選擇

動作代表您要個人化工具從中選取最佳內容項目的內容選擇。 將下列方法新增至 Program 類別,以代表動作及其特性的組合。

private static IList<PersonalizerRankableAction> GetActions()
{
    IList<PersonalizerRankableAction> actions = new List<PersonalizerRankableAction>
    {
        new PersonalizerRankableAction(
            id: "Red-Polo-Shirt-432",
            features:
            new List<object>() { new { onSale = "true", price = "20", category = "Clothing" } }
        ),

        new PersonalizerRankableAction(
            id: "Tennis-Racket-133",
            features:
            new List<object>() { new { onSale = "false", price = "70", category = "Sports" } }
        ),

        new PersonalizerRankableAction(
            id: "31-Inch-Monitor-771",
            features:
            new List<object>() { new { onSale = "true", price = "200", category = "Electronics" } }
        ),

        new PersonalizerRankableAction(
            id: "XBox-Series X-117",
            features:
            new List<object>() { new { onSale = "false", price = "499", category = "Electronics" } }
        )
    };

    return actions;
}

取得位置

位置會構成與使用者互動的頁面。 個人化工具會決定要在每一個已定義位置中顯示的動作。 您可以從特定位置排除動作,並以 ExcludeActions 顯示。 BaselineAction 是位置的預設動作,會在不使用個人化工具的情況下顯示。

本快速入門包含簡單的位置功能。 在生產系統中,判斷和評估功能 (部分機器翻譯) 可能不是簡單的事。

private static IList<PersonalizerSlotOptions> GetSlots()
{
    IList<PersonalizerSlotOptions> slots = new List<PersonalizerSlotOptions>
    {
        new PersonalizerSlotOptions(
            id: "BigHeroPosition",
            features: new List<object>() { new { size = "large", position = "left" } },
            excludedActions: new List<string>() { "31-Inch-Monitor-771" },
            baselineAction: "Red-Polo-Shirt-432"

        ),

        new PersonalizerSlotOptions(
            id: "SmallSidebar",
            features: new List<object>() { new { size = "small", position = "right" } },
            excludedActions: new List<string>() { "Tennis-Racket-133" },
            baselineAction: "XBox-Series X-117"
        ),
    };

    return slots;
}

取得內容的使用者喜好設定

將下列方法新增至 [程式] 類別,以從命令列取得一天時間和使用者所在裝置類型的使用者輸入。 這些方法會作為內容特性使用。

static string GetTimeOfDayForContext()
{
    string[] timeOfDayFeatures = new string[] { "morning", "afternoon", "evening", "night" };

    Console.WriteLine("\nWhat time of day is it (enter number)? 1. morning 2. afternoon 3. evening 4. night");
    if (!int.TryParse(GetKey(), out int timeIndex) || timeIndex < 1 || timeIndex > timeOfDayFeatures.Length)
    {
        Console.WriteLine("\nEntered value is invalid. Setting feature value to " + timeOfDayFeatures[0] + ".");
        timeIndex = 1;
    }

    return timeOfDayFeatures[timeIndex - 1];
}
static string GetDeviceForContext()
{
    string[] deviceFeatures = new string[] { "mobile", "tablet", "desktop" };

    Console.WriteLine("\nWhat is the device type (enter number)? 1. Mobile 2. Tablet 3. Desktop");
    if (!int.TryParse(GetKey(), out int deviceIndex) || deviceIndex < 1 || deviceIndex > deviceFeatures.Length)
    {
        Console.WriteLine("\nEntered value is invalid. Setting feature value to " + deviceFeatures[0] + ".");
        deviceIndex = 1;
    }

    return deviceFeatures[deviceIndex - 1];
}

這兩個方法都會使用 GetKey 方法從命令列讀取使用者的選取。

private static string GetKey()
{
    return Console.ReadKey().Key.ToString().Last().ToString().ToUpper();
}
private static IList<object> GetContext(string time, string device)
{
    return new List<object>()
    {
        new { time = time },
        new { device = device }
    };
}

建立學習迴圈

個人化工具學習迴圈是 RankMultiSlotRewardMultiSlot 呼叫的循環。 在本快速入門中,用於個人化內容的每個排名呼叫後面都會接著獎勵呼叫,以告訴個人化工具該服務的成效為何。

下列程式碼會透過命令列進行詢問使用者喜好的循環迴圈,並將該資訊傳送至個人化工具以選取每個位置的最佳動作,然後向客戶顯示選取項目,讓他們從清單中選擇,接著將獎勵分數傳送至個人化工具,指出服務在其選取項目中的成效為何。

static void Main(string[] args)
{
    Console.WriteLine($"Welcome to this Personalizer Quickstart!\n" +
    $"This code will help you understand how to use the Personalizer APIs (multislot rank and multislot reward).\n" +
    $"Each iteration represents a user interaction and will demonstrate how context, actions, slots, and rewards work.\n" +
    $"Note: Personalizer AI models learn from a large number of user interactions:\n" +
    $"You won't be able to tell the difference in what Personalizer returns by simulating a few events by hand.\n" +
    $"If you want a sample that focuses on seeing how Personalizer learns, see the Python Notebook sample.");

    int iteration = 1;
    bool runLoop = true;

    IList<PersonalizerRankableAction> actions = GetActions();
    IList<PersonalizerSlotOptions> slots = GetSlots();
    PersonalizerClient client = InitializePersonalizerClient(new Uri(ServiceEndpoint));

    do
    {
        Console.WriteLine("\nIteration: " + iteration++);

        string timeOfDayFeature = GetTimeOfDayForContext();
        string deviceFeature = GetDeviceForContext();

        IList<object> currentContext = GetContext(timeOfDayFeature, deviceFeature);

        string eventId = Guid.NewGuid().ToString();

        var multiSlotRankOptions = new PersonalizerRankMultiSlotOptions(actions, slots, currentContext, eventId);
        PersonalizerMultiSlotRankResult multiSlotRankResult = client.RankMultiSlot(multiSlotRankOptions);

        for (int i = 0; i < multiSlotRankResult.Slots.Count(); ++i)
        {
            string slotId = multiSlotRankResult.Slots[i].SlotId;
            Console.WriteLine($"\nPersonalizer service decided you should display: { multiSlotRankResult.Slots[i].RewardActionId} in slot {slotId}. Is this correct? (y/n)");

            string answer = GetKey();

            if (answer == "Y")
            {
                client.RewardMultiSlot(eventId, slotId, 1f);
                Console.WriteLine("\nGreat! The application will send Personalizer a reward of 1 so it learns from this choice of action for this slot.");
            }
            else if (answer == "N")
            {
                client.RewardMultiSlot(eventId, slotId, 0f);
                Console.WriteLine("\nYou didn't like the recommended item. The application will send Personalizer a reward of 0 for this choice of action for this slot.");
            }
            else
            {
                client.RewardMultiSlot(eventId, slotId, 0f);
                Console.WriteLine("\nEntered choice is invalid. Service assumes that you didn't like the recommended item.");
            }
        }

        Console.WriteLine("\nPress q to break, any other key to continue:");
        runLoop = !(GetKey() == "Q");

    } while (runLoop);
}

請仔細查看下列各節中的排名和報酬呼叫。 新增下列方法,取得內容選項取得位置傳送多位置排名和獎勵要求,再執行程式碼檔案:

  • GetActions
  • GetSlots
  • GetTimeOfDayForContext
  • GetDeviceForContext
  • GetKey
  • GetContext

要求最佳動作

為了完成排名要求,程式會詢問使用者的喜好,以建立內容選擇的 Context。 要求包含內容、動作和位置及其各自的功能與唯一事件識別碼,用以接收回應。

本快速入門包含一天時間和使用者裝置的簡單內容功能。 在生產系統中,判斷和評估動作和特性可能不是簡單的事。

string timeOfDayFeature = GetTimeOfDayForContext();
string deviceFeature = GetDeviceForContext();

IList<object> currentContext = GetContext(timeOfDayFeature, deviceFeature);

string eventId = Guid.NewGuid().ToString();

var multiSlotRankOptions = new PersonalizerRankMultiSlotOptions(actions, slots, currentContext, eventId);
PersonalizerMultiSlotRankResult multiSlotRankResult = client.RankMultiSlot(multiSlotRankOptions);

傳送獎勵

若要取得獎勵要求的獎勵分數,程式會透過命令列取得使用者針對每個位置的選取項目,將數值 (獎勵分數) 指派給選取項目,然後將唯一的事件識別碼、位置識別碼和每個位置的獎勵分數當作數值傳送至獎勵 API。 不需要為每個位置定義獎勵。

本快速入門會指派簡單的數字作為獎勵分數,也就是零或 1。 在生產系統中,視您的特定需求而定,判斷要傳送給獎勵呼叫的時機和內容可能不是簡單的事。

for (int i = 0; i < multiSlotRankResult.Slots.Count(); ++i)
{
    string slotId = multiSlotRankResult.Slots[i].SlotId;
    Console.WriteLine($"\nPersonalizer service decided you should display: { multiSlotRankResult.Slots[i].RewardActionId} in slot {slotId}. Is this correct? (y/n)");

    string answer = GetKey();

    if (answer == "Y")
    {
        client.RewardMultiSlot(eventId, slotId, 1f);
        Console.WriteLine("\nGreat! The application will send Personalizer a reward of 1 so it learns from this choice of action for this slot.");
    }
    else if (answer == "N")
    {
        client.RewardMultiSlot(eventId, slotId, 0f);
        Console.WriteLine("\nYou didn't like the recommended item. The application will send Personalizer a reward of 0 for this choice of action for this slot.");
    }
    else
    {
        client.RewardMultiSlot(eventId, slotId, 0f);
        Console.WriteLine("\nEntered choice is invalid. Service assumes that you didn't like the recommended item.");
    }
}

執行程式

從應用程式目錄使用 dotnet run 命令來執行應用程式。

dotnet run

快速入門程式會詢問幾個問題以收集使用者偏好 (稱為特性),然後提供最佳的動作。

這裡可取得適用於此快速入門的原始程式碼

參考文件 | 多位置概念 | 範例

必要條件

  • Azure 訂用帳戶 - 建立免費帳戶
  • 安裝 Node.js \(英文\) 和 NPM (已使用 Node.js v14.16.0 和 NPM 6.14.11 進行驗證)。
  • 擁有 Azure 訂閱之後,在 Azure 入口網站中建立個人化工具資源,以取得您的金鑰和端點。 在其部署後,選取 [前往資源]
    • 您需要來自所建立資源的金鑰和端點,以將應用程式連線至個人化工具 API。 稍後會在快速入門中將金鑰和端點貼到下列程式碼中。
    • 您可以使用免費定價層 (F0) 來試用服務,之後可升級至付費層以用於實際執行環境。

設定

將個人化工具執行個體升級為多位置

注意

多位置個人化 (預覽) 會影響個人化工具服務的其他功能。 這項變更無法復原。 啟用多位置個人化之前,請參閱多位置個人化 (預覽)

  1. 停用自動最佳化。在 Azure 入口網站的個人化工具資源中,於 [資源管理] 下的 [Model and learning settings] \(模型和學習設定\) 頁面上,關閉自動最佳化並儲存。

注意

除非您停用自動最佳化,否則多位置個人化將無法運作。 未來將會支援多位置個人化的自動最佳化。

  1. 將個人化服務工具更新為多插槽。在 Azure 入口網站的個人化服務工具資源中,於 [資源管理] 下的 [模型和學習設定] 頁面上,選取 [匯出學習設定]。 已下載 JSON 檔案中的 [引數] 欄位會以 --cb_explore_adf 開頭。 請將此變更為 --ccb_explore_adf 並儲存檔案。 CB (Contextual Bandit) 和 CCB (Conditional Contextual Bandit) 是個人化工具針對單一位置個人化和多位置個人化分別使用的演算法。 ADF (動作相依功能) 表示動作是以功能表示/識別。

變更前的學習設定

變更後的學習設定

在入口網站的相同索引標籤中,於 [import learning settings] \(匯入學習設定\) 下,瀏覽並找到您最近修改的 JSON 檔案,然後將其上傳。 這會將您的個人化工具執行個體更新為「多位置」個人化工具,現在會支援多位置排名和獎勵呼叫。

變更模型更新頻率

在 Azure 入口網站中,前往個人化服務工具資源的 [設定] 頁面,將 [模型更新頻率] 變更為 30 秒。 這個較短的時間將會快速定型模型,讓您可以查看建議的動作會如何針對每個反覆項目變更。

變更模型更新頻率

變更奬勵等待時間

在 Azure 入口網站中,前往個人化服務工具資源的 [設定] 頁面,將 [奬勵等待時間] 變更為 10 分鐘。 這會決定模型在傳送建議之後等候的時間長度,以接收來自該建議的獎勵意見反應。 直到獎勵等候時間過後,才會進行定型。

變更奬勵等待時間

建立新的 Node.js 應用程式

在主控台視窗 (例如 cmd、PowerShell 或 Bash) 中,為您的應用程式建立新的目錄,並瀏覽至該目錄。

mkdir myapp && cd myapp

執行 npm init -y 命令以建立 package.json 檔案。

npm init -y

在您慣用的編輯器或 IDE 中,建立名為 sample.js 的新 Node.js 應用程式,並為您的資源端點和訂用帳戶金鑰建立變數。

重要

前往 Azure 入口網站。 如果您在 [必要條件] 區段中建立的個人化工具資源成功部署,請按一下 [後續步驟] 底下的 [前往資源] 按鈕。 您可以在 [資源管理] 底下的 [金鑰和端點] 頁面中找到金鑰和端點。

完成時,請記得從程式碼中移除金鑰,且不要公開張貼金鑰。 在生產環境中,請考慮使用安全的方式來儲存及存取您的認證。 例如,Azure金鑰保存庫

const axios = require('axios');
const { v4: uuidv4 } = require('uuid');
const readline = require('readline-sync');
// The endpoint specific to your personalization service instance; 
// e.g. https://<your-resource-name>.cognitiveservices.azure.com
const PersonalizationBaseUrl = '<REPLACE-WITH-YOUR-PERSONALIZER-ENDPOINT>';
// The key specific to your personalization service instance; e.g. "0123456789abcdef0123456789ABCDEF"
const ResourceKey = '<REPLACE-WITH-YOUR-PERSONALIZER-KEY>';

安裝適用於快速入門的 NPM 套件

npm install readline-sync uuid axios --save

物件模型

若要要求每個位置內容的首選項目,請建立 rankRequest,然後將 POST 要求傳送至 multislot/rank。 回應會接著剖析成 rankResponse

若要將獎勵分數傳送至個人化工具,請建立獎勵,然後將 POST 要求傳送至 multislot/events/{事件識別碼}/reward

在本快速入門中,決定獎勵分數是很簡單的。 在生產系統中,判斷影響獎勵分數的因素及影響程度可能是複雜的程序,您可能會隨著時間做出變更決定。 此設計決策應該是您個人化工具架構中的其中一個主要決策。

程式碼範例

這些程式碼片段將示範如何藉由傳送 NodeJS 的 HTTP 要求來執行下列工作:

建立基底 URL

在本節中,您將使用基底 URL 建構排名/獎勵 URL,並使用資源金鑰建構要求標頭。

const MultiSlotRankUrl = PersonalizationBaseUrl.concat('personalizer/v1.1-preview.1/multislot/rank');
const MultiSlotRewardUrlBase = PersonalizationBaseUrl.concat('personalizer/v1.1-preview.1/multislot/events/');
const Headers = {
    'ocp-apim-subscription-key': ResourceKey,
    'Content-Type': 'application/json'
};

取得以動作表示的內容選擇

動作代表您要個人化工具從中選取最佳內容項目的內容選擇。 將下列方法新增至指令碼,以代表動作及其功能的組合。

function getActions() {
    return [
        {
            'id': 'Red-Polo-Shirt-432',
            'features': [
                {
                    'onSale': 'true',
                    'price': 20,
                    'category': 'Clothing'
                }
            ]
        },
        {
            'id': 'Tennis-Racket-133',
            'features': [
                {
                    'onSale': 'false',
                    'price': 70,
                    'category': 'Sports'
                }
            ]
        },
        {
            'id': '31-Inch-Monitor-771',
            'features': [
                {
                    'onSale': 'true',
                    'price': 200,
                    'category': 'Electronics'
                }
            ]
        },
        {
            'id': 'XBox-Series X-117',
            'features': [
                {
                    'onSale': 'false',
                    'price': 499,
                    'category': 'Electronics'
                }
            ]
        }
    ];
}

取得內容的使用者喜好設定

將下列方法新增至指令碼,以從命令列取得一天時間和使用者所在裝置類型的使用者輸入。 這些會作為關係特性使用。

function getContextFeatures() {
    const timeOfDayFeatures = ['morning', 'afternoon', 'evening', 'night'];
    const deviceFeatures = ['mobile', 'tablet', 'desktop'];

    let answer = readline.question('\nWhat time of day is it (enter number)? 1. morning 2. afternoon 3. evening 4. night\n');
    let selection = parseInt(answer);
    const timeOfDay = selection >= 1 && selection <= 4 ? timeOfDayFeatures[selection - 1] : timeOfDayFeatures[0];

    answer = readline.question('\nWhat type of device is the user on (enter number)? 1. mobile 2. tablet 3. desktop\n');
    selection = parseInt(answer);
    const device = selection >= 1 && selection <= 3 ? deviceFeatures[selection - 1] : deviceFeatures[0];

    console.log('Selected features:\n');
    console.log('Time of day: ' + timeOfDay + '\n');
    console.log('Device: ' + device + '\n');

    return [
        {
            'time': timeOfDay
        },
        {
            'device': device
        }
    ];
}

取得位置

位置會構成與使用者互動的頁面。 個人化工具會決定要在每一個已定義位置中顯示的動作。 您可以從特定位置排除動作,並以 ExcludeActions 顯示。 BaselineAction 是位置的預設動作,會在不使用個人化工具的情況下顯示。

本快速入門包含簡單的位置功能。 在生產系統中,判斷和評估功能 (部分機器翻譯) 可能不是簡單的事。

function getSlots() {
    return [
        {
            'id': 'BigHeroPosition',
            'features': [
                {
                    'size': 'large',
                    'position': 'left',
                }
            ],
            'excludedActions': ['31-Inch-Monitor-771'],
            'baselineAction': 'Red-Polo-Shirt-432'
        },
        {
            'id': 'SmallSidebar',
            'features': [
                {
                    'size': 'small',
                    'position': 'right',
                }
            ],
            'excludedActions': ['Tennis-Racket-133'],
            'baselineAction': 'XBox-Series X-117'
        }
    ];
}

發出 HTTP 要求

新增這些函式,將 POST 要求傳送至個人化工具端點,以進行多位置排名和獎勵呼叫。

async function sendMultiSlotRank(rankRequest) {
    try {
        let response = await axios.post(MultiSlotRankUrl, rankRequest, { headers: Headers })
        return response.data;
    }
    catch (err) {
        if(err.response)
        {
            throw err.response.data
        }
        console.log(err)
        throw err;
    }
}
async function sendMultiSlotReward(rewardRequest, eventId) {
    try {
        let rewardUrl = MultiSlotRewardUrlBase.concat(eventId, '/reward');
        let response = await axios.post(rewardUrl, rewardRequest, { headers: Headers })
    }
    catch (err) {
        console.log(err);
        throw err;
    }
}

取得對於個人化工具決策的意見反應

將下列方法新增至指令碼。 您將透過命令列提示,指出個人化工具是否對每個位置做出適當的決策。

function getRewardForSlot() {
    let answer = readline.question('\nIs this correct? (y/n)\n').toUpperCase();
    if (answer === 'Y') {
        console.log('\nGreat! The application will send Personalizer a reward of 1 so it learns from this choice of action for this slot.\n');
        return 1;
    }
    else if (answer === 'N') {
        console.log('\nYou didn\'t like the recommended item.The application will send Personalizer a reward of 0 for this choice of action for this slot.\n');
        return 0;
    }
    console.log('\nEntered choice is invalid. Service assumes that you didn\'t like the recommended item.\n');
    return 0;
}

建立學習迴圈

個人化工具學習迴圈是排名獎勵呼叫的循環。 在本快速入門中,用於個人化內容的每個排名呼叫後面都會接著獎勵呼叫,以告訴個人化工具該服務的成效為何。

下列程式碼會透過命令列進行詢問使用者喜好的循環迴圈,並將該資訊傳送至個人化工具以選取每個位置的最佳動作,然後向客戶顯示選取項目,讓他們從清單中選擇,接著將獎勵分數傳送至個人化工具,指出服務在其選取項目中的成效為何。

let runLoop = true;

(async () => {
    do {

        let multiSlotRankRequest = {};

        // Generate an ID to associate with the request.
        multiSlotRankRequest.eventId = uuidv4();

        // Get context information from the user.
        multiSlotRankRequest.contextFeatures = getContextFeatures();

        // Get the actions list to choose from personalization with their features.
        multiSlotRankRequest.actions = getActions();

        // Get the list of slots for which Personalizer will pick the best action.
        multiSlotRankRequest.slots = getSlots();

        multiSlotRankRequest.deferActivation = false;

        try {
            //Rank the actions for each slot
            let multiSlotRankResponse = await sendMultiSlotRank(multiSlotRankRequest);
            let multiSlotrewards = {};
            multiSlotrewards.reward = [];
    
            for (let i = 0; i < multiSlotRankResponse.slots.length; i++) {
                console.log('\nPersonalizer service decided you should display: '.concat(multiSlotRankResponse.slots[i].rewardActionId, ' in slot ', multiSlotRankResponse.slots[i].id, '\n'));
    
                let slotReward = {};
                slotReward.slotId = multiSlotRankResponse.slots[i].id;
                // User agrees or disagrees with Personalizer decision for slot
                slotReward.value = getRewardForSlot();
                multiSlotrewards.reward.push(slotReward);
            }
    
            // Send the rewards for the event
            await sendMultiSlotReward(multiSlotrewards, multiSlotRankResponse.eventId);
    
            let answer = readline.question('\nPress q to break, any other key to continue:\n').toUpperCase();
            if (answer === 'Q') {
                runLoop = false;
            }
        }
        catch (err) {
            console.log(err);
            throw err;
        }



    } while (runLoop);
})()

請仔細查看下列各節中的排名和報酬呼叫。

新增下列方法,取得內容選項取得內容的使用者喜好設定取得位置提出 HTTP 要求取得每個位置的獎勵,再執行程式碼檔案:

  • getActions
  • getContextFeatures
  • getSlots
  • sendRank
  • sendReward
  • getRewardForSlot

要求最佳動作

為了完成排名要求,程式會詢問使用者的喜好來建立內容選擇。 要求本文包含內容、動作和位置及其各自的功能。 sendMultiSlotRank 方法會接受 rankRequest,並執行多位置排名要求。

本快速入門包含一天時間和使用者裝置的簡單內容功能。 在生產系統中,判斷和評估動作和特性可能不是簡單的事。

let multiSlotRankRequest = {};

// Generate an ID to associate with the request.
multiSlotRankRequest.eventId = uuidv4();

// Get context information from the user.
multiSlotRankRequest.contextFeatures = getContextFeatures();

// Get the actions list to choose from personalization with their features.
multiSlotRankRequest.actions = getActions();

// Get the list of slots for which Personalizer will pick the best action.
multiSlotRankRequest.slots = getSlots();

multiSlotRankRequest.deferActivation = false;

//Rank the actions for each slot
try {
    let multiSlotRankResponse = await sendMultiSlotRank(multiSlotRankRequest);
}
catch (err) {
    console.log(err);
    throw err;
}

傳送獎勵

若要取得獎勵要求的獎勵分數,程式會透過命令列取得使用者針對每個位置的選取項目,將數值 (獎勵分數) 指派給選取項目,然後將唯一的事件識別碼、位置識別碼和每個位置的獎勵分數傳送至 sendMultiSlotReward 方法。 不需要為每個位置定義獎勵。

本快速入門會指派簡單的數字作為獎勵分數,也就是零或 1。 在生產系統中,視您的特定需求而定,判斷要傳送給獎勵呼叫的時機和內容可能不是簡單的事。

let multiSlotrewards = {};
multiSlotrewards.reward = [];

for (i = 0; i < multiSlotRankResponse.slots.length; i++) {
    console.log('\nPersonalizer service decided you should display: '.concat(multiSlotRankResponse.slots[i].rewardActionId, ' in slot ', multiSlotRankResponse.slots[i].id, '\n'));

    let slotReward = {};
    slotReward.slotId = multiSlotRankResponse.slots[i].id;
    // User agrees or disagrees with Personalizer decision for slot
    slotReward.value = getRewardForSlot();
    multiSlotrewards.reward.push(slotReward);
}

// Send the rewards for the event
await sendMultiSlotReward(multiSlotrewards, multiSlotRankResponse.eventId);

執行程式

使用 Node.js 從您的應用程式目錄執行應用程式。

node sample.js

快速入門程式會詢問幾個問題以收集使用者偏好 (稱為特性),然後提供最佳的動作。

這裡可取得適用於此快速入門的原始程式碼

多位置概念 | 範例

必要條件

  • Azure 訂用帳戶 - 建立免費帳戶
  • Python 3.x
  • 擁有 Azure 訂閱之後,在 Azure 入口網站中建立個人化工具資源,以取得您的金鑰和端點。 在其部署後,選取 [前往資源]
    • 您需要來自所建立資源的金鑰和端點,以將應用程式連線至個人化工具 API。 稍後會在快速入門中將金鑰和端點貼到下列程式碼中。
    • 您可以使用免費定價層 (F0) 來試用服務,之後可升級至付費層以用於實際執行環境。

設定

將個人化工具執行個體升級為多位置

注意

多位置個人化 (預覽) 會影響個人化工具服務的其他功能。 這項變更無法復原。 啟用多位置個人化之前,請參閱多位置個人化 (預覽)

  1. 停用自動最佳化。在 Azure 入口網站的個人化工具資源中,於 [資源管理] 下的 [Model and learning settings] \(模型和學習設定\) 頁面上,關閉自動最佳化並儲存。

注意

除非您停用自動最佳化,否則多位置個人化將無法運作。 未來將會支援多位置個人化的自動最佳化。

  1. 將個人化服務工具更新為多插槽。在 Azure 入口網站的個人化服務工具資源中,於 [資源管理] 下的 [模型和學習設定] 頁面上,選取 [匯出學習設定]。 已下載 JSON 檔案中的 [引數] 欄位會以 --cb_explore_adf 開頭。 請將此變更為 --ccb_explore_adf 並儲存檔案。 CB (Contextual Bandit) 和 CCB (Conditional Contextual Bandit) 是個人化工具針對單一位置個人化和多位置個人化分別使用的演算法。 ADF (動作相依功能) 表示動作是以功能表示/識別。

變更前的學習設定

變更後的學習設定

在入口網站的相同索引標籤中,於 [import learning settings] \(匯入學習設定\) 下,瀏覽並找到您最近修改的 JSON 檔案,然後將其上傳。 這會將您的個人化工具執行個體更新為「多位置」個人化工具,現在會支援多位置排名和獎勵呼叫。

變更模型更新頻率

在 Azure 入口網站中,前往個人化服務工具資源的 [設定] 頁面,將 [模型更新頻率] 變更為 30 秒。 這個較短的時間將會快速定型模型,讓您可以查看建議的動作會如何針對每個反覆項目變更。

變更模型更新頻率

變更奬勵等待時間

在 Azure 入口網站中,前往個人化服務工具資源的 [設定] 頁面,將 [奬勵等待時間] 變更為 10 分鐘。 這會決定模型在傳送建議之後等候的時間長度,以接收來自該建議的獎勵意見反應。 直到獎勵等候時間過後,才會進行定型。

變更奬勵等待時間

建立新的 Python 應用程式

建立新的 Python 檔案,並為資源的端點和訂用帳戶金鑰建立變數。

重要

前往 Azure 入口網站。 如果您在 [必要條件] 區段中建立的個人化工具資源成功部署,請按一下 [後續步驟] 底下的 [前往資源] 按鈕。 您可以在 [資源管理] 底下的 [金鑰和端點] 頁面中找到金鑰和端點。

完成時,請記得從程式碼中移除金鑰,且不要公開張貼金鑰。 在生產環境中,請考慮使用安全的方式來儲存及存取您的認證。 例如,Azure金鑰保存庫

import json, uuid, requests

# The endpoint specific to your personalization service instance; 
# e.g. https://<your-resource-name>.cognitiveservices.azure.com
PERSONALIZATION_BASE_URL = "<REPLACE-WITH-YOUR-PERSONALIZER-ENDPOINT>"
# The key specific to your personalization service instance; e.g. "0123456789abcdef0123456789ABCDEF"
RESOURCE_KEY = "<REPLACE-WITH-YOUR-PERSONALIZER-KEY>"

物件模型

若要要求每個位置內容的首選項目,請建立 rank_request,然後將 POST 要求傳送至 multislot/rank。 回應會接著剖析成 rank_response

若要將獎勵分數傳送至個人化工具,請建立獎勵,然後將 POST 要求傳送至 multislot/events/{事件識別碼}/reward

在本快速入門中,決定獎勵分數是很簡單的。 在生產系統中,判斷影響獎勵分數的因素及影響程度可能是複雜的程序,您可能會隨著時間更改決定。 此設計決策應該是您個人化工具架構中的其中一個主要決策。

程式碼範例

這些程式碼片段將示範如何藉由傳送 Python 的 HTTP 要求來執行下列工作:

建立基底 URL

在本節中,您將使用基底 URL 建構排名/獎勵 URL,並使用資源金鑰建構要求標頭。

MULTI_SLOT_RANK_URL = '{0}personalizer/v1.1-preview.1/multislot/rank'.format(PERSONALIZATION_BASE_URL)
MULTI_SLOT_REWARD_URL_BASE = '{0}personalizer/v1.1-preview.1/multislot/events/'.format(PERSONALIZATION_BASE_URL)
HEADERS = {
    'ocp-apim-subscription-key': RESOURCE_KEY,
    'Content-Type': 'application/json'
}

取得以動作表示的內容選擇

動作代表您要個人化工具從中選取最佳內容項目的內容選擇。 將下列方法新增至指令碼,以代表動作及其功能的組合。

def get_actions():
    return [
        {
            "id": "Red-Polo-Shirt-432",
            "features": [
                {
                    "onSale": "true",
                    "price": 20,
                    "category": "Clothing"
                }
            ]
        },
        {
            "id": "Tennis-Racket-133",
            "features": [
                {
                    "onSale": "false",
                    "price": 70,
                    "category": "Sports"
                }
            ]
        },
        {
            "id": "31-Inch-Monitor-771",
            "features": [
                {
                    "onSale": "true",
                    "price": 200,
                    "category": "Electronics"
                }
            ]
        },
        {
            "id": "XBox-Series X-117",
            "features": [
                {
                    "onSale": "false",
                    "price": 499,
                    "category": "Electronics"
                }
            ]
        }
    ]

取得內容的使用者喜好設定

將下列方法新增至指令碼,以從命令列取得一天時間和使用者所在裝置類型的使用者輸入。 這些會作為關係特性使用。

def get_context_features():
    time_features = ["morning", "afternoon", "evening", "night"]
    time_pref = input("What time of day is it (enter number)? 1. morning 2. afternoon 3. evening 4. night\n")
    try:
        parsed_time = int(time_pref)
        if(parsed_time <=0 or parsed_time > len(time_features)):
            raise IndexError
        time_of_day = time_features[parsed_time-1]
    except (ValueError, IndexError):
        print("Entered value is invalid. Setting feature value to", time_features[0] + ".")
        time_of_day = time_features[0]

    device_features = ['mobile', 'tablet', 'desktop']
    device_pref = input("What type of device is the user on (enter number)? 1. mobile 2. tablet 3. desktop\n")
    try:
        parsed_device = int(device_pref)
        if(parsed_device <=0 or parsed_device > len(device_features)):
            raise IndexError
        device = device_features[parsed_device-1]
    except (ValueError, IndexError):
        print("Entered value is invalid. Setting feature value to", device_features[0]+ ".")
        device = device_features[0]

    return [
        {'time': time_of_day},
        {'device': device}
        ]

取得位置

位置會構成與使用者互動的頁面。 個人化工具會決定要在每一個已定義位置中顯示的動作。 您可以從特定位置排除動作,並以 ExcludeActions 顯示。 BaselineAction 是位置的預設動作,會在不使用個人化工具的情況下顯示。

本快速入門包含簡單的位置功能。 在生產系統中,判斷和評估功能 (部分機器翻譯) 可能不是簡單的事。

def get_slots():
    return [
        {
            "id": "BigHeroPosition",
            "features": [
                {
                    "size": "large",
                    "position": "left",
                }
            ],
            "excludedActions": ["31-Inch-Monitor-771"],
            "baselineAction": "Red-Polo-Shirt-432"
        },
        {
            "id": "SmallSidebar",
            "features": [
                {
                    "size": "small",
                    "position": "right",
                }
            ],
            "excludedActions": ["Tennis-Racket-133"],
            "baselineAction": "XBox-Series X-117"
        }
    ]

發出 HTTP 要求

新增這些函式,將 POST 要求傳送至個人化工具端點,以進行多位置排名和獎勵呼叫。

def send_multi_slot_rank(rank_request):
multi_slot_response = requests.post(MULTI_SLOT_RANK_URL, data=json.dumps(rank_request), headers=HEADERS)
if multi_slot_response.status_code != 201:
    raise Exception(multi_slot_response.text)
return json.loads(multi_slot_response.text)
def send_multi_slot_reward(reward_request, event_id):
    reward_url = '{0}{1}/reward'.format(MULTI_SLOT_REWARD_URL_BASE, event_id)
    requests.post(reward_url, data=json.dumps(reward_request), headers=HEADERS)

取得對於個人化工具決策的意見反應

將下列方法新增至指令碼。 您將透過命令列提示,指出個人化工具是否對每個位置做出適當的決策。

def get_reward_for_slot():
    answer = input('\nIs this correct? (y/n)\n').upper()
    if (answer == 'Y'):
        print('\nGreat! The application will send Personalizer a reward of 1 so it learns from this choice of action for this slot.\n')
        return 1
    elif (answer == 'N'):
        print('\nYou didn\'t like the recommended item.The application will send Personalizer a reward of 0 for this choice of action for this slot.\n')
        return 0
    print('\nEntered choice is invalid. Service assumes that you didn\'t like the recommended item.\n')
    return 0

建立學習迴圈

個人化工具學習迴圈是排名獎勵呼叫的循環。 在本快速入門中,用於個人化內容的每個排名呼叫後面都會接著獎勵呼叫,以告訴個人化工具該服務的成效為何。

下列程式碼會透過命令列進行詢問使用者喜好的循環迴圈,並將該資訊傳送至個人化工具以選取每個位置的最佳動作,然後向客戶顯示選取項目,讓他們從清單中選擇,接著將獎勵分數傳送至個人化工具,指出服務在其選取項目中的成效為何。

run_loop = True

while run_loop:

    eventId = str(uuid.uuid4())
    context = get_context_features()
    actions = get_actions()
    slots = get_slots()

    rank_request = {
        "eventId": eventId,
        "contextFeatures": context,
        "actions": actions,
        "slots": slots,
        "deferActivation": False
      }

    #Rank the actions for each slot
    multi_slot_rank_response = send_multi_slot_rank(rank_request)
    multi_slot_rewards = {"reward": []}

    for i in range(len(multi_slot_rank_response['slots'])):
        print('\nPersonalizer service decided you should display: {0} in slot {1}\n'.format(multi_slot_rank_response['slots'][i]['rewardActionId'], multi_slot_rank_response['slots'][i]['id']))

        slot_reward = {'slotId': multi_slot_rank_response['slots'][i]['id']}
        # User agrees or disagrees with Personalizer decision for slot
        slot_reward['value'] = get_reward_for_slot()
        multi_slot_rewards['reward'].append(slot_reward)

    # Send the rewards for the event
    send_multi_slot_reward(multi_slot_rewards, multi_slot_rank_response['eventId'])

    answer = input('\nPress q to break, any other key to continue:\n').upper()
    if (answer == 'Q'):
        run_loop = False

請仔細查看下列各節中的排名和報酬呼叫。

新增下列方法,取得內容選項取得內容的使用者喜好設定取得位置提出 HTTP 要求取得每個位置的獎勵,再執行程式碼檔案:

  • get_actions
  • get_context_features
  • get_slots
  • send_rank
  • send_reward
  • get_reward_for_dsot

要求最佳動作

為了完成排名要求,程式會詢問使用者的喜好來建立內容選擇。 要求本文包含內容、動作和位置及其各自的功能。 send_multi_slot_rank 方法會接受 rankRequest,並執行多位置排名要求。

本快速入門包含一天時間和使用者裝置的簡單內容功能。 在生產系統中,判斷和評估動作和特性可能不是簡單的事。

eventId = str(uuid.uuid4())
context = get_context_features()
actions = get_actions()
slots = get_slots()

rank_request = {
    "eventId": eventId,
    "contextFeatures": context,
    "actions": actions,
    "slots": slots,
    "deferActivation": False
    }

#Rank the actions for each slot
multi_slot_rank_response = send_multi_slot_rank(rank_request)

傳送獎勵

若要取得獎勵要求的獎勵分數,程式會透過命令列取得使用者針對每個位置的選取項目,將數值 (獎勵分數) 指派給選取項目,然後將唯一的事件識別碼、位置識別碼和每個位置的獎勵分數傳送至 send_multi_slot_reward 方法。 不需要為每個位置定義獎勵。

本快速入門會指派簡單的數字作為獎勵分數,也就是零或 1。 在生產系統中,視您的特定需求而定,判斷要傳送給獎勵呼叫的時機和內容可能不是簡單的事。

multi_slot_rewards = {"reward": []}

for i in range(len(multi_slot_rank_response['slots'])):
    print('\nPersonalizer service decided you should display: {0} in slot {1}\n'.format(multi_slot_rank_response['slots'][i]['rewardActionId'], multi_slot_rank_response['slots'][i]['id']))

    slot_reward = {'slotId': multi_slot_rank_response['slots'][i]['id']}
    # User agrees or disagrees with Personalizer decision for slot
    slot_reward['value'] = get_reward_for_slot()
    multi_slot_rewards['reward'].append(slot_reward)

# Send the rewards for the event
send_multi_slot_reward(multi_slot_rewards, multi_slot_rank_response['eventId'])

執行程式

使用 Python 從您的應用程式目錄執行應用程式。

python sample.py

快速入門程式會詢問幾個問題以收集使用者偏好 (稱為特性),然後提供最佳的動作。

這裡可取得適用於此快速入門的原始程式碼

下一步