使用 API 建置自訂用戶端

中的自動學習功能 watsonx Assistant
自 2025 年 6 月 16 日起,watsonx Assistant。 此日期之後,自動學習設定會從作業全局設定頁移除,所有自動學習功能也會停用。

如果沒有任何內建整合符合您的需求,您可以透過開發與使用者互動並與 IBM® watsonx™ Assistant 服務進行通訊的自訂用戶端應用程式來部署助理。

Watson SDK 可協助您撰寫與 watsonx Assistant互動的程式碼。 有關 SDK 的更多信息,請參閱 IBM Watson API

設定助理

我們在中建立的範例應用程式會實作數個簡式函數,以說明用戶端應用程式如何與 watsonx Assistant互動。 應用程式碼會收集輸入並將其傳送至助理,該助理會將應用程式顯示的回應傳送給使用者。

若要自行嘗試此範例,您首先需要設定用戶端所連接的簡式範例助理:

  1. 下載動作 JSON 檔案
  2. 建立助理
  3. 在新的助理中,開啟廣域動作設定。 移至 上傳/下載 標籤,並從您下載的檔案匯入動作。

範例動作包括詢問客戶名稱的 Greet customer 動作,以及用於建立及取消預約的簡式動作。

取得服務資訊

若要存取 watsonx Assistant REST API,您的應用程式需要能夠向 IBM Cloud® 進行鑑別,並連接至其部署所在環境中的助理。 您需要複製服務憑證和環境 ID,然後貼到應用程式代碼中。 您還需要服務實例位置的 URL (例如,https://api.us-south.assistant.watson.cloud.ibm.com )。

若要尋找此資訊,請執行下列動作:

  1. 移至 環境 頁面,然後選擇您要連接的環境。

  2. 按一下 設定 圖示 齒輪圖示 圖示,以開啟環境設定。

  3. 選擇 API 詳細資訊以查看環境的詳細信息,包括服務實例 URL 和環境 ID。 若要尋找 API 金鑰,請遵循 服務認證 區段中的鏈結。

與 watsonx Assistant 服務通訊

從用戶端應用程式與 watsonx Assistant 服務互動很簡單。 我們從連接至服務的範例開始,傳送單一空訊息,並將輸出列印至主控台:

// Example 1: Creates service object, sends initial message, and
// receives response.

const AssistantV2 = require('ibm-watson/assistant/v2');
const { IamAuthenticator } = require('ibm-watson/auth');

// Create Assistant service object.
const assistant = new AssistantV2({
  version: '2021-11-27',
  authenticator: new IamAuthenticator({
    apikey: '{apikey}', // replace with API key
  }),
  url: '{url}', // replace with URL
});

const assistantId = '{environment_id}'; // replace with environment ID

// Start conversation with empty message
messageInput = {
  messageType: 'text',
  text: '',
};
sendMessage(messageInput);

// Send message to assistant.
function sendMessage(messageInput) {
  assistant
    .messageStateless({
      assistantId,
      input: messageInput,
    })
    .then(res => {
      processResult(res.result);
    })
    .catch(err => {
      console.log(err); // something went wrong
    });
}

// Process the result.
function processResult(result) {
  // Print responses from actions, if any. Supports only text responses.
  if (result.output.generic) {
    if (result.output.generic.length > 0) {
      result.output.generic.forEach( response => {
        if (response.response_type == 'text') {
          console.log(response.text);
        }
      });
    }
  }
}
# Example 1: Creates service object, sends initial message, and
# receives response.

from ibm_watson import AssistantV2
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

# Create Assistant service object.
authenticator = IAMAuthenticator('{apikey}') # replace with API key
assistant = AssistantV2(
    version = '2021-11-27',
    authenticator = authenticator
)
assistant.set_service_url('{url}') # replace with service instance URL
assistant_id = '{environment_id}' # replace with environment ID

# Start conversation with empty message.
result = assistant.message_stateless(
    assistant_id,
).get_result()

# Print responses from actions, if any. Supports only text responses.
if result['output']['generic']:
    for response in result['output']['generic']:
        if response['response_type'] == 'text':
            print(response['text'])

首要步驟是建立服務物件,這是 watsonx Assistant 服務的一種封套。

您可以使用服務物件,將輸入傳送至服務,以及從服務接收輸出。 建立服務物件時,您可以指定用於鑑別的 API 金鑰,以及您正在使用的 watsonx Assistant API 版本。

在 Node.js 這個範例中,服務物件是 AssistantV2 的一個實體,儲存在變數 assistant 中。 其他語言的 Watson SDK 提供了實體化服務物件的相等機制。

在 Python 這個範例中,服務物件是 watson_developer_cloud.AssistantV2 的一個實體,儲存在變數 assistant 中。 其他語言的 Watson SDK 提供了實體化服務物件的相等機制。

建立服務物件之後,我們會使用無狀態 message 方法,將訊息傳送給助理。 在此範例中,訊息是空的; 我們想要觸發 Greet customer 動作以開始交談,因此不需要任何輸入文字。 然後,我們會在傳回的輸出中,列印 generic 陣列中所傳回的任何文字回應。

使用 node <filename.js> 指令執行範例應用程式。

使用 python3 <filename.py> 指令執行範例應用程式。

注意: 請確認您使用 npm install ibm-watson 安裝 Watson SDK for Node.js。

注意: 請確認您使用 pip install --upgrade ibm-watsoneasy_install --upgrade ibm-watson 安裝 Python 的 Watson SDK。

假設一切都如預期般運作,助理會傳回助理的輸出,然後應用程式會將輸出列印到控制台:

Welcome to the watsonx Assistant example. What's your name?

此輸出告訴我們,我們已與助理進行通訊,並收到 Greet customer 動作指定的問候語訊息。 但我們還沒有辦法回答助理的問題

正在處理使用者輸入

為了可以處理使用者輸入,我們需要將使用者介面新增至用戶端應用程式。 在這個範例中,我們保持簡單,使用標準輸入和輸出。 您可以使用 Node.js prompt-sync 模組。 (您可以使用 npm install prompt-sync 安裝 prompt-sync ) 您可以使用 Python 3 input 函數。

// Example 2: Adds user input.

const prompt = require('prompt-sync')();
const AssistantV2 = require('ibm-watson/assistant/v2');
const { IamAuthenticator } = require('ibm-watson/auth');

// Create Assistant service object.
const assistant = new AssistantV2({
  version: '2021-11-27',
  authenticator: new IamAuthenticator({
    apikey: '{apikey}', // replace with API key
  }),
  url: '{url}', // replace with URL
});

const assistantId = '{environment_id}'; // replace with environment ID

// Start conversation with empty message
messageInput = {
  messageType: 'text',
  text: '',
};
sendMessage(messageInput);

// Send message to assistant.
function sendMessage(messageInput) {
  assistant
    .messageStateless({
      assistantId,
      input: messageInput,
    })
    .then(res => {
      processResult(res.result);
    })
    .catch(err => {
      console.log(err); // something went wrong
    });
}

// Process the result.
function processResult(result) {

  // Print responses from actions, if any. Supports only text responses.
  if (result.output.generic) {
    if (result.output.generic.length > 0) {
      result.output.generic.forEach( response => {
        if (response.response_type === 'text') {
          console.log(response.text);
        }  
      });
    }
  }

  // Prompt for the next round of input unless skip_user_input is true.
  let newMessageFromUser = '';
  if (result.context.global.system.skip_user_input !== true) {
    newMessageFromUser = prompt('>> ');
  }

  if (newMessageFromUser !== 'quit') {
    newMessageInput = {
      messageType: 'text',
      text: newMessageFromUser,
    }
    sendMessage(newMessageInput);
  }
}
# Example 2: Adds user input.

from ibm_watson import AssistantV2
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

# Create Assistant service object.
authenticator = IAMAuthenticator('{apikey}') # replace with API key
assistant = AssistantV2(
    version = '2021-11-27',
    authenticator = authenticator
)
assistant.set_service_url('{url}') # replace with service instance URL
assistant_id = '{environment_id}' # replace with environment ID

# Initialize with empty value to start the conversation.
message_input = {
    'message_type:': 'text',
    'text': ''
    }

context = None

# Main input/output loop
while message_input['text'] != 'quit':

    # Send message to assistant.
    result = assistant.message_stateless(
        assistant_id,
        input = message_input,
        context=context
    ).get_result()
    context = response['context']

    # Print responses from actions, if any. Supports only text responses.
    if result['output']['generic']:
        for response in result['output']['generic']:
            if response['response_type'] == 'text':
                print(response['text'])

    # Prompt for the next round of input unless skip_user_input is True.
    if not result['context']['global']['system'].get('skip_user_input', False):
        user_input = input('>> ')
        message_input = {
            'text': user_input
        }

此版本應用程式的開始方式像之前一樣:將空白訊息傳送至助理以開始交談。

processResult() 函數會顯示從助理收到的任何回應的文字。 之後,它會提示下一輪的使用者輸入。

然後,它會顯示從助理收到的任何回應的文字,並提示輸入下一輪使用者輸入。

此範例會檢查廣域環境定義變數 skip_user_input,並僅在此變數未設為 trueTrue時提示使用者輸入。 在某些不需要使用者輸入的情況下 (例如,如果助理呼叫外部服務,但仍在等待結果),助理會設定 skip_user_input 變數。 在您提示輸入使用者之前,最好一律先進行此檢查。

因為我們需要結束交談的方法,所以用戶端應用程式也在監看文字指令 quit,以指出程式應該結束。

但仍有問題:

Welcome to the watsonx Assistant example. What's your name?
>> Robert
I'm afraid I don't understand. Please rephrase your question.
>> I want to make an appointment.
What day would you like to come in?
>> Thursday
I'm afraid I don't understand. Please rephrase your question.
>>

助理從正確的問候語開始,但當您說出您的姓名時卻無法理解。 如果您告訴它您想要進行預約,則會觸發正確的動作; 但同樣地,當您回答後續問題時,它會無法理解。

原因是我們使用無狀態 message 方法,這表示用戶端應用程式負責維護交談的狀態資訊。 因為我們還沒有做任何事情來維護狀態,所以助理會將使用者的每一輪輸入都視為新對話的第一個回合。 因為它沒有提出問題的記憶,所以它會嘗試將您的回答解譯為新的問題或要求。

維護狀態

使用上下文來維護您會話的狀態資訊。 環境定義是在應用程式與助理之間來回傳遞的物件,儲存在交談繼續進行時可以保留及更新的資訊。 因為我們是使用 Stateless message 方法,所以助理不會儲存環境定義,所以我們的用戶端應用程式負責從交談的一次到下一次維護它。

環境定義包括每一個交談的階段作業 ID,以及隨著每一次交談而遞增的計數器。 助理會更新環境定義並傳回每一個回應。 但是我們之前版本的範例並沒有保留上下文,因此這些更新都遺失了,而每一輪輸入似乎都是新對話的開始。 我們可以透過每次儲存上下文並傳送回助手來解決這個問題。

除了維持我們在對話中的位置之外,上下文還可以包含動作變數,儲存您想要在應用程式和助理之間來回傳遞的其他資料。 例如,您可以包括要在整個交談中維護的持續資料 (例如客戶名稱或帳號),或您要追蹤的任何其他資料 (例如購物車或使用者喜好設定的內容)。

// Example 3: Preserves context to maintain state.

const prompt = require('prompt-sync')();
const AssistantV2 = require('ibm-watson/assistant/v2');
const { IamAuthenticator } = require('ibm-watson/auth');

// Create Assistant service object.
const assistant = new AssistantV2({
  version: '2021-11-27',
  authenticator: new IamAuthenticator({
    apikey: '{apikey}', // replace with API key
  }),
  url: '{url}', // replace with URL
});

const assistantId = '{environment_id}'; // replace with environment ID

// Start conversation with empty message
messageInput = {
  messageType: 'text',
  text: '',
};
context = {};
sendMessage(messageInput);

// Send message to assistant.
function sendMessage(messageInput, context) {
  assistant
    .messageStateless({
      assistantId,
      input: messageInput,
      context: context,
    })
    .then(res => {
      processResult(res.result);
    })
    .catch(err => {
      console.log(err); // something went wrong
    });
}

// Process the result.
function processResult(result) {

  let context = result.context;

  // Print responses from actions, if any. Supports only text responses.
  if (result.output.generic) {
    if (result.output.generic.length > 0) {
      result.output.generic.forEach( response => {
        if (response.response_type === 'text') {
          console.log(response.text);
        }  
      });
    }
  }

  // Prompt for the next round of input unless skip_user_input is true.
  let newMessageFromUser = '';
  if (result.context.global.system.skip_user_input !== true) {
    newMessageFromUser = prompt('>> ');
  }

  if (newMessageFromUser !== 'quit') {
    newMessageInput = {
      messageType: 'text',
      text: newMessageFromUser,
    }
    sendMessage(newMessageInput, context);
  }
}
# Example 3: Preserves context to maintain state.

from ibm_watson import AssistantV2
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

# Create Assistant service object.
authenticator = IAMAuthenticator('{apikey}') # replace with API key
assistant = AssistantV2(
    version = '2021-11-27',
    authenticator = authenticator
)
assistant.set_service_url('{url}') # replace with service instance URL
assistant_id = '{environment_id}' # replace with environment ID

# Initialize with empty message to start the conversation.
message_input = {
    'message_type:': 'text',
    'text': ''
    }
context = {}

# Initialize with empty message to start the conversation.
message_input = {
    'message_type:': 'text',
    'text': ''
    }
context = {}

# Main input/output loop
while message_input['text'] != 'quit':

    # Send message to assistant.
    result = assistant.message_stateless(
        assistant_id,
        input = message_input,
        context = context
    ).get_result()

    context = result['context']

    # Print responses from actions, if any. Supports only text responses.
    if result['output']['generic']:
        for response in result['output']['generic']:
            if response['response_type'] == 'text':
                print(response['text'])

    # Prompt for the next round of input unless skip_user_input is True.
    if not result['context']['global']['system'].get('skip_user_input', False):
        user_input = input('>> ')
        message_input = {
            'text': user_input
        }

與上一個範例相比,唯一的改變是我們現在將從助手接收到的上下文儲存在一個名為 context 的變數中,並隨著下一輪使用者輸入將它傳送回去:

與上一個範例相比,唯一的改變是我們現在將從助手接收到的上下文儲存在一個名為 context 的變數中,並隨著下一輪使用者輸入將它傳送回去:

  assistant
    .messageStateless({
      assistantId,
      input: messageInput,
      context: context,
    })
response = assistant.message_stateless(
    assistant_id,
    input = message_input,
    context = context
).get_result()

這可確保將環境定義從某一次維護到下一次,因此,watsonx Assistant 服務不再認為每一次都是第一次:

Welcome to the watsonx Assistant example. What's your name?
>> Robert
Hi, Robert! How can I help you?
>> I want to make an appointment.
What day would you like to come in?
>> Next Monday
What time works for you?
>> 10 AM
OK, Robert. You have an appointment for 10:00 AM on Sep 12. See you then!

成功! 應用程式現在使用 watsonx Assistant 服務來瞭解自然語言輸入,並顯示適當的回應。

此簡式範例說明如何建置自訂用戶端應用程式,以與助理進行通訊。 現實世界的應用程式會使用更準確的使用者介面,並可能與其他應用程式 (例如客戶資料庫或其他商務系統) 整合。 它也需要傳送更多資料給助理,例如使用者 ID,以辨識每位獨特的使用者。 但是,應用程式如何與 watsonx Assistant 服務互動的基本原則仍會相同。

包括澄清問題

當助理發現多個動作可能滿足客戶的要求時,它可以自動要求釐清。 如需相關資訊,請參閱 詢問釐清問題

若要包括在自訂用戶端中釐清問題,您需要:

  • 顯示從 message API 傳回的說明建議選項
  • 在下一輪使用有效負載來呼叫 message API,該有效負載對應於客戶選擇以回答澄清問題的建議選項。 如果您未實作該呼叫,則 自動學習使用無法辨識的要求來取得動作建議 無法正確運作。

每項澄清建議包括:

  • 可以向客戶顯示的標籤
  • 指定在使用者選擇對應建議時傳送給助理之輸入的值

若要在應用程式中實作澄清建議,請執行下列動作:

  1. 使用所選建議中的 value.input 物件作為下一輪訊息輸入,而不是建置新的輸入物件。 然後,助理會透過觸發與建議選項相關聯的動作以開始進行回應。

  2. 請使用 分析 頁面來驗證您已使用自訂用戶端正確實作此作業。 輸入會觸發說明的輸入,然後按一下 以上皆非 選項。 當您在 交談 中檢視要求時,請檢查起始說明的使用者要求是否標示有 無法辨識,這表示您的用戶端適當地將說明輸入傳送給助理。

使用 v1 runtime API

建議使用第 2 版 API 來建置與 watsonx Assistant 服務通訊的運行環境用戶端應用程式。 不過,有些舊版應用程式可能仍在使用 v1 runtime API,其中包含類似的方法,可在對話技巧中傳送訊息到工作區。 如果您的應用程式使用 v1 runtime API,它會直接與工作區溝通,繞過助理的技能協調和狀態管理功能。

有關 v1 /message 方法和上下文的詳細資訊,請參閱 v1 API Reference