기술 내에서 대화 상자 사용

적용 대상: SDK v4

이 문서에서는 여러 작업을 지원하는 기술을 만드는 방법을 보여 줍니다. 대화 상자를 사용하여 이러한 작업을 지원합니다. 기본 대화 상자는 기술 소비자로부터 초기 입력을 받은 다음 적절한 작업을 시작합니다. 연결된 샘플 코드에 대한 기술 소비자 구현에 대한 자세한 내용은 대화 상자를 사용하여 기술을 사용하는 방법을 참조하세요.

이 문서에서는 이미 기술을 만드는 데 익숙하다고 가정합니다. 일반적으로 기술 봇을 만드는 방법은 기술을 구현하는 방법을 참조하세요.

참고 항목

Bot Framework JavaScript, C#및 Python SDK는 계속 지원되지만 Java SDK는 2023년 11월에 종료되는 최종 장기 지원으로 사용 중지됩니다. 이 리포지토리 내의 중요한 보안 및 버그 수정만 수행됩니다.

Java SDK를 사용하여 빌드된 기존 봇은 계속 작동합니다.

새 봇 빌드의 경우 Power Virtual Agents 사용을 고려하고 올바른 챗봇 솔루션을 선택하는 방법을 읽어 보세요.

자세한 내용은 봇 빌드의 미래를 참조 하세요.

필수 조건

참고 항목

LUIS(Language Understanding)는 2025년 10월 1일에 사용 중지됩니다. 2023년 4월 1일부터 새 LUIS 리소스를 만들 수 없습니다. 이제 최신 버전의 언어 이해가 Azure AI Language의 일부로 제공됩니다.

Azure AI Language의 기능인 CLU(대화형 언어 이해)는 업데이트된 LUIS 버전입니다. Bot Framework SDK의 언어 이해 지원에 대한 자세한 내용은 자연어 이해를 참조하세요.

이 샘플 정보

skillDialog 기술 샘플에는 두 개의 봇에 대한 프로젝트가 포함되어 있습니다.

  • ‘대화 루트 봇’은 ‘스킬 대화’ 클래스를 사용하여 스킬을 사용합니다.
  • 대화 상자 기술 봇대화 상자를 사용하여 기술 소비자의 활동을 처리합니다. 이 기술은 핵심 봇 샘플을 조정하는 것입니다. (핵심 봇에 대한 자세한 내용은 봇자연어 이해를 추가하는 방법을 참조하세요.)

이 문서에서는 기술 봇 내에서 대화 상자를 사용하여 여러 작업을 관리하는 방법에 중점을 둡니다.

기술 소비자 봇에 대한 자세한 내용은 대화 상자를 사용하여 기술을 사용하는 방법을 참조하세요.

리소스

배포된 봇의 경우 봇-봇 인증을 사용하려면 참여하는 각 봇에 유효한 ID가 있어야 합니다. 그러나 ID 정보 없이 Bot Framework Emulator를 사용하여 기술 및 기술 소비자를 로컬로 테스트할 수 있습니다.

사용자 연결 봇에서 기술을 사용할 수 있도록 하려면 Azure에 기술을 등록합니다. 자세한 내용은 Azure AI Bot Service에 봇을 등록하는 방법을 참조하세요.

필요에 따라 기술 봇은 비행 예약 LUIS 모델을 사용할 수 있습니다. 이 모델을 사용하려면 CognitiveModels/FlightBooking.json 파일을 사용하여 LUIS 모델을 만들고 학습시키고 게시합니다.

애플리케이션 구성

  1. 필요에 따라 기술의 ID 정보를 기술의 구성 파일에 추가합니다. (기술 또는 기술 소비자가 ID를 지정하는 경우 둘 다 반드시 필요합니다.)

  2. LUIS 모델을 사용하는 경우 LUIS 앱 ID, API 키 및 API 호스트 이름을 추가합니다.

DialogSkillBot\appsettings.json

{
  "MicrosoftAppType": "",
  "MicrosoftAppId": "",
  "MicrosoftAppPassword": "",
  "MicrosoftAppTenantId": "",
  "ConnectionName": "",

  "LuisAppId": "",
  "LuisAPIKey": "",
  "LuisAPIHostName": "",

  // This is a comma separate list with the App IDs that will have access to the skill.
  // This setting is used in AllowedCallersClaimsValidator.
  // Examples: 
  //    [ "*" ] allows all callers.
  //    [ "AppId1", "AppId2" ] only allows access to parent bots with "AppId1" and "AppId2".
  "AllowedCallers": [ "*" ]
}

활동 라우팅 논리

기술은 몇 가지 다른 기능을 지원합니다. 그것은 비행을 예약하거나 도시의 날씨를 얻을 수 있습니다. 또한 이러한 컨텍스트 외부에서 메시지를 수신하는 경우 LUIS를 사용하여 메시지를 해석할 수 있습니다. 기술 매니페스트는 이러한 작업, 해당 입력 및 출력 매개 변수 및 기술의 엔드포인트를 설명합니다. 참고로, 이 기술은 “BookFlight” 또는 “GetWeather” 이벤트를 처리할 수 있습니다. 메시지 작업을 처리할 수도 있습니다.

기술은 기술 소비자의 초기 들어오는 활동을 기반으로 시작할 작업을 선택하는 데 사용하는 활동 라우팅 대화 상자를 정의합니다. 제공된 경우 LUIS 모델은 초기 메시지에서 책 비행 및 날씨 가져오기 의도를 인식할 수 있습니다.

책 비행 작업은 별도의 대화 상자로 구현되는 다단계 프로세스입니다. 작업이 시작되면 들어오는 활동이 해당 대화 상자에서 처리됩니다. 날씨 가져오기 작업에는 완전히 구현된 봇에서 대체될 자리 표시자 논리가 있습니다.

활동 라우팅 대화 상자에는 다음을 위한 코드가 포함됩니다.

기술에 사용되는 대화 상자는 구성 요소 대화 상자 클래스에서 상속됩니다. 구성 요소 대화에 대한 자세한 내용은 대화 복잡성 관리 방법을 참조하세요.

대화 상자 초기화

활동 라우팅 대화 상자에는 항공편 예약을 위한 자식 대화 상자가 포함되어 있습니다. 기본 폭포 대화 상자에는 받은 초기 활동을 기반으로 작업을 시작하는 한 단계가 있습니다.

LUIS 인식기도 허용합니다. 이 인식기가 초기화되면 대화 상자에서 이 인식기를 사용하여 초기 메시지 활동의 의도를 해석합니다.

DialogSkillBot\Dialogs\ActivityRouterDialog.cs

private readonly DialogSkillBotRecognizer _luisRecognizer;

public ActivityRouterDialog(DialogSkillBotRecognizer luisRecognizer)
    : base(nameof(ActivityRouterDialog))
{
    _luisRecognizer = luisRecognizer;

    AddDialog(new BookingDialog());
    AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[] { ProcessActivityAsync }));

    // The initial child Dialog to run.
    InitialDialogId = nameof(WaterfallDialog);
}

초기 작업 처리

기본 폭포 대화 상자의 첫 번째(및 유일한) 단계에서 기술은 들어오는 활동 유형을 검사.

  • 이벤트 활동은 이벤트 이름에 따라 적절한 작업을 시작하는 온 이벤트 활동 처리기로 전달됩니다.
  • 메시지 활동은 수행할 작업을 결정하기 전에 추가 처리를 수행하는 메시지 작업 처리기로 전달됩니다.

기술에서 들어오는 작업의 유형이나 이벤트의 이름을 인식하지 못하는 경우 오류 메시지를 보내고 종료합니다.

DialogSkillBot\Dialogs\ActivityRouterDialog.cs

private async Task<DialogTurnResult> ProcessActivityAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    // A skill can send trace activities, if needed.
    await stepContext.Context.TraceActivityAsync($"{GetType().Name}.ProcessActivityAsync()", label: $"Got ActivityType: {stepContext.Context.Activity.Type}", cancellationToken: cancellationToken);

    switch (stepContext.Context.Activity.Type)
    {
        case ActivityTypes.Event:
            return await OnEventActivityAsync(stepContext, cancellationToken);

        case ActivityTypes.Message:
            return await OnMessageActivityAsync(stepContext, cancellationToken);

        default:
            // We didn't get an activity type we can handle.
            await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Unrecognized ActivityType: \"{stepContext.Context.Activity.Type}\".", inputHint: InputHints.IgnoringInput), cancellationToken);
            return new DialogTurnResult(DialogTurnStatus.Complete);
    }
}
// This method performs different tasks based on the event name.
private async Task<DialogTurnResult> OnEventActivityAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var activity = stepContext.Context.Activity;
    await stepContext.Context.TraceActivityAsync($"{GetType().Name}.OnEventActivityAsync()", label: $"Name: {activity.Name}. Value: {GetObjectAsJsonString(activity.Value)}", cancellationToken: cancellationToken);

    // Resolve what to execute based on the event name.
    switch (activity.Name)
    {
        case "BookFlight":
            return await BeginBookFlight(stepContext, cancellationToken);

        case "GetWeather":
            return await BeginGetWeather(stepContext, cancellationToken);

        default:
            // We didn't get an event name we can handle.
            await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Unrecognized EventName: \"{activity.Name}\".", inputHint: InputHints.IgnoringInput), cancellationToken);
            return new DialogTurnResult(DialogTurnStatus.Complete);
    }
}

메시지 작업 처리

LUIS 인식기가 구성된 경우 기술은 LUIS를 호출한 다음 의도에 따라 작업을 시작합니다. LUIS 인식기가 구성되지 않았거나 의도가 지원되지 않는 경우 기술은 오류 메시지를 보내고 종료합니다.

DialogSkillBot\Dialogs\ActivityRouterDialog.cs

// This method just gets a message activity and runs it through LUIS. 
private async Task<DialogTurnResult> OnMessageActivityAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var activity = stepContext.Context.Activity;
    await stepContext.Context.TraceActivityAsync($"{GetType().Name}.OnMessageActivityAsync()", label: $"Text: \"{activity.Text}\". Value: {GetObjectAsJsonString(activity.Value)}", cancellationToken: cancellationToken);

    if (!_luisRecognizer.IsConfigured)
    {
        await stepContext.Context.SendActivityAsync(MessageFactory.Text("NOTE: LUIS is not configured. To enable all capabilities, add 'LuisAppId', 'LuisAPIKey' and 'LuisAPIHostName' to the appsettings.json file.", inputHint: InputHints.IgnoringInput), cancellationToken);
    }
    else
    {
        // Call LUIS with the utterance.
        var luisResult = await _luisRecognizer.RecognizeAsync<FlightBooking>(stepContext.Context, cancellationToken);

        // Create a message showing the LUIS results.
        var sb = new StringBuilder();
        sb.AppendLine($"LUIS results for \"{activity.Text}\":");
        var (intent, intentScore) = luisResult.Intents.FirstOrDefault(x => x.Value.Equals(luisResult.Intents.Values.Max()));
        sb.AppendLine($"Intent: \"{intent}\" Score: {intentScore.Score}");

        await stepContext.Context.SendActivityAsync(MessageFactory.Text(sb.ToString(), inputHint: InputHints.IgnoringInput), cancellationToken);

        // Start a dialog if we recognize the intent.
        switch (luisResult.TopIntent().intent)
        {
            case FlightBooking.Intent.BookFlight:
                return await BeginBookFlight(stepContext, cancellationToken);

            case FlightBooking.Intent.GetWeather:
                return await BeginGetWeather(stepContext, cancellationToken);

            default:
                // Catch all for unhandled intents.
                var didntUnderstandMessageText = $"Sorry, I didn't get that. Please try asking in a different way (intent was {luisResult.TopIntent().intent})";
                var didntUnderstandMessage = MessageFactory.Text(didntUnderstandMessageText, didntUnderstandMessageText, InputHints.IgnoringInput);
                await stepContext.Context.SendActivityAsync(didntUnderstandMessage, cancellationToken);
                break;
        }
    }

    return new DialogTurnResult(DialogTurnStatus.Complete);
}

다단계 작업 시작

책 비행 작업은 사용자로부터 예약 세부 정보를 얻기 위해 다단계 대화 상자를 시작합니다.

날씨 가져오기 작업은 구현되지 않습니다. 현재 자리 표시자 메시지를 보낸 다음 종료됩니다.

DialogSkillBot\Dialogs\ActivityRouterDialog.cs

private async Task<DialogTurnResult> BeginBookFlight(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var activity = stepContext.Context.Activity;
    var bookingDetails = new BookingDetails();
    if (activity.Value != null)
    {
        bookingDetails = JsonConvert.DeserializeObject<BookingDetails>(JsonConvert.SerializeObject(activity.Value));
    }

    // Start the booking dialog.
    var bookingDialog = FindDialog(nameof(BookingDialog));
    return await stepContext.BeginDialogAsync(bookingDialog.Id, bookingDetails, cancellationToken);
}
private static async Task<DialogTurnResult> BeginGetWeather(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var activity = stepContext.Context.Activity;
    var location = new Location();
    if (activity.Value != null)
    {
        location = JsonConvert.DeserializeObject<Location>(JsonConvert.SerializeObject(activity.Value));
    }

    // We haven't implemented the GetWeatherDialog so we just display a TODO message.
    var getWeatherMessageText = $"TODO: get weather for here (lat: {location.Latitude}, long: {location.Longitude}";
    var getWeatherMessage = MessageFactory.Text(getWeatherMessageText, getWeatherMessageText, InputHints.IgnoringInput);
    await stepContext.Context.SendActivityAsync(getWeatherMessage, cancellationToken);
    return new DialogTurnResult(DialogTurnStatus.Complete);
}

결과 반환

이 기술은 북 플라이트 작업에 대한 예약 대화 상자를 시작합니다. 활동 라우팅 대화 상자에는 한 단계만 있으므로 예약 대화 상자가 종료되면 활동 라우팅 대화 상자도 종료되고 예약 대화 상자의 대화 결과는 활동 라우팅 대화 상자의 대화 결과가 됩니다.

날씨 예보 작업은 반환 값을 설정하지 않고 종료됩니다.

다단계 작업 취소

예약 대화 상자와 해당 자식 날짜 확인자 대화 상자는 모두 사용자의 메시지를 검사 기본 취소 및 도움말 대화 상자에서 파생됩니다.

  • "help" 또는 "?"에서는 도움말 메시지를 표시한 다음, 다음 차례에서 대화 흐름을 계속 진행합니다.
  • "취소" 또는 "종료"에서는 모든 대화 상자를 취소하면 기술이 종료됩니다.

자세한 내용은 사용자 중단 처리 방법을 참조하세요.

서비스 등록

이 기술에 필요한 서비스는 일반적으로 스킬 봇에 필요한 서비스와 동일합니다. 필요한 서비스의 논의에 대한 기술 구현 방법을 참조하세요.

기술 매니페스트

기술 매니페스트는 기술이 수행할 수 있는 활동, 입력 및 출력 매개 변수 및 기술의 엔드포인트를 설명하는 JSON 파일입니다. 매니페스트에는 다른 봇의 기술에 액세스하는 데 필요한 정보가 포함됩니다.

DialogSkillBot\wwwroot\manifest\dialogchildbot-manifest-1.0.json

{
  "$schema": "https://schemas.botframework.com/schemas/skills/skill-manifest-2.0.0.json",
  "$id": "DialogSkillBot",
  "name": "Skill bot with dialogs",
  "version": "1.0",
  "description": "This is a sample skill definition for multiple activity types.",
  "publisherName": "Microsoft",
  "privacyUrl": "https://dialogskillbot.contoso.com/privacy.html",
  "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.",
  "license": "",
  "iconUrl": "https://dialogskillbot.contoso.com/icon.png",
  "tags": [
    "sample",
    "travel",
    "weather",
    "luis"
  ],
  "endpoints": [
    {
      "name": "default",
      "protocol": "BotFrameworkV3",
      "description": "Default endpoint for the skill.",
      "endpointUrl": "https://dialogskillbot.contoso.com/api/messages",
      "msAppId": "00000000-0000-0000-0000-000000000000"
    }
  ],
  "activities": {
    "bookFlight": {
      "description": "Books a flight (multi turn).",
      "type": "event",
      "name": "BookFlight",
      "value": {
        "$ref": "#/definitions/bookingInfo"
      },
      "resultValue": {
        "$ref": "#/definitions/bookingInfo"
      }
    },
    "getWeather": {
      "description": "Retrieves and returns the weather for the user's location.",
      "type": "event",
      "name": "GetWeather",
      "value": {
        "$ref": "#/definitions/location"
      },
      "resultValue": {
        "$ref": "#/definitions/weatherReport"
      }
    },
    "passthroughMessage": {
      "type": "message",
      "description": "Receives the user's utterance and attempts to resolve it using the skill's LUIS models.",
      "value": {
        "type": "object"
      }
    }
  },
  "definitions": {
    "bookingInfo": {
      "type": "object",
      "required": [
        "origin"
      ],
      "properties": {
        "origin": {
          "type": "string",
          "description": "This is the origin city for the flight."
        },
        "destination": {
          "type": "string",
          "description": "This is the destination city for the flight."
        },
        "travelDate": {
          "type": "string",
          "description": "The date for the flight in YYYY-MM-DD format."
        }
      }
    },
    "weatherReport": {
      "type": "array",
      "description": "Array of forecasts for the next week.",
      "items": [
        {
          "type": "string"
        }
      ]
    },
    "location": {
      "type": "object",
      "description": "Location metadata.",
      "properties": {
        "latitude": {
          "type": "number",
          "title": "Latitude"
        },
        "longitude": {
          "type": "number",
          "title": "Longitude"
        },
        "postalCode": {
          "type": "string",
          "title": "Postal code"
        }
      }
    }
  }
}

기술 매니페스트 스키마는 기술 매니페스트의 스키마를 설명하는 JSON 파일입니다. 최신 스키마 버전은 v2.1입니다.

기술 봇 테스트

에뮬레이터에서 기술 소비자를 사용하여 기술을 테스트할 수 있습니다. 이렇게 하려면 기술과 기술 소비자 봇을 동시에 실행해야 합니다. 대화 상자를 사용하여 기술을 사용하는 방법을 참조하여 기술을 구성하는 방법에 대한 정보를 확인합니다.

최신 Bot Framework Emulator를 다운로드하여 설치합니다.

  1. 대화 기술 봇 및 대화 루트 봇을 머신에서 로컬로 실행합니다. 지침이 필요한 경우 C#, JavaScript, Java 또는 Python에 대한 샘플 README 파일을 참조하세요.
  2. 에뮬레이터를 사용하여 봇을 테스트합니다.
    • 대화에 처음 참가하면 봇이 환영 메시지를 표시하고 어떤 기술을 호출할지 묻습니다. 이 샘플의 기술 봇에는 하나의 기술만 있습니다.
    • DialogSkillBot을 선택합니다.
  3. 다음으로, 봇은 기술에 대한 작업을 선택하도록 요청합니다. "BookFlight"를 선택합니다.
    1. 기술은 책 비행 작업을 시작합니다. 프롬프트에 응답합니다.
    2. 기술이 완료되면 루트 봇은 예약 세부 정보를 표시한 후 호출하려는 기술에 대해 다시 묻는 메시지를 표시합니다.
  4. DialogSkillBot을 다시 선택하고 "BookFlight"를 선택합니다.
    1. 첫 번째 프롬프트에 응답한 다음 " 취소"를 입력하여 작업을 취소합니다.
    2. 스킬 봇은 작업을 완료하지 않고 종료되고 소비자는 호출하려는 기술을 묻는 메시지를 표시합니다.

디버깅에 대한 자세한 정보

기술과 기술 소비자 간의 트래픽이 인증되므로 이러한 봇을 디버깅할 때 추가 단계가 있습니다.

  • 기술 소비자와 직접 또는 간접적으로 사용하는 모든 기술을 실행해야 합니다.
  • 봇이 로컬로 실행되고 앱 ID와 암호가 있는 봇이 있는 경우 모든 봇에는 유효한 ID와 암호가 있어야 합니다.
  • 봇이 모두 배포된 경우 ngrok사용하여 모든 채널에서 봇을 디버그하는 방법을 참조하세요.
  • 일부 봇이 로컬로 실행되고 일부 봇이 배포된 경우 기술 또는 기술 소비자를 디버그하는 방법을 알아보세요.

그렇지 않으면 다른 봇을 디버그하는 것처럼 기술 소비자 또는 기술을 디버그할 수 있습니다. 자세한 내용은 Bot Framework Emulator를 사용하여 봇 디버깅 및 디버그를 참조하세요.

추가 정보