API を使用したカスタム・クライアントのビルド
の自動学習機能 watsonx Assistant
2025年6月16日をもって、 watsonx Assistant の自動学習機能は廃止される。 この日を過ぎると、自動学習設定は 「アクション」グローバル設定ページから削除され、すべての自動学習機能が無効になります。
組み込みの統合がどれも要件を満たさない場合は、ユーザーと対話し、 IBM® watsonx™ Assistant サービスと通信するカスタムクライアントアプリケーションを開発することで、アシスタントを展開できます。
Watson SDK は、 watsonx Assistantと対話するコードの作成に役立ちます。 SDKの詳細については、 IBM Watson APIを参照してください。
アシスタントのセットアップ
ここで作成するサンプル・アプリケーションは、クライアント・アプリケーションが watsonx Assistantと対話する方法を示すために、いくつかの単純な関数を実装します。 アプリケーション・コードは入力を収集し、アシスタントに送信します。アシスタントは、アプリケーションがユーザーに表示する応答を送信します。
この例を試すには、まず、クライアントが接続する単純なサンプル・アシスタントをセットアップする必要があります。
- アクション JSON ファイルをダウンロードします。
- アシスタントを作成します。
- 新規アシスタントで、 グローバル・アクション設定を開きます。 「アップロード/ダウンロード」 タブに移動し、ダウンロードしたファイルからアクションをインポートします。
アクションの例には、顧客の名前を尋ねる Greet customer アクションと、予約を作成およびキャンセルするための単純なアクションが含まれています。
サービス情報の取得
watsonx Assistant REST API にアクセスするには、アプリケーションが IBM Cloud® で認証され、デプロイされている環境でアシスタントに接続できる必要があります。 サービス・クレデンシャルと環境IDをコピーし、アプリケーション・コードに貼り付ける必要がある。 また、サービス・インスタンスの場所の URL (例えば、 https://api.us-south.assistant.watson.cloud.ibm.com
)も必要です。
この情報を見つけるには:
-
「環境」 ページに移動し、接続先の環境を選択します。
-
設定アイコン
アイコン をクリックし、環境設定を開きます。
-
APIの詳細を選択すると、サービスインスタンスの URL環境IDなど、環境の詳細が表示されます。 API キーを見つけるには、 「サービス資格情報」 セクションのリンクをたどります。
watsonx Assistant サービスとの通信
クライアント・アプリケーションからの watsonx Assistant サービスとの対話は簡単です。 まずは、サービスに接続し、空のメッセージを1つ送信し、その出力をコンソールに表示する例から始める:
// 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-watson
または easy_install --upgrade ibm-watson
を使用して、 Python 用の Watson SDK をインストールしてください。
すべてが期待通りに動いたと仮定すると、アシスタントはアシスタントからの出力を返し、アプリはそれをコンソールに出力します:
Welcome to the watsonx Assistant example. What's your name?
この出力は、アシスタントと通信したこと、および 「Greet customer」 アクションによって指定された挨拶メッセージを受信したことを示しています。 しかし、アシスタントの質問に対応する方法はまだありません。
ユーザー入力の処理
ユーザー入力を処理するためには、クライアント・アプリケーションにユーザー・インターフェースを追加する必要があります。 この例では、シンプルに標準入出力を使用する。
Node.js prompt-sync モジュールを使用できます。 (prompt-sync は npm install 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
を検査し、この変数が true
True
に設定されていない場合にのみ、ユーザー入力を求めるプロンプトを出します。
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
メソッドを使用しているため、アシスタントはコンテキストを保管しません。会話の 1 つのターンから次のターンまでコンテキストを維持するのは、クライアント・アプリケーションの責任です。
コンテキストには、会話ごとのセッション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 を呼び出します。 呼び出しを実装しない場合、 自動学習 および 認識されない要求を使用してアクション推奨を取得する が正しく機能しません。
各明確化の提案には以下が含まれます。
- お客様に表示できるラベル
- ユーザーが対応する提案を選択した場合にアシスタントに送信される入力を指定する値
アプリケーションに説明の提案を実装するには、以下のようにします。
-
新しい入力オブジェクトを作成するのではなく、選択した提案の
value.input
オブジェクトをメッセージ入力の次のラウンドとして使用します。 その後、アシスタントは、開始する提案オプションに関連付けられているアクションをトリガーすることによって応答します。 -
「分析」 ページを使用して、カスタム・クライアントを使用してこれを正しく実装したことを確認します。 説明をトリガーする入力を入力し、 「上記以外」 オプションをクリックします。 Conversations で要求を表示する場合は、明確化を開始したユーザー要求に 「認識されない (Unrecognized)」 のマークが付いていることを確認してください。これは、クライアントが明確化の入力をアシスタントに適切に送信していることを示します。
v1 ランタイム API の使用
watsonx Assistant サービスと通信するランタイム・クライアント・アプリケーションを構築する場合には、v2 API を使用することをお勧めします。 ただし、一部の古いアプリケーションはまだ v1 ランタイム API を使用している可能性があります。この API には、ダイアログ・スキル内でワークスペースにメッセージを送信するための類似の方法が含まれています。 アプリが v1 ランタイムAPIを使用する場合、ワークスペースと直接通信し、アシスタントのスキルオーケストレーションと状態管理機能をバイパスします。
v1 /message
メソッドとコンテキストの詳細については、 v1 APIリファレンスを参照のこと。