Share via


快速入門:個人化工具用戶端連結庫

重要

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

開始使用 Azure AI 個人化工具用戶端連結庫來設定基本學習迴圈。 學習迴圈是一種決策和意見反應系統:應用程式會向服務要求決策排名,然後使用排名最高的選擇,並從結果計算獎勵分數。 它會將獎勵分數傳回給服務。 隨著時間推移,個人化工具會使用 AI 演算法,為任何指定的內容做出更好的決策。 請遵循下列步驟來設定範例應用程式。

範例案例

在本快速入門中,雜貨店電子零售商想要在其網站上向每位客戶顯示相關和個人化產品,以增加收入。 在主頁面上,有一個「精選產品」區段,可向潛在客戶顯示備妥的膳食產品。 電子零售商想要決定如何向正確的客戶顯示正確的產品,以最大化購買的可能性。

個人化工具服務會使用增強式學習,以自動化、可調整且可調整的方式解決此問題。 您將瞭解如何建立動作及其功能、內容功能和獎勵分數。 您將使用個人化工具用戶端連結庫來呼叫 排名和獎勵 API

參考文件 | 連結庫原始程式碼 | 套件 (NuGet) | .NET 程式代碼範例

必要條件

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

模型設定

變更模型更新頻率

在 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 Microsoft.Azure.CognitiveServices.Personalizer --version 1.0.0

提示

如果您使用 Visual Studio IDE,用戶端連結庫會以可下載的 NuGet 套件的形式提供。

程序代碼區塊 1:產生範例數據

個人化工具是要在接收和解譯實時數據的應用程式上執行。 在本快速入門中,您將使用範例程式代碼在雜貨店網站上產生虛構的客戶動作。 下列程式代碼區塊會定義三個主要方法:GetActionsGetContextGetRewardScore

  • GetActions 會傳回雜貨店網站需要排名的選項清單。 在此範例中,動作是膳食產品。 每個動作選擇都有可能會影響使用者行為的詳細數據(功能)。 動作會作為排名 API 的輸入使用

  • GetContext 會傳回仿真的客戶流覽。 它會選取隨機化的詳細數據(內容功能),例如客戶存在的詳細數據,以及進行訪問的一天中的時間。 一般而言,內容代表應用程式、系統、環境或使用者的目前狀態。 內容物件會當做排名 API 的輸入使用。

    本快速入門中的內容功能很簡單。 不過,在實際的生產系統中,設計 您的功能評估其有效性 非常重要。 如需指引,請參閱鏈接的檔。

  • GetRewardScore 會傳回零和一個之間的分數,代表客戶互動的成功。 它會使用簡單的邏輯來判斷不同內容如何回應不同的動作選擇。 例如,特定使用者一律會為素食和素食產品提供 1.0,而其他產品則為 0.0。 在真實案例中,個人化工具會從排名和獎勵 API 呼叫中傳送的數據學習使用者喜好設定。 您不會在範例程式代碼中明確定義這些。

    在實際生產系統中, 獎勵分數 的設計應符合您的商務目標和 KPI。 判斷如何計算獎勵計量可能需要一些實驗。

    在下列程式代碼中,使用者對動作的喜好設定和回應會硬式編碼為一系列的條件語句,而且說明文字會包含在程序代碼中,以供示範之用。

  1. 尋找您的金鑰和端點。

    重要

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

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

  2. 在文本編輯器或 IDE 中開啟 Program.cs ,並貼上下列程式代碼。

    using Microsoft.Azure.CognitiveServices.Personalizer;
    using Microsoft.Azure.CognitiveServices.Personalizer.Models;
    
    class Program
    {
        private static readonly string ApiKey = "REPLACE_WITH_YOUR_PERSONALIZER_KEY";
        private static readonly string ServiceEndpoint = "REPLACE_WITH_YOUR_ENDPOINT_URL";
    
        static PersonalizerClient InitializePersonalizerClient(string url)
        {
            PersonalizerClient client = new PersonalizerClient(
                new ApiKeyServiceClientCredentials(ApiKey))
            { Endpoint = url };
    
            return client;
        }
    
        static Dictionary<string, ActionFeatures> actions = new Dictionary<string, ActionFeatures>
        {
        {"pasta", new ActionFeatures(
                        new BrandInfo(company: "pasta_inc"),
                        new ItemAttributes(
                            quantity: 1,
                            category: "Italian",
                            price: 12),
                        new DietaryAttributes(
                            vegan: false,
                            lowCarb: false,
                            highProtein: false,
                            vegetarian: false,
                            lowFat: true,
                            lowSodium: true))},
        {"bbq", new ActionFeatures(
                        new BrandInfo(company: "ambisco"),
                        new ItemAttributes(
                            quantity: 2,
                            category: "bbq",
                            price: 20),
                        new DietaryAttributes(
                            vegan: false,
                            lowCarb: true,
                            highProtein: true,
                            vegetarian: false,
                            lowFat: false,
                            lowSodium: false))},
        {"bao", new ActionFeatures(
                        new BrandInfo(company: "bao_and_co"),
                        new ItemAttributes(
                            quantity: 4,
                            category: "Chinese",
                            price: 8),
                        new DietaryAttributes(
                            vegan: false,
                            lowCarb: true,
                            highProtein: true,
                            vegetarian: false,
                            lowFat: true,
                            lowSodium: false))},
        {"hummus", new ActionFeatures(
                        new BrandInfo(company: "garbanzo_inc"),
                        new ItemAttributes(
                            quantity: 1,
                            category: "Breakfast",
                            price: 5),
                        new DietaryAttributes(
                            vegan: true,
                            lowCarb: false,
                            highProtein: true,
                            vegetarian: true,
                            lowFat: false,
                            lowSodium: false))},
        {"veg_platter", new ActionFeatures(
                        new BrandInfo(company: "farm_fresh"),
                        new ItemAttributes(
                            quantity: 1,
                            category: "produce",
                            price: 7),
                        new DietaryAttributes(
                            vegan: true,
                            lowCarb: true,
                            highProtein: false,
                            vegetarian: true,
                            lowFat: true,
                            lowSodium: true ))},
    };
    
        static IList<RankableAction> GetActions()
        {
            IList<RankableAction> rankableActions = new List<RankableAction>();
            foreach (var action in actions)
            {
                rankableActions.Add(new RankableAction
                {
                    Id = action.Key,
                    Features = new List<object>() { action.Value }
                });
            }
    
            return rankableActions;
        }
    
        public class BrandInfo
        {
            public string Company { get; set; }
            public BrandInfo(string company)
            {
                Company = company;
            }
        }
    
        public class ItemAttributes
        {
            public int Quantity { get; set; }
            public string Category { get; set; }
            public double Price { get; set; }
            public ItemAttributes(int quantity, string category, double price)
            {
                Quantity = quantity;
                Category = category;
                Price = price;
            }
        }
    
        public class DietaryAttributes
        {
            public bool Vegan { get; set; }
            public bool LowCarb { get; set; }
            public bool HighProtein { get; set; }
            public bool Vegetarian { get; set; }
            public bool LowFat { get; set; }
            public bool LowSodium { get; set; }
            public DietaryAttributes(bool vegan, bool lowCarb, bool highProtein, bool vegetarian, bool lowFat, bool lowSodium)
            {
                Vegan = vegan;
                LowCarb = lowCarb;
                HighProtein = highProtein;
                Vegetarian = vegetarian;
                LowFat = lowFat;
                LowSodium = lowSodium;
    
            }
        }
    
        public class ActionFeatures
        {
            public BrandInfo BrandInfo { get; set; }
            public ItemAttributes ItemAttributes { get; set; }
            public DietaryAttributes DietaryAttributes { get; set; }
            public ActionFeatures(BrandInfo brandInfo, ItemAttributes itemAttributes, DietaryAttributes dietaryAttributes)
            {
                BrandInfo = brandInfo;
                ItemAttributes = itemAttributes;
                DietaryAttributes = dietaryAttributes;
            }
        }
    
        public static Context GetContext()
        {
            return new Context(
                    user: GetRandomUser(),
                    timeOfDay: GetRandomTimeOfDay(),
                    location: GetRandomLocation(),
                    appType: GetRandomAppType());
        }
    
        static string[] timesOfDay = new string[] { "morning", "afternoon", "evening" };
    
        static string[] locations = new string[] { "west", "east", "midwest" };
    
        static string[] appTypes = new string[] { "edge", "safari", "edge_mobile", "mobile_app" };
    
        static IList<UserProfile> users = new List<UserProfile>
    {
        new UserProfile(
            name: "Bill",
            dietaryPreferences: new Dictionary<string, bool> { { "low_carb", true } },
            avgOrderPrice: "0-20"),
        new UserProfile(
            name: "Satya",
            dietaryPreferences: new Dictionary<string, bool> { { "low_sodium", true} },
            avgOrderPrice: "201+"),
        new UserProfile(
            name: "Amy",
            dietaryPreferences: new Dictionary<string, bool> { { "vegan", true }, { "vegetarian", true } },
            avgOrderPrice: "21-50")
    };
    
        static string GetRandomTimeOfDay()
        {
            var random = new Random();
            var timeOfDayIndex = random.Next(timesOfDay.Length);
            Console.WriteLine($"TimeOfDay: {timesOfDay[timeOfDayIndex]}");
            return timesOfDay[timeOfDayIndex];
        }
    
        static string GetRandomLocation()
        {
            var random = new Random();
            var locationIndex = random.Next(locations.Length);
            Console.WriteLine($"Location: {locations[locationIndex]}");
            return locations[locationIndex];
        }
    
        static string GetRandomAppType()
        {
            var random = new Random();
            var appIndex = random.Next(appTypes.Length);
            Console.WriteLine($"AppType: {appTypes[appIndex]}");
            return appTypes[appIndex];
        }
    
        static UserProfile GetRandomUser()
        {
            var random = new Random();
            var userIndex = random.Next(users.Count);
            Console.WriteLine($"\nUser: {users[userIndex].Name}");
            return users[userIndex];
        }
    
        public class UserProfile
        {
            // Mark name as non serializable so that it is not part of the context features
            [NonSerialized()]
            public string Name;
            public Dictionary<string, bool> DietaryPreferences { get; set; }
            public string AvgOrderPrice { get; set; }
    
            public UserProfile(string name, Dictionary<string, bool> dietaryPreferences, string avgOrderPrice)
            {
                Name = name;
                DietaryPreferences = dietaryPreferences;
                AvgOrderPrice = avgOrderPrice;
            }
        }
    
        public class Context
        {
            public UserProfile User { get; set; }
            public string TimeOfDay { get; set; }
            public string Location { get; set; }
            public string AppType { get; set; }
    
            public Context(UserProfile user, string timeOfDay, string location, string appType)
            {
                User = user;
                TimeOfDay = timeOfDay;
                Location = location;
                AppType = appType;
            }
        }
        public static float GetRewardScore(Context context, string actionId)
        {
            float rewardScore = 0.0f;
            string userName = context.User.Name;
            ActionFeatures actionFeatures = actions[actionId];
            if (userName.Equals("Bill"))
            {
                if (actionFeatures.ItemAttributes.Price < 10 && !context.Location.Equals("midwest"))
                {
                    rewardScore = 1.0f;
                    Console.WriteLine($"\nBill likes to be economical when he's not in the midwest visiting his friend Warren. He bought {actionId} because it was below a price of $10.");
                }
                else if (actionFeatures.DietaryAttributes.LowCarb && context.Location.Equals("midwest"))
                {
                    rewardScore = 1.0f;
                    Console.WriteLine($"\nBill is visiting his friend Warren in the midwest. There he's willing to spend more on food as long as it's low carb, so Bill bought {actionId}.");
                }
                else if (actionFeatures.ItemAttributes.Price >= 10 && !context.Location.Equals("midwest"))
                {
                    rewardScore = 1.0f;
                    Console.WriteLine($"\nBill didn't buy {actionId} because the price was too high when not visting his friend Warren in the midwest.");
                }
                else if (actionFeatures.DietaryAttributes.LowCarb && context.Location.Equals("midwest"))
                {
                    rewardScore = 1.0f;
                    Console.WriteLine($"\nBill didn't buy {actionId} because it's not low-carb, and he's in the midwest visitng his friend Warren.");
                }
            }
            else if (userName.Equals("Satya"))
            {
                if (actionFeatures.DietaryAttributes.LowSodium)
                {
                    rewardScore = 1.0f;
                    Console.WriteLine($"\nSatya is health conscious, so he bought {actionId} since it's low in sodium.");
                }
                else
                {
                    Console.WriteLine($"\nSatya did not buy {actionId} because it's not low sodium.");
                }
            }
            else if (userName.Equals("Amy"))
            {
                if (actionFeatures.DietaryAttributes.Vegan || actionFeatures.DietaryAttributes.Vegetarian)
                {
                    rewardScore = 1.0f;
                    Console.WriteLine($"\nAmy likes to eat plant-based foods, so she bought {actionId} because it's vegan or vegetarian friendly.");
                }
                else
                {
                    Console.WriteLine($"\nAmy did not buy {actionId} because it's not vegan or vegetarian.");
                }
            }
            return rewardScore;
        }
        // ...
    
  3. 在指示的位置中貼上您的金鑰和端點。 您的端點格式為 https://<your_resource_name>.cognitiveservices.azure.com/

    重要

    完成時,請記得從程式碼中移除金鑰,且不要公開張貼金鑰。 在生產環境中,請使用安全的方式來儲存和存取您的認證,例如 Azure Key Vault。 如需詳細資訊,請參閱 Azure AI 服務安全性一文。

程序代碼區塊 2:逐一查看學習迴圈

下一個程式代碼區塊會 定義main 方法,並關閉腳本。 它會執行學習迴圈反覆專案,其中會產生內容(包括客戶)、使用排名 API 要求該內容中的動作排名、計算獎勵分數,並使用 Reward API 將分數傳回個人化工具服務。 它會在每個步驟將相關信息列印至主控台。

在此範例中,會進行每個 Rank 呼叫,以判斷應該顯示在[精選產品] 區段中的產品。 接著,Reward 通話會指出使用者是否已購買精選產品。 獎勵會透過一般 EventId 值與其決策相關聯。

    static void Main(string[] args)
    {
        int iteration = 1;
        bool runLoop = true;

        // Get the actions list to choose from personalizer with their features.
        IList<RankableAction> actions = GetActions();

        // Initialize Personalizer client.
        PersonalizerClient client = InitializePersonalizerClient(ServiceEndpoint);

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

            // Get context information.
            Context context = GetContext();

            // Create current context from user specified data.
            IList<object> currentContext = new List<object>() {
            context
        };

            // Generate an ID to associate with the request.
            string eventId = Guid.NewGuid().ToString();

            // Rank the actions
            var request = new RankRequest(actions: actions, contextFeatures: currentContext, eventId: eventId);
            RankResponse response = client.Rank(request);

            Console.WriteLine($"\nPersonalizer service thinks {context.User.Name} would like to have: {response.RewardActionId}.");

            float reward = GetRewardScore(context, response.RewardActionId);

            // Send the reward for the action based on user response.
            client.Reward(response.EventId, new RewardRequest(reward));

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

        } while (runLoop);
    }

        private static string GetKey()
    {
        return Console.ReadKey().Key.ToString().Last().ToString().ToUpper();
    }

}

執行程式

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

dotnet run

在第一次反覆運算中,個人化工具會建議隨機動作,因為它尚未完成任何定型。 您可以選擇性地執行更多反覆專案。 大約10分鐘之後,服務會開始顯示其建議的改善。

快速入門計劃會詢問幾個問題來收集使用者喜好設定,稱為功能,然後提供最上層的動作。

產生許多事件進行分析(選擇性)

您可以輕鬆地從本快速入門案例產生 5,000 個事件,這足以使用學徒模式和在線模式、執行離線評估,以及建立功能評估。 將上述主要方法取代為:

    static void Main(string[] args)
    {
    int iteration = 1;
    int runLoop = 0;

    // Get the actions list to choose from personalizer with their features.
    IList<RankableAction> actions = GetActions();

    // Initialize Personalizer client.
    PersonalizerClient client = InitializePersonalizerClient(ServiceEndpoint);

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

        // Get context information.
        Context context = GetContext();

        // Create current context from user specified data.
        IList<object> currentContext = new List<object>() {
            context
        };

        // Generate an ID to associate with the request.
        string eventId = Guid.NewGuid().ToString();

        // Rank the actions
        var request = new RankRequest(actions: actions, contextFeatures: currentContext, eventId: eventId);
        RankResponse response = client.Rank(request);

        Console.WriteLine($"\nPersonalizer service thinks {context.User.Name} would like to have: {response.RewardActionId}.");

        float reward = GetRewardScore(context, response.RewardActionId);

        // Send the reward for the action based on user response.
        client.Reward(response.EventId, new RewardRequest(reward));

        runLoop = runLoop + 1;

    } while (runLoop < 1000);
}

本快速入門的原始程式碼可在 GitHub取得。

參考文件 | 套件 (npm) | 快速入門程式代碼範例

必要條件

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

模型設定

變更模型更新頻率

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

變更模型更新頻率

變更獎勵等候時間

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

變更獎勵等候時間

建立新的 Node.js 應用程式

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

mkdir myapp && cd myapp

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

npm init -y

在慣用的編輯器或 IDE 中建立名為 personalizer-quickstart.js 的新Node.js腳本,併為資源的端點和訂用帳戶密鑰建立變數。

安裝用戶端程式庫

使用下列命令安裝適用於 Node.js的個人化工具用戶端連結庫:

npm install @azure/cognitiveservices-personalizer --save

安裝本快速入門的其餘 npm 套件:

npm install @azure/ms-rest-azure-js @azure/ms-rest-js readline-sync uuid --save

程序代碼區塊 1:產生範例數據

個人化工具是要在接收和解譯實時數據的應用程式上執行。 在本快速入門中,您將使用範例程式代碼在雜貨店網站上產生虛構的客戶動作。 下列程式代碼區塊會定義三個主要方法:getActionsList、getContextFeaturesListgetReward

  • getActionsList 會傳回雜貨店網站需要排名的選項清單。 在此範例中,動作是膳食產品。 每個動作選擇都有可能會影響使用者行為的詳細數據(功能)。 動作會作為排名 API 的輸入使用

  • getContextFeaturesList 會傳回仿真的客戶流覽。 它會選取隨機化的詳細數據(內容功能),例如客戶存在的詳細數據,以及進行訪問的一天中的時間。 一般而言,內容代表應用程式、系統、環境或使用者的目前狀態。 內容物件會當做排名 API 的輸入使用。

    本快速入門中的內容功能很簡單。 不過,在實際的生產系統中,設計 您的功能評估其有效性 非常重要。 如需指引,請參閱鏈接的檔。

  • getReward 會提示用戶將服務的建議評分為成功或失敗。 它會傳回零到一個之間的分數,代表客戶互動的成功。 在真實案例中,個人化工具會從即時客戶互動中學習使用者喜好設定。

    在實際生產系統中, 獎勵分數 的設計應符合您的商務目標和 KPI。 判斷如何計算獎勵計量可能需要一些實驗。

在文本編輯器或 IDE 中開啟 personalizer-quickstart.js ,然後貼上下列程式代碼。

const uuidv1 = require('uuid/v1');
const Personalizer = require('@azure/cognitiveservices-personalizer');
const CognitiveServicesCredentials = require('@azure/ms-rest-azure-js').CognitiveServicesCredentials;
const readline = require('readline-sync');

function getReward() {
  const answer = readline.question("\nIs this correct (y/n)\n");
  if (answer.toLowerCase() === 'y') {
    console.log("\nGreat| Enjoy your food.");
    return 1;
  }
  console.log("\nYou didn't like the recommended food choice.");
  return 0;
}

function getContextFeaturesList() {
  const timeOfDayFeatures = ['morning', 'afternoon', 'evening', 'night'];
  const tasteFeatures = ['salty', 'sweet'];

  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 food would you prefer (enter number)? 1. salty 2. sweet\n");
  selection = parseInt(answer);
  const taste = selection >= 1 && selection <= 2 ? tasteFeatures[selection - 1] : tasteFeatures[0];

  console.log("Selected features:\n");
  console.log("Time of day: " + timeOfDay + "\n");
  console.log("Taste: " + taste + "\n");

  return [
    {
      "time": timeOfDay
    },
    {
      "taste": taste
    }
  ];
}

function getExcludedActionsList() {
  return [
    "juice"
  ];
}

function getActionsList() {
  return [
    {
      "id": "pasta",
      "features": [
        {
          "taste": "salty",
          "spiceLevel": "medium"
        },
        {
          "nutritionLevel": 5,
          "cuisine": "italian"
        }
      ]
    },
    {
      "id": "ice cream",
      "features": [
        {
          "taste": "sweet",
          "spiceLevel": "none"
        },
        {
          "nutritionalLevel": 2
        }
      ]
    },
    {
      "id": "juice",
      "features": [
        {
          "taste": "sweet",
          "spiceLevel": "none"
        },
        {
          "nutritionLevel": 5
        },
        {
          "drink": true
        }
      ]
    },
    {
      "id": "salad",
      "features": [
        {
          "taste": "salty",
          "spiceLevel": "low"
        },
        {
          "nutritionLevel": 8
        }
      ]
    }
  ];
}

程序代碼區塊 2:逐一查看學習迴圈

下一個程式代碼區塊會 定義main 方法,並關閉腳本。 它會執行學習迴圈反覆專案,其中會詢問使用者在命令行上的喜好設定,並將該資訊傳送給個人化工具,以選取最佳動作。 它會向使用者呈現選取的動作,該使用者會使用命令行進行選擇。 然後,它會將獎勵分數傳送給個人化工具服務,以指出服務在其選取範圍中的表現。

個人化工具學習迴圈是排名獎勵呼叫的迴圈。 在本快速入門中,每個排名呼叫,為了個人化內容,接著是獎勵呼叫,告知個人化工具服務的執行程度。

  1. 將下列程式代碼新增至 personalizer-quickstart.js

  2. 尋找您的金鑰和端點。 您的端點格式為 https://<your_resource_name>.cognitiveservices.azure.com/

    重要

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

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

  3. 在指示的位置中貼上您的金鑰和端點。

    重要

    完成時,請記得從程式碼中移除金鑰,且不要公開張貼金鑰。 在生產環境中,請使用安全的方式來儲存和存取您的認證,例如 Azure Key Vault。 如需安全性的詳細資訊,請參閱 Azure AI 服務 安全性 一文。

    async function main() {
    
        // The key specific to your personalization service instance; e.g. "0123456789abcdef0123456789ABCDEF"
        const serviceKey = "PASTE_YOUR_PERSONALIZER_SUBSCRIPTION_KEY_HERE";
      
        // The endpoint specific to your personalization service instance; 
        // e.g. https://<your-resource-name>.cognitiveservices.azure.com
        const baseUri = "PASTE_YOUR_PERSONALIZER_ENDPOINT_HERE";
      
        const credentials = new CognitiveServicesCredentials(serviceKey);
      
        // Initialize Personalization client.
        const personalizerClient = new Personalizer.PersonalizerClient(credentials, baseUri);
      
      
        let runLoop = true;
      
        do {
      
          let rankRequest = {}
      
          // Generate an ID to associate with the request.
          rankRequest.eventId = uuidv1();
      
          // Get context information from the user.
          rankRequest.contextFeatures = getContextFeaturesList();
      
          // Get the actions list to choose from personalization with their features.
          rankRequest.actions = getActionsList();
      
          // Exclude an action for personalization ranking. This action will be held at its current position.
          rankRequest.excludedActions = getExcludedActionsList();
      
          rankRequest.deferActivation = false;
      
          // Rank the actions
          const rankResponse = await personalizerClient.rank(rankRequest);
      
          console.log("\nPersonalization service thinks you would like to have:\n")
          console.log(rankResponse.rewardActionId);
      
          // Display top choice to user, user agrees or disagrees with top choice
          const reward = getReward();
      
          console.log("\nPersonalization service ranked the actions with the probabilities as below:\n");
          for (let i = 0; i < rankResponse.ranking.length; i++) {
            console.log(JSON.stringify(rankResponse.ranking[i]) + "\n");
          }
      
          // Send the reward for the action based on user response.
      
          const rewardRequest = {
            value: reward
          }
      
          await personalizerClient.events.reward(rankRequest.eventId, rewardRequest);
      
          runLoop = continueLoop();
      
        } while (runLoop);
      }
      
      function continueLoop() {
        const answer = readline.question("\nPress q to break, any other key to continue.\n")
        if (answer.toLowerCase() === 'q') {
          return false;
        }
        return true;
      }
    
    main()
    .then(result => console.log("done"))
    .catch(err=> console.log(err));
    

執行程式

使用應用程式目錄中的 Node.js 命令執行應用程式。

node personalizer-quickstart.js

逐一查看幾個學習迴圈。 大約10分鐘之後,服務會開始顯示其建議的改善。

本快速入門的原始程式碼可在 GitHub取得。

參考文件 | 連結庫原始程式碼套件 (pypi) | 快速入門程式代碼範例 |

必要條件

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

模型設定

變更模型更新頻率

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

變更模型更新頻率

變更獎勵等候時間

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

變更獎勵等候時間

建立新的 Python 應用程式

建立名為 personalizer-quickstart.py 的新 Python 檔案。

安裝用戶端程式庫

使用 pip 安裝個人化工具用戶端連結庫:

pip install azure-cognitiveservices-personalizer

程序代碼區塊 1:產生範例數據

個人化工具是要在接收和解譯實時數據的應用程式上執行。 基於本快速入門的目的,您將使用範例程式代碼在雜貨店網站上產生虛構的客戶動作。 下列程式代碼區塊會定義三個主要函式: get_actionsget_contextget_reward_score

  • get_actions會傳回雜貨店網站需要排名的選項清單。 在此範例中,動作是膳食產品。 每個動作選擇都有可能會影響使用者行為的詳細數據(功能)。 動作會作為排名 API 的輸入使用

  • get_context傳回仿真的客戶流覽。 它會選取隨機化的詳細數據(內容功能),例如客戶存在的詳細數據,以及進行訪問的一天中的時間。 一般而言,內容代表應用程式、系統、環境或使用者的目前狀態。 內容物件會當做排名 API 的輸入使用。

    本快速入門中的內容功能很簡單。 不過,在實際的生產系統中,設計 您的功能評估其有效性 非常重要。 如需指引,請參閱鏈接的檔。

  • get_reward_score傳回零和一個之間的分數,代表客戶互動的成功。 它會使用簡單的邏輯來判斷不同內容會如何回應不同的動作選擇。 例如,特定使用者一律會為素食和素食產品提供 1.0,而其他產品則為 0.0。 在真實案例中,個人化工具會從排名和獎勵 API 呼叫中傳送的數據學習使用者喜好設定。 您不會在範例程式代碼中明確定義這些。

    在實際生產系統中, 獎勵分數 的設計應符合您的商務目標和 KPI。 判斷如何計算獎勵計量可能需要一些實驗。

    在下列程式代碼中,使用者對動作的喜好設定和回應會硬式編碼為一系列的條件語句,而且說明文字會包含在程序代碼中,以供示範之用。

請遵循下列步驟來設定個人化工具腳本。

  1. 尋找您的金鑰和端點。

    重要

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

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

  2. 在文本編輯器或 IDE 中開啟 personalizer-quickstart.py ,然後貼上下列程式代碼。

  3. 在指示的位置中貼上您的金鑰和端點。 您的端點格式為 https://<your_resource_name>.cognitiveservices.azure.com/

    重要

    完成時,請記得從程式碼中移除金鑰,且不要公開張貼金鑰。 針對生產環境,請使用安全方法來儲存和存取您的認證,例如 Azure 金鑰保存庫。 如需詳細資訊,請參閱 Azure AI 服務 安全性

from azure.cognitiveservices.personalizer import PersonalizerClient
from azure.cognitiveservices.personalizer.models import RankableAction, RewardRequest, RankRequest
from msrest.authentication import CognitiveServicesCredentials

import datetime, json, os, time, uuid, random

key = "paste_your_personalizer_key_here"
endpoint = "paste_your_personalizer_endpoint_here"

# Instantiate a Personalizer client
client = PersonalizerClient(endpoint, CognitiveServicesCredentials(key))

actions_and_features = {
    'pasta': {
        'brand_info': {
            'company':'pasta_inc'
        }, 
        'attributes': {
            'qty':1, 'cuisine':'italian',
            'price':12
        },
        'dietary_attributes': {
            'vegan': False,
            'low_carb': False,
            'high_protein': False,
            'vegetarian': False,
            'low_fat': True,
            'low_sodium': True
        }
    },
    'bbq': {
        'brand_info' : {
            'company': 'ambisco'
        },
        'attributes': {
            'qty': 2,
            'category': 'bbq',
            'price': 20
        }, 
        'dietary_attributes': {
            'vegan': False,
            'low_carb': True,
            'high_protein': True,
            'vegetarian': False,
            'low_fat': False,
            'low_sodium': False
        }
    },
    'bao': {
        'brand_info': {
            'company': 'bao_and_co'
        },
        'attributes': {
            'qty': 4,
            'category': 'chinese',
            'price': 8
        }, 
        'dietary_attributes': {
            'vegan': False,
            'low_carb': True,
            'high_protein': True,
            'vegetarian': False,
            'low_fat': True,
            'low_sodium': False
        }
    },
    'hummus': {
        'brand_info' : { 
            'company': 'garbanzo_inc'
        },
        'attributes' : {
            'qty': 1,
            'category': 'breakfast',
            'price': 5
        }, 
        'dietary_attributes': {
            'vegan': True, 
            'low_carb': False,
            'high_protein': True,
            'vegetarian': True,
            'low_fat': False, 
            'low_sodium': False
        }
    },
    'veg_platter': {
        'brand_info': {
            'company': 'farm_fresh'
        }, 
        'attributes': {
            'qty': 1,
            'category': 'produce', 
            'price': 7
        },
        'dietary_attributes': {
            'vegan': True,
            'low_carb': True,
            'high_protein': False,
            'vegetarian': True,
            'low_fat': True,
            'low_sodium': True
        }
    }
}

def get_actions():
    res = []
    for action_id, feat in actions_and_features.items():
        action = RankableAction(id=action_id, features=[feat])
        res.append(action)
    return res

user_profiles = {
    'Bill': {
        'dietary_preferences': 'low_carb', 
        'avg_order_price': '0-20',
        'browser_type': 'edge'
    },
    'Satya': {
        'dietary_preferences': 'low_sodium',
        'avg_order_price': '201+',
        'browser_type': 'safari'
    },
    'Amy': {
        'dietary_preferences': {
            'vegan', 'vegetarian'
        },
        'avg_order_price': '21-50',
        'browser_type': 'edge'},
    }

def get_context(user):
    location_context = {'location': random.choice(['west', 'east', 'midwest'])}
    time_of_day = {'time_of_day': random.choice(['morning', 'afternoon', 'evening'])}
    app_type = {'application_type': random.choice(['edge', 'safari', 'edge_mobile', 'mobile_app'])}
    res = [user_profiles[user], location_context, time_of_day, app_type]
    return res

def get_random_users(k = 5):
    return random.choices(list(user_profiles.keys()), k=k)


def get_reward_score(user, actionid, context):
    reward_score = 0.0
    action = actions_and_features[actionid]
    
    if user == 'Bill':
        if action['attributes']['price'] < 10 and (context[1]['location'] !=  "midwest"):
            reward_score = 1.0
            print("Bill likes to be economical when he's not in the midwest visiting his friend Warren. He bought", actionid, "because it was below a price of $10.")
        elif (action['dietary_attributes']['low_carb'] == True) and (context[1]['location'] ==  "midwest"):
            reward_score = 1.0
            print("Bill is visiting his friend Warren in the midwest. There he's willing to spend more on food as long as it's low carb, so Bill bought" + actionid + ".")
            
        elif (action['attributes']['price'] >= 10) and (context[1]['location'] != "midwest"):
            print("Bill didn't buy", actionid, "because the price was too high when not visting his friend Warren in the midwest.")
            
        elif (action['dietary_attributes']['low_carb'] == False) and (context[1]['location'] ==  "midwest"):
            print("Bill didn't buy", actionid, "because it's not low-carb, and he's in the midwest visitng his friend Warren.")
             
    elif user == 'Satya':
        if action['dietary_attributes']['low_sodium'] == True:
            reward_score = 1.0
            print("Satya is health conscious, so he bought", actionid,"since it's low in sodium.")
        else:
            print("Satya did not buy", actionid, "because it's not low sodium.")   
            
    elif user == 'Amy':
        if (action['dietary_attributes']['vegan'] == True) or (action['dietary_attributes']['vegetarian'] == True):
            reward_score = 1.0
            print("Amy likes to eat plant-based foods, so she bought", actionid, "because it's vegan or vegetarian friendly.")       
        else:
            print("Amy did not buy", actionid, "because it's not vegan or vegetarian.")
                
    return reward_score
    # ...

程序代碼區塊 2:逐一查看學習迴圈

下一個程式代碼區塊會 定義run_personalizer_cycle函式 ,並在簡單的使用者意見反應迴圈中呼叫它。 它會執行學習迴圈反覆專案,其中會產生內容(包括客戶)、使用排名 API 要求該內容中的動作排名、計算獎勵分數,並使用 Reward API 將分數傳回個人化工具服務。 它會在每個步驟將相關信息列印至主控台。

在此範例中,會進行每個 Rank 呼叫,以判斷應該顯示在[精選產品] 區段中的產品。 接著,Reward 通話會指出使用者是否已購買精選產品。 獎勵會透過一般 EventId 值與其決策相關聯。

def run_personalizer_cycle():
    actions = get_actions()
    user_list = get_random_users()
    for user in user_list:
        print("------------")
        print("User:", user, "\n")
        context = get_context(user)
        print("Context:", context, "\n")
        
        rank_request = RankRequest(actions=actions, context_features=context)
        response = client.rank(rank_request=rank_request)
        print("Rank API response:", response, "\n")
        
        eventid = response.event_id
        actionid = response.reward_action_id
        print("Personalizer recommended action", actionid, "and it was shown as the featured product.\n")
        
        reward_score = get_reward_score(user, actionid, context)
        client.events.reward(event_id=eventid, value=reward_score)     
        print("\nA reward score of", reward_score , "was sent to Personalizer.")
        print("------------\n")

continue_loop = True
while continue_loop:
    run_personalizer_cycle()
    
    br = input("Press Q to exit, or any other key to run another loop: ")
    if(br.lower()=='q'):
        continue_loop = False

執行程式

在 Python 檔案中包含上述所有程式代碼之後,您就可以從應用程式目錄執行它。

python personalizer-quickstart.py

在第一次反覆運算中,個人化工具會建議隨機動作,因為它尚未完成任何定型。 您可以選擇性地執行更多反覆專案。 大約10分鐘之後,服務會開始顯示其建議的改善。

快速入門計劃會詢問幾個問題來收集使用者喜好設定,稱為功能,然後提供最上層的動作。

產生許多事件進行分析(選擇性)

您可以輕鬆地從本快速入門案例產生5,000個事件,這足以使用學徒模式、在線模式、執行脫機評估,以及建立功能評估來取得經驗。 while以下列程式代碼取代上述程式代碼區塊中的迴圈。

for i in range(0,1000):
    run_personalizer_cycle()

本快速入門的原始程式碼可在 GitHub取得。

下載定型的模型

如果您想要從上述範例下載已定型 5,000 個事件的個人化工具模型,請瀏覽 個人化工具範例存放庫 並下載 Personalizer_QuickStart_Model.zip 檔案。 然後移至 Azure 入口網站 中的個人化工具資源,移至 [設定] 頁面和 [匯入/匯出] 索引卷標,然後匯入檔案。

清除資源

若要清除 Azure AI 服務訂用帳戶,您可以刪除資源或刪除資源群組,這會刪除任何相關聯的資源。

下一步