다음을 통해 공유


스토리지에 직접 작성

적용 대상: SDK v4

미들웨어 또는 컨텍스트 개체를 사용하지 않고 스토리지 개체를 직접 읽고 쓸 수 있습니다. 이는 봇에서 대화를 보존하는 데 사용하는 데이터 또는 봇의 대화 흐름 외부 소스에서 제공되는 데이터에 적합할 수 있습니다. 이 데이터 스토리지 모델에서 데이터는 상태 관리자를 사용하는 대신 스토리지에서 직접 읽습니다. 이 문서의 코드 예제에서는 메모리, Cosmos DB, Azure Blob 및 Azure Blob Transcript Storage를 사용하여 데이터를 읽고 스토리지에 쓰는 방법을 보여 줍니다.

참고 항목

Bot Framework JavaScript, C#및 Python SDK는 계속 지원되지만 Java SDK는 2023년 11월에 종료되는 최종 장기 지원으로 사용 중지됩니다.

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

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

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

필수 조건

참고 항목

Visual Studio 내에서 템플릿을 설치할 수 있습니다.

  1. 메뉴에서 확장을 선택한 다음, 확장 관리를 선택합니다.
  2. 확장 관리 대화 상자에서 Visual Studio용 Bot Framework v4 SDK 템플릿을 검색하고 설치합니다.

.NET 봇을 Azure에 배포하는 방법에 대한 자세한 내용은 봇을 프로비전하고 게시하는 방법을 참조하세요.

이 샘플 정보

이 문서의 샘플 코드는 기본 에코 봇의 구조로 시작한 다음, 아래에 나와 있는 코드를 추가하여 봇의 기능을 확장합니다. 이 확장 코드는 사용자 입력이 수신될 때 유지되는 목록을 만듭니다. 메모리에 저장된 사용자 입력의 전체 목록은 각 턴마다 사용자에게 다시 에코됩니다. 그런 다음 이 입력 목록을 포함하는 데이터 구조가 스토리지에 저장되도록 수정됩니다. 이 샘플 코드에 추가 기능이 추가됨에 따라 다양한 유형의 스토리지가 탐색됩니다.

메모리 스토리지

Bot Framework SDK를 사용하면 메모리 내 스토리지를 사용하여 사용자 입력을 저장할 수 있습니다. 메모리 내 스토리지는 봇을 다시 시작할 때마다 지워지므로 테스트 목적에 가장 적합하며 프로덕션 용도로는 적합하지 않습니다. 데이터베이스 스토리지와 같은 영구 스토리지 유형은 프로덕션 봇에 가장 적합합니다.

기본 봇 빌드

이 항목의 나머지 내용은 Echo 봇에서 빌드됩니다. Echo 봇 샘플 코드는 봇 만들기에 대한 빠른 시작 지침에 따라 로컬로 빌드할 수 있습니다.

EchoBot.cs 코드를 다음 코드로 바꿉다.

using System;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

// Represents a bot saves and echoes back user input.
public class EchoBot : ActivityHandler
{
   // Create local Memory Storage.
   private static readonly MemoryStorage _myStorage = new MemoryStorage();

   // Create cancellation token (used by Async Write operation).
   public CancellationToken cancellationToken { get; private set; }

   // Class for storing a log of utterances (text of messages) as a list.
   public class UtteranceLog : IStoreItem
   {
      // A list of things that users have said to the bot
      public List<string> UtteranceList { get; } = new List<string>();

      // The number of conversational turns that have occurred
      public int TurnNumber { get; set; } = 0;

      // Create concurrency control where this is used.
      public string ETag { get; set; } = "*";
   }

   // Echo back user input.
   protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
   {
      // preserve user input.
      var utterance = turnContext.Activity.Text;

      // Make empty local log-items list.
      UtteranceLog logItems = null;

      // See if there are previous messages saved in storage.
      try
      {
         string[] utteranceList = { "UtteranceLog" };
         logItems = _myStorage.ReadAsync<UtteranceLog>(utteranceList).Result?.FirstOrDefault().Value;
      }
      catch
      {
         // Inform the user an error occurred.
         await turnContext.SendActivityAsync("Sorry, something went wrong reading your stored messages!");
      }

      // If no stored messages were found, create and store a new entry.
      if (logItems is null)
      {
         // Add the current utterance to a new object.
         logItems = new UtteranceLog();
         logItems.UtteranceList.Add(utterance);

         // Set initial turn counter to 1.
         logItems.TurnNumber++;

         // Show user new user message.
         await turnContext.SendActivityAsync($"{logItems.TurnNumber}: The list is now: {string.Join(", ", logItems.UtteranceList)}");

         // Create dictionary object to hold received user messages.
         var changes = new Dictionary<string, object>();
         {
            changes.Add("UtteranceLog", logItems);
         }
         try
         {
            // Save the user message to your Storage.
            await _myStorage.WriteAsync(changes, cancellationToken);
         }
         catch
         {
            // Inform the user an error occurred.
            await turnContext.SendActivityAsync("Sorry, something went wrong storing your message!");
         }
      }
      // Else, our storage already contained saved user messages, add new one to the list.
      else
      {
         // add new message to list of messages to display.
         logItems.UtteranceList.Add(utterance);
         // increment turn counter.
         logItems.TurnNumber++;

         // show user new list of saved messages.
         await turnContext.SendActivityAsync($"{logItems.TurnNumber}: The list is now: {string.Join(", ", logItems.UtteranceList)}");

         // Create Dictionary object to hold new list of messages.
         var changes = new Dictionary<string, object>();
         {
            changes.Add("UtteranceLog", logItems);
         };

         try
         {
            // Save new list to your Storage.
            await _myStorage.WriteAsync(changes,cancellationToken);
         }
         catch
         {
            // Inform the user an error occurred.
            await turnContext.SendActivityAsync("Sorry, something went wrong storing your message!");
         }
      }
   }
}

봇 시작

로컬로 봇을 실행합니다.

에뮬레이터를 시작하고 봇 연결

Bot Framework Emulator Next를 설치하고 에뮬레이터를 시작한 다음 에뮬레이터에서 봇에 연결합니다.

  1. 에뮬레이터 시작 탭에서 새 봇 구성 만들기 링크를 선택합니다.
  2. 봇을 시작할 때 표시되는 웹 페이지의 정보를 고려하여 필드를 채워 봇에 연결합니다.

봇과의 상호 작용

봇에 메시지를 보냅니다. 봇은 받은 메시지를 나열합니다.

사용자의 메시지 목록을 유지하는 봇을 보여 주는 봇과의 대화입니다.

이 문서의 re기본der는 봇의 내부 메모리 대신 영구 스토리지에 저장하는 방법을 보여 줍니다.

Cosmos DB 사용

Important

Cosmos DB 스토리지 클래스는 더 이상 사용되지 않습니다. 원래 CosmosDbStorage를 사용하여 만든 컨테이너에는 파티션 키 집합이 없으며 _/partitionKey의 기본 파티션 키가 지정되었습니다.

Cosmos DB 스토리지만든 컨테이너는 Cosmos DB 분할 스토리지와 함께 사용할 수 있습니다. 자세한 내용은 Azure Cosmos DB 분할을 읽어보세요.

또한 레거시 Cosmos DB 스토리지와 달리 Cosmos DB 분할된 스토리지는 Cosmos DB 계정 내에서 데이터베이스를 자동으로 만들지 않습니다. 새 데이터베이스를 수동으로 만들어야 하지만 CosmosDbPartitionedStorage에서 컨테이너를 만들므로 컨테이너를 수동으로 만드는 작업은 건너뜁니다.

이제 메모리 스토리지를 사용했으므로 Azure Cosmos DB를 사용하도록 코드를 업데이트합니다. Cosmos DB는 전 세계에 배포된 Microsoft의 멀티모델 데이터베이스입니다. Azure Cosmos DB를 사용하면 여러 Azure 지리적 지역에 걸쳐 처리량 및 스토리지를 탄력적이고 독립적으로 확장할 수 있습니다. 포괄적인 SLA(서비스 수준 계약)를 통해 처리량, 대기 시간, 가용성 및 일관성을 보장합니다.

Cosmos DB 리소스 설정

봇에서 Cosmos DB를 사용하려면 코드에 들어가기 전에 데이터베이스 리소스를 만들어야 합니다. Cosmos DB 데이터베이스 및 앱 만들기에 대한 자세한 설명은 .NET, Node.js 또는 Python에 대한 빠른 시작을 참조하세요.

데이터베이스 계정 만들기

  1. Azure Portal로 이동하여 Azure Cosmos DB 계정을 만듭니다. Azure Cosmos DB를 검색하여 선택합니다.

  2. Azure Cosmos DB 페이지에서 새로 만들기를 선택하여 Azure Cosmos DB 계정 만들기 페이지를 표시합니다.

    Cosmos DB 계정을 만드는 스크린샷

  3. 다음 필드에 대한 값을 제공합니다.

    1. 구독. 이 Azure Cosmos 계정에 사용하려는 Azure 구독을 선택합니다.
    2. 리소스 그룹. 기존 리소스 그룹을 선택하거나 새로 만들기를 선택하고 새 리소스 그룹의 이름을 입력합니다.
    3. 계정 이름입니다. Azure Cosmos 계정을 식별하는 이름을 입력합니다. URI를 만들기 위해 제공하는 이름에 documents.azure.com이 추가되므로 고유한 이름을 사용합니다. 다음 지침에 유의하세요.
      • 이름은 Azure에서 고유해야 합니다.
      • 이름은 3~31자 사이여야 합니다.
      • 이름은 소문자, 숫자 및 하이픈(-) 문자만 포함할 수 있습니다.
    4. API. Core(SQL) 선택
    5. 위치. 사용자에게 가장 가까운 위치를 선택하여 데이터에 가장 빠르게 액세스할 수 있도록 합니다.
  4. 검토 + 생성를 선택합니다.

  5. 유효성 검사가 끝나면 만들기를 선택합니다.

계정 생성에는 몇 분 정도가 소요됩니다. 포털에 축하합니다! Azure Cosmos DB 계정이 만들어졌습니다 페이지가 표시될 때까지 기다리세요.

데이터베이스 추가

참고 항목

컨테이너를 직접 만들지 마세요. 봇은 내부 Cosmos DB 클라이언트를 만들 때 봇 상태를 저장하도록 올바르게 구성되도록 만듭니다.

  1. 새로 만든 Cosmos DB 계정 내의 데이터 탐색기 페이지로 이동한 다음 새 컨테이너 드롭다운에서 새 데이터베이스선택합니다. 그러면 창의 오른쪽에 패널이 열리고 새 데이터베이스에 대한 세부 정보를 입력할 수 있습니다.

    Cosmos DB 데이터베이스를 만드는 스크린샷

  2. 새 데이터베이스의 ID를 입력하고 필요에 따라 처리량을 설정하고(나중에 변경할 수 있습니다) 마지막으로 확인을 선택하여 데이터베이스를 만듭니다. 나중에 봇을 구성할 때 사용할 데이터베이스 ID를 기록해 둡니다.

  3. 이제 Cosmos DB 계정 및 데이터베이스를 만들었으므로 새 데이터베이스를 봇에 통합하기 위한 일부 값을 복사해야 합니다. 이를 검색하려면 Cosmos DB 계정의 데이터베이스 설정 섹션 내에서 키 탭으로 이동합니다. 이 페이지에서 URI(Cosmos DB 엔드포인트) 및 기본 키(권한 부여 키)가 필요합니다.

이제 데이터베이스가 있는 Cosmos DB 계정과 봇 설정에서 사용할 준비가 된 다음 값이 있어야 합니다.

  • URI
  • Primary Key
  • 데이터베이스 ID

Cosmos DB 구성 정보 추가

이 문서의 이전 부분에서 기록한 세부 정보를 사용하여 엔드포인트, 권한 부여 키 및 데이터베이스 ID를 설정합니다. 마지막으로, 봇 상태를 저장하기 위해 데이터베이스 내에 생성될 컨테이너에 대한 적절한 이름을 선택해야 합니다. 아래 예제에서 생성된 Cosmos DB 컨테이너의 이름은 "bot-storage"입니다.

구성 파일에 다음 정보를 추가합니다.

appsettings.json

"CosmosDbEndpoint": "<your-CosmosDb-URI>",
"CosmosDbAuthKey": "<your-primary-key>",
"CosmosDbDatabaseId": "<your-database-id>",
"CosmosDbContainerId": "bot-storage"

Cosmos DB 패키지 설치

Cosmos DB에 필요한 패키지가 있는지 확인합니다.

Microsoft.Bot.Builder.Azure NuGet 패키지를 설치합니다. NuGet 사용에 대한 자세한 내용은 NuGet 패키지 관리자 사용하여 Visual Studio에서 패키지 설치 및 관리를 참조하세요.

Cosmos DB 구현

참고 항목

버전 4.6에는 새로운 Cosmos DB 스토리지 공급자, Cosmos DB 분할된 스토리지 클래스가 도입되었으며, 원래의 Cosmos DB 스토리지 클래스는 더 이상 사용되지 않습니다. Cosmos DB 스토리지만든 컨테이너는 Cosmos DB 분할 스토리지와 함께 사용할 수 있습니다. 자세한 내용은 Azure Cosmos DB 분할을 읽어보세요.

레거시 Cosmos DB 스토리지와 달리 Cosmos DB 분할 스토리지는 Cosmos DB 계정 내에서 데이터베이스를 자동으로 만들지 않습니다. 새 데이터베이스를 수동으로 만들어야 하지만 CosmosDbPartitionedStorage에서 컨테이너를 만들므로 컨테이너를 수동으로 만드는 작업은 건너뜁니다.

다음 샘플 코드는 위에 나열된 예외를 제외하고 위에서 제공한 메모리 스토리지 샘플과 동일한 봇 코드를 사용하여 실행됩니다. 아래 코드 조각은 로컬 메모리 스토리지를 대체하는 'myStorage'에 대한 Cosmos DB 스토리지의 구현을 보여 줍니다.

먼저 봇 작성기 Azure 라이브러리를 참조하도록 Startup.cs 업데이트해야 합니다.

using Microsoft.Bot.Builder.Azure;

다음으로, ConfigureServices Startup.cs 메서드에서 개체를 만듭니다CosmosDbPartitionedStorage. 종속성 주입을 EchoBot 통해 생성자로 전달됩니다.

// Use partitioned CosmosDB for storage, instead of in-memory storage.
services.AddSingleton<IStorage>(
    new CosmosDbPartitionedStorage(
        new CosmosDbPartitionedStorageOptions
        {
            CosmosDbEndpoint = Configuration.GetValue<string>("CosmosDbEndpoint"),
            AuthKey = Configuration.GetValue<string>("CosmosDbAuthKey"),
            DatabaseId = Configuration.GetValue<string>("CosmosDbDatabaseId"),
            ContainerId = Configuration.GetValue<string>("CosmosDbContainerId"),
            CompatibilityMode = false,
        }));

EchoBot.cs 변수 선언 private static readonly MemoryStorage _myStorage = new MemoryStorage();_myStorage 다음으로 변경합니다.

// variable used to save user input to CosmosDb Storage.
private readonly IStorage _myStorage;

그런 다음, 개체 EchoBotIStorage 생성자에 전달합니다.

public EchoBot(IStorage storage)
{
    if (storage is null) throw new ArgumentNullException();
    _myStorage = storage;
}

Cosmos DB 봇 시작

로컬로 봇을 실행합니다.

Bot Framework Emulator를 사용하여 Cosmos DB 봇 테스트

이제 Bot Framework Emulator를 시작하고 봇에 연결합니다.

  1. 에뮬레이터 시작 탭에서 새 봇 구성 만들기 링크를 선택합니다.
  2. 봇을 시작할 때 표시되는 웹 페이지의 정보를 고려하여 필드를 채워 봇에 연결합니다.

Cosmos DB 봇과 상호 작용

봇에 메시지를 보내면 봇이 수신한 메시지를 나열합니다.

사용자의 메시지 목록을 유지하는 봇을 보여 주는 봇과의 대화입니다.

Cosmos DB 데이터 보기

봇을 실행하고 정보를 저장한 후에는 데이터 탐색기 탭에서 Azure Portal에 저장된 데이터를 볼 수 있습니다.

Azure Portal의 데이터 탐색기 스크린샷.

Blob Storage 사용

Azure Blob Storage는 클라우드를 위한 Microsoft의 개체 스토리지 솔루션입니다. Blob Storage는 텍스트 또는 이진 데이터와 같이 구조화되지 않은 대량의 데이터를 저장하는 데 최적화되어 있습니다. 이 섹션에서는 Azure Blob Storage 계정 및 컨테이너를 만든 다음, 봇에서 Blob Storage 컨테이너를 참조하는 방법을 설명합니다.

Blob Storage 에 대한 자세한 내용은 Azure Blob Storage란?

Blob Storage 계정 만들기

봇에서 Blob Storage를 사용하려면 코드에 들어가기 전에 몇 가지를 설정해야 합니다.

  1. Azure Portal에서 모든 서비스를 선택합니다.

  2. 모든 서비스 페이지의 추천 섹션에서 Storage 계정을 선택합니다.

  3. Storage 계정 페이지에서 새로 만들기를 선택합니다.

    Azure Storage 계정을 만드는 스크린샷.

  4. 구독 필드에서 스토리지 계정을 만들 구독을 선택합니다.

  5. 리소스 그룹 필드에서 기존 리소스 그룹을 선택하거나 새로 만들기를 선택하고 새 리소스 그룹의 이름을 입력합니다.

  6. 스토리지 계정 이름 필드에 계정 이름을 입력합니다. 다음 지침을 참조하세요.

    • 이름은 Azure에서 고유해야 합니다.
    • 이름은 3~24자여야 합니다.
    • 이름은 숫자와 소문자만 포함할 수 있습니다.
  7. 위치 필드에서 스토리지 계정의 위치를 선택하거나 기본 위치를 사용합니다.

  8. 나머지 설정에 대해 다음을 구성합니다.

  9. 스토리지 계정 만들기 페이지의 프로젝트 세부 정보 섹션에서 구독리소스 그룹에 대해 원하는 값을 선택합니다.

  10. 스토리지 계정 만들기 페이지의 인스턴스 세부 정보 섹션에서 스토리지 계정 이름을 입력한 다음 위치, 계정 종류복제 값을 선택합니다.

  11. 검토 + 만들기를 선택하여 스토리지 계정 설정을 검토합니다.

  12. 유효성 검사가 끝나면 만들기를 선택합니다.

Blob Storage 컨테이너 만들기

Blob Storage 계정이 만들어지면 다음을 엽니다.

  1. Storage Explorer(미리 보기)를 선택합니다.

  2. 그런 다음 BLOB 컨테이너를 마우스 오른쪽 단추로 클릭합니다.

  3. 드롭다운 목록에서 Blob 컨테이너 만들기를 선택합니다.

    Blob 컨테이너를 만드는 스크린샷.

  4. 새 컨테이너 양식에 이름을 입력합니다. "Blob 컨테이너 이름" 값에 이 이름을 사용하여 Blob Storage 계정에 대한 액세스를 제공합니다. 다음 지침을 참조하세요.

    • 이 이름은 소문자, 숫자 및 하이픈만 포함할 수 있습니다.
    • 이 이름은 문자 또는 숫자로 시작해야 합니다.
    • 각 하이픈 앞에는 유효한 하이픈이 아닌 문자가 와야 합니다.
    • 이름은 3~63자여야 합니다.

Blob Storage 구성 정보 추가

위와 같이 봇에 대한 Blob Storage를 구성하는 데 필요한 Blob Storage 키를 찾습니다.

  1. Azure Portal에서 Blob Storage 계정을 열고 설정 섹션에서 액세스 키를 선택합니다.
  2. Blob Storage 계정에 액세스하도록 봇을 구성하려면 커넥트ion 문자열을 blob 연결 문자열으로 사용합니다.

구성 파일에 다음 정보를 추가합니다.

appsettings.json

"BlobConnectionString": "<your-blob-connection-string>",
"BlobContainerName": "<your-blob-container-name>",

Blob Storage 패키지 설치

이전에 설치하지 않은 경우 다음 패키지를 설치합니다.

Microsoft.Bot.Builder.Azure.Blobs NuGet 패키지를 설치합니다. NuGet 사용에 대한 자세한 내용은 NuGet 패키지 관리자 사용하여 Visual Studio에서 패키지 설치 및 관리를 참조하세요.

Blob Storage 구현

Blob Storage 는 봇 상태를 저장하는 데 사용됩니다.

참고 항목

버전 4.10 Microsoft.Bot.Builder.Azure.AzureBlobStorage 을 기준으로 더 이상 사용되지 않습니다. 그 자리에 새 Microsoft.Bot.Builder.Azure.Blobs.BlobsStorage 것을 사용합니다.

다음 샘플 코드는 위에 나열된 예외를 제외하고 위에서 제공한 메모리 스토리지 샘플과 동일한 봇 코드를 사용하여 실행됩니다.

아래 코드 조각은 로컬 메모리 스토리지를 대체하는 'myStorage'에 대한 Blob Storage 구현을 보여 줍니다.

먼저 봇 작성기 Azure Blob 라이브러리를 참조하도록 Startup.cs 업데이트해야 합니다.

Startup.cs

using Microsoft.Bot.Builder.Azure.Blobs;

다음으로, ConfigureServices Startup.cs 메서드에서 개체를 BlobsStorage 만들어 값을 전달합니다appsettings.json. 종속성 주입을 EchoBot 통해 생성자로 전달됩니다.

//Use Azure Blob storage, instead of in-memory storage.
services.AddSingleton<IStorage>(
    new BlobsStorage(
        Configuration.GetValue<string>("BlobConnectionString"),
        Configuration.GetValue<string>("BlobContainerName")
        ));

이제 먼저 EchoBot.cs 업데이트하여 봇 작성기 Azure Blob 라이브러리를 참조해야 합니다.

EchoBot.cs

using Microsoft.Bot.Builder.Azure.Blobs;

다음으로, MemoryStorage 변수 'private static readonly MemoryStorage _myStorage = new MemoryStorage();'를 만드는 코드 줄을 제거하거나 주석 처리하고 사용자 입력을 Blob Storage에 저장하는 데 사용할 새 변수를 만듭니다.

EchoBot.cs

// variable used to save user input to CosmosDb Storage.
private readonly IStorage _myStorage;

그런 다음, 개체 EchoBotIStorage 생성자에 전달합니다.

public EchoBot(IStorage storage)
{
    if (storage is null) throw new ArgumentNullException();
    _myStorage = storage;
}

스토리지가 Blob Storage 계정을 가리키도록 설정되면 봇 코드는 이제 Blob Storage에서 데이터를 저장하고 검색합니다.

스토리지가 Blob Storage 계정을 가리키도록 설정되면 봇 코드는 이제 Blob Storage에서 데이터를 저장하고 검색합니다.

Blob Storage 봇 시작

로컬로 봇을 실행합니다.

에뮬레이터를 시작하고 Blob Storage 봇 연결

다음으로 에뮬레이터를 시작한 다음 에뮬레이터에서 봇에 연결합니다.

  1. 에뮬레이터 "시작" 탭에서 새 봇 구성 만들기 링크를 선택합니다.
  2. 봇을 시작할 때 표시되는 웹 페이지의 정보를 고려하여 필드를 채워 봇에 연결합니다.

Blob Storage 봇과 상호 작용

봇에 메시지를 보내면 봇이 받는 메시지가 나열됩니다.

사용자의 메시지 목록을 유지하는 봇을 보여 주는 봇과의 대화입니다.

Blob Storage 데이터 보기

봇을 실행하고 정보를 저장한 후에는 Azure Portal의 Storage Explorer 탭에서 볼 수 있습니다.

Blob 기록 스토리지

Azure Blob Transcript Storage는 기록된 대화 내용의 형태로 사용자 대화를 쉽게 저장하고 검색할 수 있는 특수 스토리지 옵션을 제공합니다. Azure Blob Transcript Storage는 봇의 성능을 디버깅하는 동안 검사할 사용자 입력을 자동으로 캡처하는 데 유용합니다.

참고 항목

Python은 현재 Azure Blob Transcript Storage를 지원하지 않습니다. JavaScript는 Blob Transcript Storage를 지원하지만 다음 지침은 C# 전용입니다.

Blob Transcript Storage 컨테이너 설정

Azure Blob 기록 스토리지는 위의 섹션 "Blob Storage 계정 만들기" 및 "구성 정보 추가"에 설명된 단계를 따라 만들어진 동일한 Blob Storage 계정을 사용할 수 있습니다. 이제 대본을 보관할 컨테이너를 추가합니다.

기록 저장소로 사용할 Blob 컨테이너를 만드는 스크린샷

  1. Azure Blob Storage 계정을 엽니다.
  2. Storage Explorer를 선택합니다.
  3. BLOB 컨테이너를 마우스 오른쪽 단추로 클릭하고 Blob 컨테이너 만들기를 선택합니다.
  4. 대본 컨테이너의 이름을 입력한 다음 확인을 선택합니다. (mybottranscripts를 입력했습니다 .)

Blob Transcript Storage 구현

다음 코드는 기록 스토리지 포인터 _myTranscripts를 새 Azure Blob 기록 스토리지 계정에 연결합니다. 새 컨테이너 이름인 <your-blob-transcript-container-name>을 사용하여 이 링크를 만들려면 Blob Storage 내에 기록 파일을 저장할 새 컨테이너를 만듭니다.

Blob Transcript Storage 는 봇 기록을 저장하도록 설계되었습니다.

참고 항목

버전 4.10 Microsoft.Bot.Builder.Azure.AzureBlobTranscriptStore 을 기준으로 더 이상 사용되지 않습니다. 그 자리에 새 Microsoft.Bot.Builder.Azure.Blobs.BlobsTranscriptStore 것을 사용합니다.

echoBot.cs

using Microsoft.Bot.Builder.Azure.Blobs;

public class EchoBot : ActivityHandler
{
   ...

   private readonly BlobsTranscriptStore _myTranscripts = new BlobsTranscriptStore("<your-azure-storage-connection-string>", "<your-blob-transcript-container-name>");

   ...
}

Azure Blob 대화 내용에 사용자 대화 저장

Blob 컨테이너를 사용하여 기록을 저장할 수 있게 된 후에는 봇과의 사용자 대화를 유지할 수 있습니다. 이러한 대화는 나중에 디버깅 도구로 사용하여 사용자가 봇과 상호 작용하는 방법을 확인할 수 있습니다. 각 에뮬레이터 다시 시작 대화 는 새 대본 대화 목록 만들기를 시작합니다. 다음 코드는 저장된 기록 파일 내에서 사용자 대화 입력을 유지합니다.

  • 현재 성적 증명서는 .를 사용하여 LogActivityAsync저장됩니다.
  • 저장된 대본은 .를 사용하여 ListTranscriptsAsync검색됩니다. 이 샘플 코드에서 저장된 각 기록의 ID는 "storedTranscripts"라는 목록에 저장됩니다. 이 목록은 나중에 보관하는 저장된 Blob 기록 수를 관리하는 데 사용됩니다.

echoBot.cs


protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    await _myTranscripts.LogActivityAsync(turnContext.Activity);

    List<string> storedTranscripts = new List<string>();
    PagedResult<Microsoft.Bot.Builder.TranscriptInfo> pagedResult = null;
    var pageSize = 0;
    do
    {
       pagedResult = await _myTranscripts.ListTranscriptsAsync("emulator", pagedResult?.ContinuationToken);
       pageSize = pagedResult.Items.Count();

       // transcript item contains ChannelId, Created, Id.
       // save the channelIds found by "ListTranscriptsAsync" to a local list.
       foreach (var item in pagedResult.Items)
       {
          storedTranscripts.Add(item.Id);
       }
    } while (pagedResult.ContinuationToken != null);

    ...
}

저장된 Blob 기록 관리

저장된 대본은 디버깅 도구로 사용할 수 있지만, 시간이 지남에 따라 저장된 대본의 수는 보존에 신경 쓰는 것보다 커질 수 있습니다. 아래에 포함된 추가 코드는 Blob 기록 저장소에서 검색된 마지막 세 개의 대본 항목을 제외한 모든 항목을 제거하는 데 사용됩니다 DeleteTranscriptAsync .

echoBot.cs


protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    await _myTranscripts.LogActivityAsync(turnContext.Activity);

    List<string> storedTranscripts = new List<string>();
    PagedResult<Microsoft.Bot.Builder.TranscriptInfo> pagedResult = null;
    var pageSize = 0;
    do
    {
       pagedResult = await _myTranscripts.ListTranscriptsAsync("emulator", pagedResult?.ContinuationToken);
       pageSize = pagedResult.Items.Count();

       // transcript item contains ChannelId, Created, Id.
       // save the channelIds found by "ListTranscriptsAsync" to a local list.
       foreach (var item in pagedResult.Items)
       {
          storedTranscripts.Add(item.Id);
       }
    } while (pagedResult.ContinuationToken != null);

    // Manage the size of your transcript storage.
    for (int i = 0; i < pageSize; i++)
    {
       // Remove older stored transcripts, save just the last three.
       if (i < pageSize - 3)
       {
          string thisTranscriptId = storedTranscripts[i];
          try
          {
             await _myTranscripts.DeleteTranscriptAsync("emulator", thisTranscriptId);
           }
           catch (System.Exception ex)
           {
              await turnContext.SendActivityAsync("Debug Out: DeleteTranscriptAsync had a problem!");
              await turnContext.SendActivityAsync("exception: " + ex.Message);
           }
       }
    }
    ...
}

클래스에 대한 자세한 내용은 Azure Blob Transcript Storage를 참조 하세요.

추가 정보

eTag를 사용하여 동시성 관리

봇 코드 예제에서는 각각 IStoreItem *eTag 속성을 .로 설정합니다. eTag 저장소 개체의 (엔터티 태그) 멤버는 Cosmos DB 내에서 동시성을 관리하는 데 사용됩니다. 데이터베이스는 eTag 봇의 다른 인스턴스가 봇이 작성하는 것과 동일한 스토리지의 개체를 변경한 경우 수행할 작업을 데이터베이스에 알려줍니다.

마지막 쓰기 우선 - 덮어쓰기 허용

별표(*)의 속성 값은 eTag 마지막 작성기가 승리했음을 나타냅니다. 새 데이터 저장소를 만들 때 작성 중인 데이터를 이전에 저장하지 않았거나 마지막 기록기가 이전에 저장된 속성을 * 덮어쓰도록 하려면 속성을 설정할 eTag 수 있습니다. 동시성이 봇에 문제가 되지 않는 경우 작성 중인 모든 데이터에 대해 속성을 * 설정 eTag 하면 덮어쓸 수 있습니다.

동시성을 유지 관리 및 덮어쓰기 방지

데이터를 Cosmos DB로 저장할 때 속성에 대한 동시 액세스를 방지하려면 eTag* 이외의 값을 사용하여 다른 봇 인스턴스의 변경 내용 덮어쓰기를 차단합니다. 봇은 상태 데이터를 저장하려고 할 때 메시지 etag conflict key= 와 함께 오류 응답을 수신하며 스토리지의 값 eTageTag 동일하지 않습니다.

기본적으로 Cosmos DB 저장소는 봇이 해당 항목에 쓸 때마다 스토리지 개체의 속성을 같음으로 검사 eTag 각 쓰기 후에 새 고유 값으로 업데이트합니다. 쓰기의 eTag 속성이 스토리지의 eTag와 일치하지 않은 경우 다른 봇 또는 스레드가 해당 데이터를 변경한 것입니다.

예를 들어 봇이 저장된 노트를 편집하려고 하지만 봇이 다른 봇 인스턴스가 수행한 변경 내용을 덮어쓰지 않도록 하겠습니다. 봇의 다른 인스턴스가 편집한 경우 사용자가 최신 업데이트로 버전을 편집하려고 합니다.

먼저 IStoreItem를 구현하는 클래스를 만듭니다.

EchoBot.cs

public class Note : IStoreItem
{
    public string Name { get; set; }
    public string Contents { get; set; }
    public string ETag { get; set; }
}

다음으로 스토리지 개체를 만들어 초기 노트를 만들고 저장소에 개체를 추가합니다.

EchoBot.cs

// create a note for the first time, with a non-null, non-* ETag.
var note = new Note { Name = "Shopping List", Contents = "eggs", ETag = "x" };

var changes = Dictionary<string, object>();
{
    changes.Add("Note", note);
};
await NoteStore.WriteAsync(changes, cancellationToken);

그런 다음 나중에 노트에 액세스하고 업데이트하여 스토어에서 읽은 노트 eTag 를 유지합니다.

EchoBot.cs

var note = NoteStore.ReadAsync<Note>("Note").Result?.FirstOrDefault().Value;

if (note != null)
{
    note.Contents += ", bread";
    var changes = new Dictionary<string, object>();
    {
         changes.Add("Note1", note);
    };
    await NoteStore.WriteAsync(changes, cancellationToken);
}

변경 내용을 작성하기 전에 스토어에서 메모가 업데이트된 경우 호출에서 Write 예외가 throw됩니다.

동시성을 유지하려면 항상 스토리지에서 속성을 읽은 다음, 읽은 속성을 수정하여 eTag를 유지 관리합니다. 저장소에서 사용자 데이터를 읽는 경우 응답에 eTag 속성이 포함됩니다. 데이터를 변경하고 업데이트된 데이터를 저장소에 쓴 경우 요청에 앞서 읽은 것과 동일한 값을 지정하는 eTag 속성이 포함됩니다. 그러나 해당 집합을 사용하여 개체 eTag* 작성하면 쓰기에서 다른 변경 내용을 덮어쓸 수 있습니다.

다음 단계

이제 스토리지에서 직접 읽고 쓰는 방법을 알게 되었으므로 상태 관리자를 사용하여 이를 수행하는 방법을 살펴보겠습니다.