將 JavaScript v3 Bot 轉換為技能

適用于: SDK v4

本文將說明如何將 2 個 JavaScript v3 Bot 範例轉換成技能,並建立可存取這些技能的 v4 技能取用者。 若要將 .NET v3 Bot 轉換成技能,請參閱如何將 .NET v3 Bot 轉換成技能。 若要將 JavaScript Bot 從 v3 遷移至 v4,請參閱如何將 JavaScript v3 Bot 遷移至 v4 Bot

Prerequisites

  • Visual Studio Code。
  • Node.js。
  • Azure 訂用帳戶。 如果您沒有 Azure 訂用帳戶,請在開始前建立免費帳戶
  • 若要測試技能,您將需要 bot 的 Bot Framework Emulator 和本機複本:

關於 Bot

在本文中,每個 v3 Bot 都會建立為技能。 其中包含 v4 技能取用者,讓您可以測試轉換為技能的 Bot。

  • v3-skill-bot 會回應其所收到的訊息。 技能會在收到「結束」或「停止」訊息時「完成」 。 要轉換的 Bot 會以最小的 v3 Bot 作為基礎。
  • v3-booking-bot-skill 可讓使用者預訂航班或旅館。 技能會在完成時將收集的資訊傳回給父系。

此外,v4 技能取用者 v4-root-bot 會示範如何取用技能,並讓您進行測試。

若要使用技能取用者來測試技能,所有 3 個 Bot 都必須同時執行。 Bot 可以透過 Bot Framework Emulator 在本機進行測試,並讓每個 Bot 都使用不同的本機連接埠。

為 Bot 建立 Azure 資源

Bot 對 Bot 驗證會要求每個參與的 Bot 都具備有效的應用程式識別碼和密碼。

  1. 如有需要,可為 Bot 建立 Bot 通道註冊。
  2. 記錄每一個 Bot 的應用程式識別碼和密碼。

轉換 v3 bot

將現有 Bot 轉換成技能 Bot 只需要幾個步驟,如以下幾節所述。 如需更深入的資訊,請參閱關於技能

  • 更新 Bot 的 .env 檔案,以設定 Bot 的應用程式識別碼和密碼,並新增「根 Bot 應用程式識別碼」 屬性。
  • 新增宣告驗證。 這會限制技能的存取,僅限使用者或根 Bot 可以存取此技能。 如需有關預設和自訂宣告驗證的詳細資訊,請參閱其他資訊一節。
  • 修改 Bot 的訊息控制器,以處理來自根 Bot 的 endOfConversation 活動。
  • 修改 Bot 程式碼,使其在技能完成時傳回 endOfConversation 活動。
  • 每當技能完成時,如果技能有交談狀態或繼續保有資源,則應該清除其交談狀態及釋出資源。
  • 選擇性地新增資訊清單檔。 由於技能取用者不一定能夠存取技能程式碼,因此請使用技能資訊清單來描述技能可以接收和產生的活動、其輸入和輸出參數,以及技能的端點。 目前的資訊清單結構描述是 skill-manifest-2.0.0.json

轉換回應 Bot

如需已轉換成基本技能的 v3 回應 Bot 範例,請參閱 Skills/v3-skill-bot

  1. 建立簡單的 JavaScript v3 Bot 專案,並匯入必要的模組。

    v3-skill-bot/app.js

    const restify = require('restify');
    const builder = require('botbuilder');
    require('dotenv').config();
    
  2. 將 Bot 設定為在本機連接埠 3979 上執行。

    v3-skill-bot/app.js

    // Setup Restify Server
    const server = restify.createServer();
    server.listen(process.env.port || process.env.PORT || 3979, function () {
       console.log('%s listening to %s', server.name, server.url); 
    });
    
  3. 在設定檔中,新增回應 Bot 的應用程式識別碼和密碼。 此外,使用簡單根 Bot 的應用程式識別碼作為其值來新增 ROOT_BOT_APP_ID 屬性。

    v3-skill-bot/.env

    # Bot Framework Credentials
    
    MICROSOFT_APP_ID=
    MICROSOFT_APP_PASSWORD=
    ROOT_BOT_APP_ID=
    
  4. 為 Bot 建立聊天連接器。 這會使用預設驗證設定。 將 enableSkills 設定為 true,以允許 Bot 作為技能使用。 allowedCallers 是允許使用此技能的 Bot 應用程式識別碼陣列。 如果這個陣列的第一個值是 ' * ',則任何 bot 都可以使用這項技能。

    v3-skill-bot/app.js

    // Create chat connector for communicating with the Bot Framework Service
    const connector = new builder.ChatConnector({
        appId: process.env.MICROSOFT_APP_ID,
        appPassword: process.env.MICROSOFT_APP_PASSWORD,
        enableSkills: true,
        allowedCallers: [process.env.ROOT_BOT_APP_ID]
    });
    
  5. 當使用者選擇結束技能時,更新訊息處理常式以傳送 endOfConversation 活動。

    v3-skill-bot/app.js

    // Create your bot with a function to receive messages from the user
    const bot = new builder.UniversalBot(connector, function (session) {
        switch (session.message.text.toLowerCase()) {
            case 'end':
            case 'stop':
                session.endConversation();
                break;
            default:
                session.send("Echo (JS V3) You said: %s", session.message.text);
                session.send('Say "end" or "stop" and I\'ll end the conversation and back to the parent.');
        }
    }).set('storage', inMemoryStorage); // Register in memory storage
    
  6. 由於此 Bot 不會維護對話狀態,而且不會為對話建立任何資源,因此 Bot 不需要處理從技能取用者接收的任何 endOfConversation 活動。

  7. 針對回應 Bot 使用此資訊清單。 將端點應用程式識別碼設定為 Bot 的應用程式識別碼。

    v3-skill-bot/manifest/v3-skill-bot-manifest.json

    {
        "$schema": "https://schemas.botframework.com/schemas/skills/skill-manifest-2.0.0.json",
        "$id": "v3-skill-bot",
        "name": "Echo Skill bot",
        "version": "1.0",
        "description": "This is a sample echo skill",
        "publisherName": "Microsoft",
        "privacyUrl": "https://echoskillbot.contoso.com/privacy.html",
        "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.",
        "license": "",
        "iconUrl": "https://echoskillbot.contoso.com/icon.png",
        "tags": [
          "sample",
          "echo"
        ],
        "endpoints": [
          {
            "name": "default",
            "protocol": "BotFrameworkV3",
            "description": "Default endpoint for the skill",
            "endpointUrl": "http://echoskillbot.contoso.com/api/messages",
            "msAppId": "00000000-0000-0000-0000-000000000000"
          }
        ]
      }
    

    如需技能-資訊清單結構描述的資訊,請參閱 skill-manifest-2.0.0.json

轉換預約 Bot

如需已轉換成基本技能的 v3 預約 Bot 範例,請參閱 Skills/v3-booking-bot-skill。 在轉換之前,Bot 類似於 v3 core-MultiDialogs 範例。

  1. 匯入必要的模組。

    v3-booking-bot-skill/app.js

    require('dotenv').config();
    
    var builder = require('botbuilder');
    var restify = require('restify');
    const skills = require('botbuilder/skills-validator');
    const { allowedCallersClaimsValidator } = require('./allowedCallersClaimsValidator');
    
  2. 將 Bot 設定為在本機連接埠 3980 上執行。

    v3-booking-bot-skill/app.js

    // Setup Restify Server
    var server = restify.createServer();
    server.listen(process.env.port || process.env.PORT || 3980, function () {
        console.log('%s listening to %s', server.name, server.url);
    });
    
  3. 在設定檔中,新增預約 Bot 的應用程式識別碼和密碼。 此外,使用簡單根 Bot 的應用程式識別碼作為其值來新增 ROOT_BOT_APP_ID 屬性。

    v3-booking-bot-skill/.env

    # Bot Framework Credentials
    
    MICROSOFT_APP_ID=
    MICROSOFT_APP_PASSWORD=
    ROOT_BOT_APP_ID=
    
  4. 為 Bot 建立聊天連接器。 這會使用自訂驗證設定。 將 enableSkills 設定為 true,以允許 Bot 作為技能使用。 authConfiguration 包含要用於驗證和宣告驗證的自訂驗證設定物件。

    v3-booking-bot-skill/app.js

    // Create chat bot and listen to messages
    var connector = new builder.ChatConnector({
        appId: process.env.MICROSOFT_APP_ID,
        appPassword: process.env.MICROSOFT_APP_PASSWORD,
        enableSkills: true,
        authConfiguration: new skills.AuthenticationConfiguration([], allowedCallersClaimsValidator)
    });
    

    v3-booking-bot-skill/allowedCallersClaimsValidator.js

    這會實作自訂宣告驗證,並在驗證失敗時擲回錯誤。

    const skills = require('botbuilder/skills-validator');
    const path = require('path');
    
    // Import required bot configuration.
    const ENV_FILE = path.join(__dirname, '.env');
    require('dotenv').config({ path: ENV_FILE });
    
    // Load the AppIds for the configured callers (we will only allow responses from skills we have configured).
    // process.env.AllowedCallers is the list of parent bot Ids that are allowed to access the skill
    // to add a new parent bot simply go to the .env file and add
    // the parent bot's Microsoft AppId to the list under AllowedCallers, e.g.:
    //  AllowedCallers=195bd793-4319-4a84-a800-386770c058b2,38c74e7a-3d01-4295-8e66-43dd358920f8
    const allowedCallers = [process.env.ROOT_BOT_APP_ID]; // process.env.AllowedCallers ? process.env.AllowedCallers.split(',') : undefined;
    
    /**
     * Sample claims validator that loads an allowed list from configuration if present
     * and checks that requests are coming from allowed parent bots.
     * @param claims An array of Claims decoded from the HTTP request's auth header
     */
    const allowedCallersClaimsValidator = async (claims) => {
        if (!allowedCallers || allowedCallers.length == 0) {
            throw new Error(`DefaultAuthenticationConfiguration allowedCallers must contain at least one element of '*' or valid MicrosoftAppId(s).`);
        }
        if (!claims || claims.length < 1) {
            throw new Error(`DefaultAuthenticationConfiguration.validateClaims.claims parameter must contain at least one element.`);
        }
        // If allowedCallers is undefined we allow all calls
        // If allowedCallers contains '*' we allow all callers
        if (skills.SkillValidation.isSkillClaim(claims)) {
                    
            if(allowedCallers[0] === '*') {
                return;
            }
            // Check that the appId claim in the skill request is in the list of skills configured for this bot.
            const appId = skills.JwtTokenValidation.getAppIdFromClaims(claims);
            if (allowedCallers.includes(appId)) {
                return;
            }
            throw new Error(`Received a request from a bot with an app ID of "${ appId }". To enable requests from this caller, add the app ID to your configuration file.`);
        }
        throw new Error(`DefaultAuthenticationConfiguration.validateClaims called without a Skill claim in claims.`);
    };
    
    module.exports.allowedCallersClaimsValidator = allowedCallersClaimsValidator;
    
  5. 更新訊息處理常式,以在技能結束時傳送 endOfConversation 活動。 請注意,除了傳送 endOfConversation 活動之外,session.endConversation() 也會清除交談狀態。

    v3-booking-bot-skill/app.js

    執行 helper 函式,以設定 endOfConversation 活動的 codevalue 屬性,並清除交談狀態。 如果 Bot 有管理交談的任何其他資源,您也可以在這裡釋出這些資源。

    // Code enum can be found here: https://aka.ms/codeEnum
    function endConversation(session, value = null, code = null) {
        session.send('Ending conversation from the skill...');
        // Send endOfConversation with custom code and values
        const msg = {
            value,
            code,
            type: 'endOfConversation'
        };
        session.send(msg);
        // Call endConversation() to clear state
        session.endConversation();
    }
    

    當使用者完成此程序時,請使用 helper 方法來結束技能,並傳回使用者收集的資料。

    var bot = new builder.UniversalBot(connector, [
        function (session) {
    
        },
        // Dialog has ended
        function(session, result) {
            endConversation(session, result, 'completedSuccessfully');
        }
    ]).set('storage', inMemoryStorage); // Register in memory storage
    

    如果使用者提早結束程序,仍然會叫用 helper 方法。

    bot.recognizer({
        recognize: function (context, done) {
            var intent = { score: 0.0 };
            if (context.message.text) {
                switch (context.message.text.toLowerCase()) {
                    case 'help':
                        intent = { score: 1.0, intent: 'Help' };
                        break;
                    case 'end':
                        intent = { score: 1.0, intent: 'End' };
                        break;
                }
            }
            done(null, intent);
        }
    });
    
    // Add global endConversation() action bound to the 'Goodbye' intent
    bot.endConversationAction('endAction', "Ok... See you later.", { matches: 'End' });
    
  6. 如果技能取用者取消技能,則取用者會傳送 endOfConversation 活動。 處理此活動並釋出與交談相關聯的任何資源。

    v3-booking-bot-skill/app.js

    // Listen for endOfConversation activities from other sources
    bot.on('endOfConversation', (message) => {
        bot.loadSession(message.address, (err, session) => {
            endConversation(session, null, 'completedSuccessfully');
        });
    })
    
  7. 針對預約 Bot 使用此資訊清單。 將端點應用程式識別碼設定為 Bot 的應用程式識別碼。

    v3-booking-bot-skill/manifest/v3-booking-bot-skill-manifest.json

    {
        "$schema": "https://schemas.botframework.com/schemas/skills/skill-manifest-2.0.0.json",
        "$id": "v3-booking-bot-skill",
        "name": "Booking Skill bot",
        "version": "1.0",
        "description": "This is a sample booking skill",
        "publisherName": "Microsoft",
        "privacyUrl": "https://bookingskillbot.contoso.com/privacy.html",
        "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.",
        "license": "",
        "iconUrl": "https://bookingskillbot.contoso.com/icon.png",
        "tags": [
          "sample",
          "echo"
        ],
        "endpoints": [
          {
            "name": "default",
            "protocol": "BotFrameworkV3",
            "description": "Default endpoint for the skill",
            "endpointUrl": "http://bookingskillbot.contoso.com/api/messages",
            "msAppId": "00000000-0000-0000-0000-000000000000"
          }
        ]
      }
    

    如需技能-資訊清單結構描述的資訊,請參閱 skill-manifest-2.0.0.json

建立 v4 根 Bot

簡單的根 Bot 會取用 2 個技能,並可讓您確認轉換步驟是否如預期運作。 此 Bot 會在本機連接埠 3978 上執行。

  1. 在設定檔中,新增根 Bot 的應用程式識別碼和密碼。 針對每個 v3 技能,新增技能的應用程式識別碼。

    v4-root-bot/.env

    MicrosoftAppId=
    MicrosoftAppPassword=
    SkillHostEndpoint=http://localhost:3978/api/skills
    
    SkillSimpleId=v3-skill-bot
    SkillSimpleAppId=
    SkillSimpleEndpoint=http://localhost:3979/api/messages
    
    SkillBookingId=v3-booking-bot-skill
    SkillBookingAppId=
    SkillBookingEndpoint=http://localhost:3980/api/messages
    

測試根目錄 Bot

下載並安裝最新版 Bot Framework Emulator

  1. 在您的機器上啟動這所有三個 Bot。
  2. 使用 Emulator 連線到根 Bot。
  3. 測試技能和技能取用者。

從4.11 版開始,您不需要應用程式識別碼和密碼,即可在模擬器中本機測試技能和技能取用者。 將您的技能部署至 Azure 時,仍需要 Azure 訂用帳戶。

其他資訊

Bot 對 Bot 驗證

根和技能會透過 HTTP 進行通訊。 其架構會使用持有人權杖和 Bot 應用程式識別碼來驗證每個 Bot 的身分識別。 並使用驗證設定物件,來驗證傳入要求的驗證標題。 您必須將宣告驗證程式新增至驗證設定。 宣告會在驗證標題之後進行評估。 您的驗證程式碼應該會擲回錯誤或例外狀況,以拒絕要求。

建立聊天連接器時,請在 settings 參數中包含 allowedCallersauthConfiguration 屬性,以啟用「Bot 對 Bot」驗證。

聊天連接器的預設宣告驗證程式會使用 allowedCallers 屬性。 其值應為 Bot 的應用程式識別碼陣列,表示這些 Bot 可以呼叫技能。 將第一個元素設定為 ' * ',以允許任何 bot 呼叫技能。

若要使用自訂宣告驗證函式,請將 authConfiguration 欄位設定為您的驗證函式。 此函式應接受宣告物件的陣列,並在驗證失敗時擲回錯誤。 預約 Bot 一節的步驟 4 包含宣告驗證程式範例。