IBM Cloud Docs
使用 API 构建定制客户机

使用 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. 在新助手中,打开全局操作设置。 转至 上载/下载 选项卡,然后从下载的文件导入操作。

示例操作包括用于询问客户姓名的 问候客户 操作,以及用于进行和取消预约的简单操作。

获取服务信息

要访问 watsonx Assistant REST API,应用程序需要能够向 IBM Cloud® 认证并连接到部署该应用程序的环境中的助手。 您需要复制服务凭证和环境 ID,并将其粘贴到应用程序代码中。 您还需要服务实例位置的 URL (例如 https://api.us-south.assistant.watson.cloud.ibm.com )。

要查找此信息:

  1. 转至“环境”页面,然后选择要连接到的环境。

  2. 单击 设置 图标 "Gear" 图标 图标以打开环境设置。

  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 方法向助手发送消息。 在此示例中,消息为空; 我们希望触发 问候客户 操作以启动对话,因此不需要任何输入文本。 然后,在返回的输出中打印 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?

此输出告诉我们,我们与助手进行了通信,并收到了由 问候客户 操作指定的欢迎消息。 但我们还没有办法回应助手的问题。

正在处理用户输入

为了能够处理用户输入,需要向客户机应用程序添加用户界面。 在本例中,我们将保持简单,使用标准输入和输出。 您可以使用 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 方法,这意味着我们的客户机应用程序负责维护对话的状态信息。 由于我们还没有采取任何措施来维护状态,助手会把用户的每一轮输入都视为新对话的第一轮。 因为它没有提问的记忆,所以它会尝试将您的回答解释为一个新的问题或请求。

维护状态

对话的状态信息通过上下文进行维护。 上下文是在应用程序和助手之间来回传递的对象,用于存储可以在对话继续时保留和更新的信息。 由于我们使用的是无状态 message 方法,因此助手不会存储上下文,因此我们的客户机应用程序负责从对话的一个轮次到下一个轮次对其进行维护。

上下文包含每个对话的会话标识以及随每个对话轮次递增的计数器。 助手会更新上下文,并随每个响应一起返回该上下文。 但我们之前版本的示例没有保留上下文,因此这些更新都丢失了,每一轮输入似乎都是新对话的开始。 我们可以通过保存上下文并每次将其发送回助手来解决这个问题。

除了保持我们在对话中的位置外,上下文还可以包含动作变量,用于存储其他数据,以便在应用程序和助手之间来回传递。 例如,您可以包含要在整个对话中维护的持久数据 (例如,客户的姓名或帐号) 或要跟踪的任何其他数据 (例如,购物车或用户首选项的内容)。

// 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 运行时应用程序接口

建议使用 V2 API 来构建与 watsonx Assistant 服务进行通信的运行时客户机应用程序。 不过,一些旧版应用程序可能仍在使用 v1 运行时 API,其中包含一种类似的方法,用于在对话框技能中向工作区发送消息。 如果您的应用程序使用 v1 运行时 API,它将直接与工作区通信,绕过助手的技能协调和状态管理功能。

有关 v1 /message 方法和上下文的更多信息,请参阅 v1 API Reference