Управление состояниемManaging state

применимо к: Пакет SDK v4APPLIES TO: SDK v4

Состояние бота подчиняется тем же принципам, что и современные веб-приложения, и пакет SDK для Bot Framework предоставляет некоторые абстракции, позволяющие упростить управление состоянием.State within a bot follows the same paradigms as modern web applications, and the Bot Framework SDK provides some abstractions to make state management easier.

Как и веб-приложения, бот по своей природе не учитывает состояния. Любой экземпляр бота может обработать любой шаг беседы.As with web apps, a bot is inherently stateless; a different instance of your bot may handle any given turn of the conversation. Для некоторых программы-роботы такая простота является предпочтительной, так — как Bot может работать без дополнительной информации, или необходимая информация гарантированно находится в входящем сообщении.For some bots, this simplicity is preferred—the bot can either operate without additional information, or the information required is guaranteed to be within the incoming message. Для других пользователей состояние (например, место, в котором отключен диалог или данные, полученные ранее) требуется для того, чтобы программа Bot получила полезную беседу.For others, state (such as where the conversation left off or data previously received about the user) is necessary for the bot to have a useful conversation.

Зачем мне нужно состояние?Why do I need state?

Поддержание состояния позволяет боту повысить информативность бесед путем запоминания некоторых данных о пользователе и (или) диалогах.Maintaining state allows your bot to have more meaningful conversations by remembering certain things about a user or conversation. Например, если вы уже общались ранее с некоторым пользователем, вы можете сохранить информацию о нем и не запрашивать ее повторно.For example, if you've talked to a user previously, you can save previous information about them, so that you don't have to ask for it again. Кроме того, состояние сохраняет данные не только о последнем шаге, что позволяет боту хранить сведения о ходе многоэтапного диалога.State also keeps data for longer than the current turn, so that your bot keeps information over the course of a multi-turn conversation.

Так как он относится к программы-роботы, существует несколько уровней использования состояния: уровень хранилища, управление состоянием (содержится в Bot-состоянии на схеме ниже) и методы доступа к свойствам состояния.As it pertains to bots, there are a few layers to using state: the storage layer, state management (contained in the bot state in the diagram below), and state property accessors. На этой схеме показаны части последовательности взаимодействий этих уровней. Сплошные стрелки обозначают вызов метода, а пунктирными представлены ответы (с возвратом значения или без).This diagram illustrates parts of the interaction sequence between these layers, with the solid arrows representing a method call, and the dashed arrows representing the response (with or without a return value).

Состояние бота

Поток на этой схеме описан в следующих разделах с подробными сведениями по каждому уровню.The flow of this diagram is explained in following sections with details each of these layers.

Уровень храненияStorage layer

Начиная с серверной части, где фактически хранятся сведения о состоянии, это уровень хранилища.Starting at the backend, where the state information is actually stored, is the storage layer. Это можно рассматривать как физическое хранилище, например в памяти, Azure или на сервере стороннего производителя.This can be thought of as your physical storage, such as in-memory, Azure, or a third party server.

Пакет SDK для Bot Framework содержит несколько реализация для уровня хранилища.The Bot Framework SDK includes some implementations for the storage layer:

  • Хранилище в памяти создает хранилище в памяти для целей тестирования.Memory storage implements in-memory storage for testing purposes. Хранение данных в памяти следует использовать только для локального тестирования, так как это хранилище является временным и ненадежным.In-memory data storage is intended for local testing only as this storage is volatile and temporary. Данные очищаются при каждом перезапуске бота.The data is cleared each time the bot is restarted.
  • Хранилище BLOB-объектов подключается к базе данных хранилища больших двоичных объектов Azure.Azure Blob Storage connects to an Azure Blob Storage object database.
  • Секционированное хранилище Azure Cosmos DB подключается к секционированной базе данных Cosmos DB NoSQL.Azure Cosmos DB partitioned storage connects to a partitioned Cosmos DB NoSQL database.

Важно!

Класс хранилища Cosmos DB является устаревшим.The Cosmos DB storage class has been deprecated. Контейнеры, изначально созданные с помощью Космосдбстораже, не имели набора ключей секций и получили ключ секции по умолчанию " / _partitionKey".Containers originally created with CosmosDbStorage had no partition key set, and were given the default partition key of "/_partitionKey".

Контейнеры, созданные с помощью хранилища Cosmos DB , можно использовать с Cosmos DB секционированного хранилища.Containers created with Cosmos DB storage can be used with Cosmos DB partitioned storage. См. сведения о секционировании в Azure Cosmos DB.Read Partitioning in Azure Cosmos DB for more information.

Также обратите внимание, что, в отличие от устаревшего Cosmos DB хранения, Cosmos DB секционированного хранилища не создает базу данных в учетной записи Cosmos DB автоматически.Also note that, unlike the legacy Cosmos DB storage, the Cosmos DB partitioned storage does not automatically create a database within your Cosmos DB account. Необходимо создать новую базу данных вручную, но пропустить создание контейнера вручную, так как космосдбпартитионедстораже создаст контейнер.You need to create a new database manually, but skip manually creating a container since CosmosDbPartitionedStorage will create the container for you.

Инструкции по подключению к другим системам хранения можно найти в статье Запись данных напрямую в хранилище.For instructions on how to connect to other storage options, see write directly to storage.

Управление данными о состоянииState management

Управление состоянием автоматизирует получение и сохранение состояния бота на уровне хранилища.State management automates the reading and writing of your bot's state to the underlying storage layer. Состояние хранится в виде свойств состояния, то есть пар "ключ — значение", которые бот может считывать и записывать через объект управления состоянием, не беспокоясь о конкретной реализации.State is stored as state properties, which are effectively key-value pairs that your bot can read and write through the state management object without worrying about the specific underlying implementation. Свойства состояния определяют, как хранятся эти данные.Those state properties define how that information is stored. Например, извлекая свойство со значением определенного класса или объекта, вы заранее знаете структуру этих данных.For example, when you retrieve a property that you defined as a specific class or object, you know how that data will be structured.

Эти свойства состояния размещаются в "контейнерах" с определенной областью видимости, которые представляют собой коллекции для упорядочивания этих свойств.These state properties are lumped into scoped "buckets", which are just collections to help organize those properties. Пакет SDK поддерживает три таких "контейнера":The SDK includes three of these "buckets":

  • состояние пользователя;User state
  • состояние беседы;Conversation state
  • личное состояние беседы.Private conversation state

Все эти контейнеры являются подклассами класса bot state (состояние бота), на основе которого вы можете определить и другие типы контейнеров с другими областями действия.All of these buckets are subclasses of the bot state class, which can be derived to define other types of buckets with different scopes.

Эти предустановленные контейнеры имеют определенные области видимости.These predefined buckets are scoped to a certain visibility, depending on the bucket:

  • Состояние пользователя доступно на любом шаге, который бот выполняет в любой беседе с определенным пользователем на определенном канале.User state is available in any turn that the bot is conversing with that user on that channel, regardless of the conversation
  • Состояние беседы доступно на любом шаге конкретной беседы для любого пользователя (например, в групповой беседе).Conversation state is available in any turn in a specific conversation, regardless of user (i.e. group conversations)
  • Для личного состояния беседы область ограничивается как конкретным диалогом, так и конкретным пользователем.Private conversation state is scoped to both the specific conversation and to that specific user

Совет

Область действий для состояний беседы и пользователя ограничивается определенным каналом.Both user and conversation state are scoped by channel. Один человек, взаимодействующий с ботом через несколько каналов связи, будет восприниматься как несколько разных пользователей с разными состояниями, по числу используемых каналов.The same person using different channels to access your bot appears as different users, one for each channel, and each with a distinct user state.

В каждом из стандартных контейнеров используются ключи, определенные для пользователя, для беседы или для обоих этих объектов.The keys used for each of these predefined buckets are specific to the user and conversation, or both. При настройке значения для свойства состояния определяется внутренний ключ с информацией в контексте шага, которая позволяет правильно соотносить пользователей и беседы с контейнерами и свойствами.When setting the value of your state property, the key is defined for you internally with information contained on the turn context to ensure that each user or conversation gets placed in the correct bucket and property. Определяются следующие ключи:Specifically, the keys are defined as follows:

  • Состояние пользователя создает ключ на основе идентификатора канала (Channel Id) и идентификатора источника (From Id).The user state creates a key using the channel ID and from ID. Например: {Activity.ChannelId}/users/{Activity.From.Id}#ИмяСвойства.For example, {Activity.ChannelId}/users/{Activity.From.Id}#YourPropertyName
  • Состояние беседы создает ключ на основе идентификатора канала (Channel Id) и идентификатора общения (Conversation Id).The conversation state creates a key using the channel ID and the conversation ID. Например: {Activity.ChannelId}/conversations/{Activity.Conversation.Id}#ИмяСвойства.For example, {Activity.ChannelId}/conversations/{Activity.Conversation.Id}#YourPropertyName
  • Личное состояние беседы создает ключ на основе идентификатора канала (Channel Id), идентификатора источника (From Id) и идентификатора общения (Conversation Id).The private conversation state creates a key using the channel ID, from ID and the conversation ID. Например: {Activity.ChannelId}/conversations/{Activity.Conversation.Id}/users/{Activity.From.Id}#ИмяСвойстваFor example, {Activity.ChannelId}/conversations/{Activity.Conversation.Id}/users/{Activity.From.Id}#YourPropertyName

Использование разных типов состоянияWhen to use each type of state

С помощью сведений о состоянии беседы можно отслеживать контекст беседы, например:Conversation state is good for tracking the context of the conversation, such as:

  • задавал ли бот пользователю вопрос, и какой именно;Whether the bot asked the user a question, and which question that was
  • на какую тему ведется текущая беседа или о чем была последняя завершенная.What the current topic of conversation is, or what the last one was

С помощью сведений о состоянии пользователя можно отслеживать сведения о пользователе, например:User state is good for tracking information about the user, such as:

  • некритические сведения о пользователе, например имя и персональные предпочтения, настройки будильников и (или) оповещений;Non-critical user information, such as name and preferences, an alarm setting, or an alert preference
  • сведения о последней беседе этого пользователя с ботом.Information about the last conversation they had with the bot
    • Например, бот службы поддержки может отслеживать список продуктов, о которых пользователь задавал вопросы.For instance, a product-support bot might track which products the user has asked about.

Личное состояние беседы хорошо подходит для каналов, где поддерживаются групповые беседы, если в них есть смысл отслеживать определенные сведения о беседе и пользователе одновременно.Private conversation state is good for channels that support group conversations, but where you want to track both user and conversation specific information. Например, в боте для школьного класса можно выполнять следующие действия:For example, if you had a classroom clicker bot:

  • собирать и отображать данные об ответах каждого учащегося на определенный вопрос;The bot could aggregate and display student responses for a given question.
  • собирать сведения о результатах каждого учащегося и передавать их ему в частном порядке после каждого сеанса.The bot could aggregate each student's performance and privately relay that back to them at the end of the session.

Дополнительные сведения о предопределенных контейнерах см. в практическом руководстве по работе с состоянием.For details on using these predefined buckets, see the state how-to article.

Подключение к нескольким базам данныхConnecting to multiple databases

Если бот должен подключаться к нескольким базам данных, создайте слой хранилища для каждой из них.If your bot needs to connect to multiple databases, create a storage layer for each database. Вы можете использовать несколько баз данных, если программа-робот собирает сведения, имеющие различные требования к безопасности, параллелизму или расположению данных.You might choose to use multiple databases if your bot collects information that has different security, concurrency, or data location needs.

Для каждого слоя хранилища создайте объекты управления состоянием, которые потребуются для хранения свойств состояния.For each storage layer, create the state management objects you need to support your state properties.

Методы доступа к свойству состоянияState property accessors

Методы доступа к свойству состояния позволяют считывать и сохранять из текущего шага свойства состояния через предоставляемые методы get, set и delete.State property accessors are used to actually read or write one of your state properties, and provide get, set, and delete methods for accessing your state properties from within a turn. Чтобы создать метод доступа, укажите имя свойства. Обычно это происходит при инициализации бота.To create an accessor, you must provide the property name, which usually takes place when you're initializing your bot. Позже вы сможете использовать этот метод доступа для получения и (или) изменения свойства в состоянии бота.Then, you can use that accessor to get and manipulate that property of your bot's state.

Методы доступа позволяют пакету SDK получать состояние из базового хранилища и самостоятельно обновляют кэш состояний бота.The accessors allow the SDK to get state from the underlying storage, and update the bot's state cache for you. Кэш состояний представляет собой локальный кэш, который бот поддерживает для хранения объекта состояния и обработки чтения и записи без фактического доступа к базовому хранилищу.The state cache is a local cache maintained by your bot that stores the state object for you, allowing read and write operations without accessing the underlying storage. Если нужного состояния нет в кэше, вызванный метод доступа get получает его из хранилища и помещает в кэш.If it isn't already in the cache, calling the accessor's get method retrieves state and also places it in the cache. Полученное свойство состояния можно изменять так же, как и обычную локальную переменную.Once retrieved, the state property can be manipulated just like a local variable.

Метод доступа delete удаляет свойство из кэша, а также из базового хранилища.The accessor's delete method removes the property from the cache, and also deletes it from the underlying storage.

Важно!

При первом вызове метода доступа get ему необходимо предоставить фабричный метод, позволяющий создать объект, если он отсутствует в нужном состоянии.For the first call to an accessor's get method, you must provide a factory method to create the object if it doesn't yet exist in your state. Если фабричный метод не предоставлен, создается исключение.If no factory method is given, you will get an exception. Сведения об использовании фабричного метода можно найти в практическом руководстве по работе с состоянием.Details on how to use a factory method can be found in the state how-to article.

Чтобы сохранить изменения, внесенные в полученное свойство состояния, обновите свойство в кэше состояния.To persist any changes you make to the state property you get from the accessor, the property in the state cache must be updated. Для этого можно вызвать метод доступа set, который устанавливает значение свойства в кэше, т. е. делает новое значение доступным для чтения и (или) обновления далее на том же шаге.You can do so via a call the accessors set method, which sets the value of your property in the cache, and is available if that needs to be read or updated later in that turn. Чтобы сохранить эти данные в базовом хранилище (т. е. сделать их доступными на следующем шаге бота), необходимо сохранить состояние.To actually persist that data to the underlying storage (and thus make it available after the current turn), you must then save your state.

Как работают методы доступа к свойству состоянияHow the state property accessor methods work

Методы доступа являются основным средством для взаимодействия бота с состоянием.The accessor methods are the primary way for your bot to interact with state. Ниже описаны принцип работы и взаимодействие базовых уровней для каждого из них.How each work, and how the underlying layers interact, are as follows:

  • Метод доступа get выполняет следующее:The accessor's get method:
    • запрашивает данные из кэша состояний;Accessor requests property from the state cache.
    • Если нужное свойство находится в кэше, оно сразу возвращается.If the property is in the cache, return it. В противном случае оно извлекается из объекта управления состоянием.Otherwise, get it from the state management object. (Если в состоянии еще нет этого объекта, применяется фабричный метод, предоставленный при вызове метода доступа get.)(If it is not yet in state, use the factory method provided in the accessors get call.)
  • Метод доступа set выполняет следующее:The accessor's set method:
    • Сохраняет в кэше состояний новое значение свойства.Update the state cache with the new property value.
  • Метод save changes в объекте управления состоянием выполняет следующее:The state management object's save changes method:
    • Проверяет изменения свойства в кэше состояний.Check the changes to the property in the state cache.
    • Сохраняет нужное свойство в хранилище.Write that property to storage.

Состояние в диалоговых окнахState in dialogs

Библиотека диалоговых окон использует метод доступа к свойству состояния диалогового окна, определенный в состоянии диалога Bot, для сохранения диалогового окна диалога.The dialogs library uses a dialog state property accessor, defined on the bot's conversation state, to retain a dialog's place in the conversation. Свойство состояние диалогового окна также позволяет каждому диалоговому окну сохранять временные данные между переходами.The dialog state property also allows each dialog to store transient information in between turns.

Адаптивные диалоговые окна имеют более сложную структуру области памяти, что упрощает доступ к результатам настройки и распознавания, а также к другим элементам.Adaptive dialogs have a more elaborate memory scope structure, which makes it easier to access configuration and recognition results, among other things. Диспетчер диалоговых окон использует объекты управления пользователя и состояния диалога для предоставления этих областей памяти.The dialog manager uses the user and conversation state management objects to provide these memory scopes.

Дополнительные сведения о библиотеке диалогов см. в статье Библиотека диалоговых окон.For information about the dialogs library, see the dialogs library article.

Сохранение состоянияSaving state

Если вы вызываете метод доступа set для сохранения обновленного состояния, свойство состояния не сохраняется в постоянное хранилище, а обновляется только в кэше состояний вашего бота.When you call the accessor's set method to record the updated state, that state property has not yet been saved to your persisted storage, and instead is only saved to your bot's state cache. Чтобы сохранить в постоянное хранилище все внесенные в кэше изменения, следует вызвать метод save changes в объекте управления состоянием, который доступен через вышеупомянутую реализацию класса состояния бота (например, состояния пользователя или состояния беседы).To save any changes in the state cache to your persisted state, you must call the state management object's save changes method, which is available on the implementation of the bot state class mentioned above (such as user state or conversation state).

Вызов метода сохранения изменений в объекте управления состоянием (например, для вышеупомянутых контейнеров) сохраняет в выбранный контейнер все свойства, обновленные на текущий момент в кэше состояний, но не затрагивает другие контейнеры в состоянии бота.Calling the save changes method for a state management object (i.e. the buckets mentioned above) saves all properties in the state cache that you have set up to that point for that bucket, but not for any of the other buckets you may have in your bot's state.

Совет

Состояние бота реализует подход "приоритет имеет последняя запись", т. е. последняя операция записи отменяет все ранее сохраненные состояния.Bot state implements a "last write wins" behavior, where the last write will stamp over the previously written state. Это допустимо для многих приложений, но имеет свои побочные эффекты, особенно в сценариях горизонтального масштабирования с определенным уровнем параллелизма и (или) задержек.This may work for many applications but has implications, particularly in scaled-out scenarios, where there may be some level of concurrency or latency in play.

Если у вас есть пользовательское ПО промежуточного слоя, которое может обновлять состояние после завершения обработчика шага, есть смысл управлять состоянием в этом ПО промежуточного слоя.If you have some custom middleware that might update state after your turn handler completes, consider handling state in middleware.

Дополнительные ресурсыAdditional resources