本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
使用語音轉錄可信度分數來改善與 Lex V2 機器人的對話
當使用者發出語音說話時,Amazon Lex V2 會使用自動語音辨識 (ASR) 來轉錄使用者的請求,然後再進行解譯。根據預設,Amazon Lex V2 會使用最有可能的音訊轉錄進行解譯。
在某些情況下,可能會有多個可能的音頻轉錄。例如,使用者可能會發出含糊不清的聲音,例如「我的名字是 John」,可能會被理解為「我的名字是胡安」。在這種情況下,您可以使用消歧義技術或將您的領域知識與轉錄置信度分數相結合,以幫助確定轉錄列表中的哪些轉錄是正確的轉錄。
Amazon Lex V2 包含最上層轉錄和最多兩個替代轉錄,供使用者在向 Lambda 程式碼掛接函數的請求中輸入。每個轉錄都包含一個可信度分數,表明它是正確的轉錄。每個轉錄還包括從用戶輸入推斷的任何插槽值。
您可以比較兩個轉錄的可信度分數,以確定它們之間是否存在模糊性。例如,如果一個轉錄的置信度分數為 0.95,而另一個轉錄的可信度分數為 0.65,則第一個轉錄可能是正確的,並且它們之間的模糊性很低。如果兩個轉錄的信心分數為 0.75 和 0.72,則它們之間的模糊性很高。您可以使用您的領域知識來區分它們。
例如,如果兩個可信度分數為 0.75 和 0.72 的記錄單中推斷的插槽值是「John」和「Juan」,您可以查詢資料庫中的使用者是否存在這些名稱,並排除其中一項轉錄。如果「John」不是資料庫中的使用者,而且「Juan」是,您可以使用對話方塊程式碼掛接將名字的推斷位置值變更為「Juan」。
Amazon Lex V2 傳回的可信度分數是比較值。不要依賴它們作為絕對分數。這些值可能會根據對 Amazon Lex V2 的改進而改變。
音訊轉錄置信度分數僅提供英文 (GB) (en_GB) 和英文 (美國) (en_US) 語言。可信度分數僅支援 8 個 kHz 音訊輸入。Amazon Lex V2 主控台上測試視窗的音訊輸入不會提供轉錄可信度分數,因為它使用 16 個 kHz 音訊輸入。
注意
您必須先重建機器人,才能將音訊轉錄置信度分數用於現有機器人。現有版本的機器人不支援轉錄可信度分數。您必須創建一個新版本的機器人才能使用它們。
您可以針對多個交談設計模式使用信賴度分數:
-
如果最高可信度分數因為環境嘈雜或訊號品質不佳而降至臨界值以下,您可以提示使用者提示相同的問題,以擷取品質較佳的音訊。
-
如果多個轉錄對於插槽值具有類似的可信度分數,例如「John」和「Juan」,您可以將這些值與預先存在的資料庫進行比較,以消除輸入,或者提示使用者選取兩個值之一。例如,「為約翰說 1,或說 2 代表胡安。」
-
如果您的商務邏輯需要根據替代文字本中的特定關鍵字進行意圖切換,且信賴度分數接近頂端成績單,您可以使用對話方塊程式碼掛接 Lambda 函數或使用工作階段管理作業來變更意圖。如需詳細資訊,請參閱工作階段管理。
Amazon Lex V2 會傳送下列JSON結構,其中包含最多三個轉錄,供使用者輸入至 Lambda 程式碼掛接函數:
"transcriptions": [
{
"transcription": "string",
"rawTranscription": "string",
"transcriptionConfidence": "number",
},
"resolvedContext": {
"intent": "string"
},
"resolvedSlots": {
"string": {
"shape": "List",
"value": {
"originalValue": "string",
"resolvedValues": [
"string"
]
},
"values": [
{
"shape": "Scalar",
"value": {
"originalValue": "string",
"resolvedValues": [
"string"
]
}
},
{
"shape": "Scalar",
"value": {
"originalValue": "string",
"resolvedValues": [
"string"
]
}
}
]
}
}
}
]
該JSON結構包含轉錄文本,為語音解析的意圖以及在話語中檢測到的任何插槽的值。對於文字使用者輸入,轉錄會包含單一成績單,信賴度分數為 1.0。
成績單的內容取決於對話的轉向和公認的意圖。
對於第一回合,意圖引出,Amazon Lex V2 決定了前三個轉錄。對於頂部轉錄,它返回轉錄中的意圖和任何推斷的插槽值。
在隨後的轉彎中,槽引出,結果取決於每個轉錄的推斷意圖,如下所示。
-
如果頂部成績單的推斷意圖與上一回合相同,並且所有其他成績單具有相同的意圖,那麼
-
所有成績單都包含推斷的位置值。
-
-
如果頂級成績單的推斷意圖與上一回合不同,並且所有其他成績單都有先前的意圖,那麼
-
頂部成績單包含新意圖的推斷插槽值。
-
其他成績單具有先前意圖的意圖和推斷的位置值,以供先前的意圖使用。
-
-
如果頂部成績單的推斷意圖與前一回合不同,則一個成績單與前一個意圖相同,而一個成績單是不同的意圖,那麼
-
頂部的成績單包含新推斷的意圖和任何推斷的插槽值在話語中。
-
具有先前推斷意圖的成績單包含針對該意圖推斷的位置值。
-
具有不同意圖的成績單沒有推斷的意圖名稱,也沒有推斷的插槽值。
-
-
如果頂級成績單的推斷意圖與上一回合不同,並且所有其他成績單具有不同的意圖,那麼
-
頂部的成績單包含新推斷的意圖和任何推斷的插槽值在話語中。
-
其他成績單不包含推斷的意圖,也沒有推斷的插槽值。
-
-
如果前兩個成績單的推斷意圖與前一回合相同且不同,而第三個成績單是不同的意圖,那麼
-
前兩個成績單中包含新推斷的意圖和任何推斷出來的插槽值。
-
第三個記錄沒有意圖名稱,也沒有解析的槽值。
-
工作階段管理
若要變更 Amazon Lex V2 在與使用者交談中使用的意圖,請使用對話方塊程式碼掛接 Lambda 函數的回應。或者,您可以在自訂應用程式APIs中使用工作階段管理。
搭配您的 Lex V2 機器人使用 Lambda 函數
當您使用 Lambda 函數時,Amazon Lex V2 會使用包含函數輸入的JSON結構來呼叫該函數。結JSON構包含一個名為的欄位transcriptions
,其中包含 Amazon Lex V2 針對話語所決定的可能轉錄。該transcriptions
欄位包含一到三個可能的轉錄,每個都有可信度分數。
若要使用替代轉錄中的意圖,請在 Lambda 函數的ConfirmIntent
或對ElicitSlot
話方塊動作中指定該意圖。若要使用替代轉錄中的插槽值,請在 Lambda 函數回應的intent
欄位中設定值。如需詳細資訊,請參閱整合 AWS Lambda 功能到你的機器人。
使用 Lambda 與 Lex V2 的範例程式
下列程式碼範例是 Python Lambda 函數,它使用音訊轉錄來改善使用者的交談體驗。
若要使用範例程式碼,您必須具備:
-
具有一種語言的機器人,可以是英文 (GB) (en_GB) 或英文 (美國) (en_US)。
-
一個意圖, OrderBirthStone. 確定已在意圖定義的 [程式碼掛接] 區段中選取 [使用 Lambda 函數進行初始化和驗證]。
-
意圖應該有兩個插槽,「BirthMonth」和「名稱」兩種類型
AMAZON.AlphaNumeric
。 -
定義了 Lambda 函數的別名。如需詳細資訊,請參閱創建一個 AWS Lambda 您的機器人的功能。
import time import os import logging logger = logging.getLogger() logger.setLevel(logging.DEBUG) # --- Helpers that build all of the responses --- def elicit_slot(session_attributes, intent_request, slots, slot_to_elicit, message): return { 'sessionState': { 'dialogAction': { 'type': 'ElicitSlot', 'slotToElicit': slot_to_elicit }, 'intent': { 'name': intent_request['sessionState']['intent']['name'], 'slots': slots, 'state': 'InProgress' }, 'sessionAttributes': session_attributes, 'originatingRequestId': 'e3ab4d42-fb5f-4cc3-bb78-caaf6fc7cccd' }, 'sessionId': intent_request['sessionId'], 'messages': [message], 'requestAttributes': intent_request['requestAttributes'] if 'requestAttributes' in intent_request else None } def close(intent_request, session_attributes, fulfillment_state, message): intent_request['sessionState']['intent']['state'] = fulfillment_state return { 'sessionState': { 'sessionAttributes': session_attributes, 'dialogAction': { 'type': 'Close' }, 'intent': intent_request['sessionState']['intent'], 'originatingRequestId': '3ab4d42-fb5f-4cc3-bb78-caaf6fc7cccd' }, 'messages': [message], 'sessionId': intent_request['sessionId'], 'requestAttributes': intent_request['requestAttributes'] if 'requestAttributes' in intent_request else None } def delegate(intent_request, session_attributes): return { 'sessionState': { 'dialogAction': { 'type': 'Delegate' }, 'intent': intent_request['sessionState']['intent'], 'sessionAttributes': session_attributes, 'originatingRequestId': 'abc' }, 'sessionId': intent_request['sessionId'], 'requestAttributes': intent_request['requestAttributes'] if 'requestAttributes' in intent_request else None } def get_session_attributes(intent_request): sessionState = intent_request['sessionState'] if 'sessionAttributes' in sessionState: return sessionState['sessionAttributes'] return {} def get_slots(intent_request): return intent_request['sessionState']['intent']['slots'] """ --- Functions that control the behavior of the bot --- """ def order_birth_stone(intent_request): """ Performs dialog management and fulfillment for ordering a birth stone. Beyond fulfillment, the implementation for this intent demonstrates the following: 1) Use of N best transcriptions to re prompt user when confidence for top transcript is below a threshold 2) Overrides resolved slot for birth month from a known fixed list if the top transcript is not accurate. """ transcriptions = intent_request['transcriptions'] if intent_request['invocationSource'] == 'DialogCodeHook': # Disambiguate if there are multiple transcriptions and the top transcription # confidence is below a threshold (0.8 here) if len(transcriptions) > 1 and transcriptions[0]['transcriptionConfidence'] < 0.8: if transcriptions[0]['resolvedSlots'] is not {} and 'Name' in transcriptions[0]['resolvedSlots'] and \ transcriptions[0]['resolvedSlots']['Name'] is not None: return prompt_for_name(intent_request) elif transcriptions[0]['resolvedSlots'] is not {} and 'BirthMonth' in transcriptions[0]['resolvedSlots'] and \ transcriptions[0]['resolvedSlots']['BirthMonth'] is not None: return validate_month(intent_request) return continue_conversation(intent_request) def prompt_for_name(intent_request): """ If the confidence for the name is not high enough, re prompt the user with the recognized names so it can be confirmed. """ resolved_names = [] for transcription in intent_request['transcriptions']: if transcription['resolvedSlots'] is not {} and 'Name' in transcription['resolvedSlots'] and \ transcription['resolvedSlots']['Name'] is not None: resolved_names.append(transcription['resolvedSlots']['Name']['value']['originalValue']) if len(resolved_names) > 1: session_attributes = get_session_attributes(intent_request) slots = get_slots(intent_request) return elicit_slot(session_attributes, intent_request, slots, 'Name', {'contentType': 'PlainText', 'content': 'Sorry, did you say your name is {} ?'.format(" or ".join(resolved_names))}) else: return continue_conversation(intent_request) def validate_month(intent_request): """ Validate month from an expected list, if not valid looks for other transcriptions and to see if the month recognized there has an expected value. If there is, replace with that and if not continue conversation. """ expected_months = ['january', 'february', 'march'] resolved_months = [] for transcription in intent_request['transcriptions']: if transcription['resolvedSlots'] is not {} and 'BirthMonth' in transcription['resolvedSlots'] and \ transcription['resolvedSlots']['BirthMonth'] is not None: resolved_months.append(transcription['resolvedSlots']['BirthMonth']['value']['originalValue']) for resolved_month in resolved_months: if resolved_month in expected_months: intent_request['sessionState']['intent']['slots']['BirthMonth']['resolvedValues'] = [resolved_month] break return continue_conversation(intent_request) def continue_conversation(event): session_attributes = get_session_attributes(event) if event["invocationSource"] == "DialogCodeHook": return delegate(event, session_attributes) # --- Intents --- def dispatch(intent_request): """ Called when the user specifies an intent for this bot. """ logger.debug('dispatch sessionId={}, intentName={}'.format(intent_request['sessionId'], intent_request['sessionState']['intent']['name'])) intent_name = intent_request['sessionState']['intent']['name'] # Dispatch to your bot's intent handlers if intent_name == 'OrderBirthStone': return order_birth_stone(intent_request) raise Exception('Intent with name ' + intent_name + ' not supported') # --- Main handler --- def lambda_handler(event, context): """ Route the incoming request based on intent. The JSON body of the request is provided in the event slot. """ # By default, treat the user request as coming from the America/New_York time zone. os.environ['TZ'] = 'America/New_York' time.tzset() logger.debug('event={}'.format(event)) return dispatch(event)
使用工作階段管理API來選擇不同的意圖或位置值
若要使用與目前意圖不同的意圖,請使用此PutSession作業。例如,如果您決定第一個替代方法比 Amazon Lex V2 選擇的意圖更好,則可以使用此PutSession
操作來變更意圖。這樣,用戶與之交互的下一個意圖將是您選擇的意圖。
您也可以使用此PutSession
作業來變更結intent
構中的位置值,以使用替代轉錄中的值。
如需詳細資訊,請參閱了解 Amazon Lex V2 機器人工作階段。