음성 트랜스크립션 신뢰도 점수 사용 - Amazon Lex

음성 트랜스크립션 신뢰도 점수 사용

사용자가 음성으로 말하면 Amazon Lex V2는 자동 음성 인식(ASR)을 사용하여 사용자의 요청을 해석하기 전에 해당 요청을 기록합니다. 기본적으로 Amazon Lex V2는 해석에 가장 가능성이 높은 오디오 트랜스크립션을 사용합니다.

경우에 따라 오디오의 트랜스크립션이 두 개 이상 있을 수 있습니다. 예를 들어, 사용자가 “내 이름은 John입니다”라고 말하면 “내 이름은 Juan입니다”와 같이 모호하게 들릴 수 있습니다. 이 경우 모호성을 없애는 기법을 사용하거나 도메인 지식을 트랜스크립션 신뢰도 점수와 결합하여 트랜스크립션 목록에 있는 트랜스크립션이 올바른지 판단하는 데 도움이 될 수 있습니다.

Amazon Lex V2에는 Lambda 코드 후크 함수에 대한 요청 시 사용자 입력을 위한 상위 트랜스크립션과 최대 2개의 대체 트랜스크립션이 포함되어 있습니다. 각 트랜스크립션에는 올바른 트랜스크립션이라는 신뢰도 점수가 포함되어 있습니다. 각 트랜스크립션에는 사용자 입력에서 추론된 모든 슬롯 값도 포함됩니다.

두 트랜스크립션의 신뢰도 점수를 비교하여 둘 사이에 모호성이 있는지 확인할 수 있습니다. 예를 들어, 한 트랜스크립션의 신뢰도 점수가 0.95이고 다른 트랜스크립션의 신뢰도 점수가 0.65인 경우 첫 번째 트랜스크립션이 정확할 가능성이 높고 두 텍스트 사이의 모호성은 낮습니다. 두 트랜스크립션의 신뢰도 점수가 0.75와 0.72이면 둘 사이의 모호성이 높습니다. 도메인에 대한 지식을 사용하여 두 가지를 구별할 수도 있습니다.

예를 들어 신뢰도 점수가 0.75와 0.72인 두 대화 내용에서 추론된 슬롯 값이 “John”과 “Juan”인 경우 데이터베이스의 사용자에게 이러한 이름이 있는지 쿼리하고 트랜스크립션 중 하나를 제거할 수 있습니다. “John”이 데이터베이스의 사용자가 아니고 “Juan”은 사용자인 경우, 대화 코드 후크를 사용하여 이름에 대해 추론된 슬롯 값을 “Juan”으로 변경할 수 있습니다.

Amazon Lex V2가 반환하는 신뢰도 점수는 비교 값입니다. 절대 점수로 사용하지 마십시오. 점수는 Amazon Lex V2의 개선 사항에 따라 변경될 수 있습니다.

오디오 트랜스크립션 신뢰도 점수는 영어(영국)(en_GB) 및 영어(미국)(en_US) 언어로만 제공됩니다. 신뢰도 점수는 8kHz 오디오 입력에만 지원됩니다. Amazon Lex V2 콘솔의 테스트 창에서 입력되는 오디오에는 16kHz 오디오 입력을 사용하므로 트랜스크립션 신뢰도 점수가 제공되지 않습니다.

참고

기존 봇에서 오디오 트랜스크립션 신뢰도 점수를 사용하려면 먼저 봇을 다시 빌드해야 합니다. 기존 버전의 봇은 트랜스크립션 신뢰도 점수를 지원하지 않습니다. 봇을 사용하려면 봇의 새 버전을 만들어야 합니다.

여러 대화 디자인 패턴에 신뢰도 점수를 사용할 수 있습니다.

  • 시끄러운 환경이나 열악한 신호 품질로 인해 최고 신뢰도 점수가 임계값 아래로 떨어지는 경우, 동일한 질문을 통해 사용자에게 더 나은 품질의 오디오를 캡처하도록 유도할 수 있습니다.

  • 여러 트랜스크립션의 슬롯 값에 대한 신뢰도 점수가 비슷한 경우(예: “John” 및 “Juan”), 값을 기존 데이터베이스와 비교하여 입력을 제거하거나 사용자에게 두 값 중 하나를 선택하라는 메시지를 표시할 수 있습니다. 예: “John의 경우 1, Juan의 경우 2라고 말하세요.”

  • 신뢰도 점수가 상위 트랜스크립트와 비슷한 대체 트랜스크립트의 특정 키워드를 기반으로 하는 의도 전환이 비즈니스 로직에 필요한 경우, 대화 코드 후크 Lambda 함수를 사용하거나 세션 관리 작업을 사용하여 의도를 변경할 수 있습니다. 자세한 내용은 세션 관리 섹션을 참조하세요.

Amazon Lex V2는 Lambda 코드 후크 함수에 대한 사용자 입력에 대해 최대 3개의 트랜스크립션이 포함된 다음 JSON 구조를 전송합니다.

"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가 상위 3개의 트랜스크립션을 결정합니다. 상위 트랜스크립션의 경우 트랜스크립션에서 의도와 추론된 슬롯 값을 반환합니다.

후속 턴에서 슬롯 유도의 결과는 다음과 같이 각 트랜스크립션의 추론된 의도에 따라 달라집니다.

  • 상위 대화 기록에 대한 추론된 의도가 이전 대화 기록과 동일하고 다른 모든 대화 기록의 의도가 같으면

    • 모든 대화 기록에는 추론된 슬롯 값이 포함되어 있습니다.

       

  • 상위 대화 기록에 대한 추론 의도가 이전 턴과 다르고 다른 모든 대화 기록에 이전 의도가 있는 경우

    • 상위 대화 기록에는 새 의도에 대해 추론된 슬롯 값이 포함됩니다.

    • 다른 대화 기록에는 이전 의도가 있고 이전 의도에 대해 추론된 슬롯 값이 있습니다.

       

  • 상위 대화 기록에 대한 추론된 의도가 이전 턴과 다른 경우(하나의 대화 기록은 이전 의도와 동일하고, 다른 하나의 트랜스크립트는 다른 의도)

    • 상위 대화 기록에는 새로 추론된 의도와 발화의 모든 추론된 슬롯 값이 포함됩니다.

    • 이전에 추론된 의도가 있는 대화 기록에는 해당 의도에 대해 추론된 슬롯 값이 포함되어 있습니다.

    • 다른 의도의 대화 기록에는 추론된 의도 이름도 없고 추론된 슬롯 값도 없습니다.

       

  • 상위 대화 기록에 대한 추론된 의도가 이전 턴과 다르고 다른 모든 대화 기록의 의도가 다르면

    • 상위 대화 기록에는 새로 추론된 의도와 발화의 모든 추론된 슬롯 값이 포함됩니다.

    • 다른 대화 기록에는 추론된 의도와 추론된 슬롯 값이 포함되어 있지 않습니다.

       

  • 상위 두 개의 대화 기록에 대한 추론된 의도가 이전 턴과 동일하고 다르고 세 번째 대화 기록의 의도가 다른 경우

    • 상위 두 개의 대화 기록에는 새로 추론된 의도와 발화의 모든 추론된 슬롯 값이 포함되어 있습니다.

    • 세 번째 트랜스크립트에는 의도 이름도 없고 확인된 슬롯 값도 없습니다.

세션 관리

Amazon Lex V2가 사용자와의 대화에서 사용하는 의도를 변경하려면 대화 코드 후크 Lambda 함수의 응답을 사용하세요. 또는 사용자 지정 애플리케이션에서 세션 관리 API를 사용할 수 있습니다.

Lambda 함수 사용

Lambda 함수를 사용하는 경우 Amazon Lex V2는 함수에 대한 입력이 포함된 JSON 구조를 사용하여 함수를 호출합니다. JSON 구조에는 Amazon Lex V2가 발화에 대해 결정한 가능한 트랜스크립션이 포함된 transcriptions이라는 필드가 포함되어 있습니다. 이 transcriptions 필드에는 1~3개의 가능한 트랜스크립션이 포함되며 각 트랜스크립션에는 신뢰도 점수가 있습니다.

대체 트랜스크립션의 의도를 사용하려면 Lambda 함수의 ConfirmIntent 또는 ElicitSlot 대화 작업에서 해당 의도를 지정합니다. 대체 트랜스크립션의 슬롯 값을 사용하려면 Lambda 함수 응답의 intent 필드에 값을 설정하십시오. 자세한 내용은 AWS Lambda 함수를 사용하여 사용자 지정 로직 활성화 섹션을 참조하세요.

예제 코드

다음 코드 예제는 오디오 트랜스크립션을 사용하여 사용자의 대화 환경을 개선하는 Python Lambda 함수입니다.

예제 코드를 사용하려면 다음이 필요합니다.

  • 영어(영국)(en_GB) 또는 영어(미국)(en_US) 중 하나의 언어를 사용하는 봇.

  • 한 가지 의도는 OrderBirthStone입니다. 의도 정의의 코드 후크 섹션에서 초기화 및 검증에 Lambda 함수 사용이 선택되어 있는지 확인하십시오.

  • 의도에는 ‘BirthMonth’과 ‘Name’이라는 두 개의 슬롯이 있어야 하며, 두 슬롯 모두 AMAZON.AlphaNumeric 유형이어야 합니다.

  • Lambda 함수가 정의된 별칭. 자세한 내용은 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 API를 사용한 세션 관리 섹션을 참조하세요.