Управление состоянием
ПРИМЕНИМО К: Пакет SDK версии 4
Состояние бота подчиняется тем же принципам, что и современные веб-приложения, и пакет SDK для Bot Framework предоставляет некоторые абстракции, позволяющие упростить управление состоянием.
Как и веб-приложения, бот по своей природе не учитывает состояния. Любой экземпляр бота может обработать любой шаг беседы. Для некоторых ботов предпочтительнее использовать эту простоту: бот может работать без дополнительных сведений, или необходимая информация гарантированно будет находиться во входящем сообщении. В других случаях состояние (например, когда беседа была выключена или ранее полученные данные о пользователе) является необходимым для бота, чтобы иметь полезную беседу.
Зачем мне нужно состояние?
Поддержание состояния позволяет боту повысить информативность бесед путем запоминания некоторых данных о пользователе и (или) диалогах. Например, если вы уже общались ранее с некоторым пользователем, вы можете сохранить информацию о нем и не запрашивать ее повторно. Кроме того, состояние сохраняет данные не только о последнем шаге, что позволяет боту хранить сведения о ходе многоэтапного диалога.
В отношении ботов существует несколько уровней использования состояния: уровень хранения, управление состоянием (содержится в состоянии бота на схеме ниже) и методы доступа к свойствам состояния. На этой схеме показаны части последовательности взаимодействий этих уровней. Сплошные стрелки обозначают вызов метода, а пунктирными представлены ответы (с возвратом значения или без).
Поток на этой схеме описан в следующих разделах с подробными сведениями по каждому уровню.
Уровень хранения
Начиная с серверной части, где фактически хранятся сведения о состоянии, является уровнем хранения. Это может быть физическое хранилище, например в памяти, Azure или сторонний сервер.
Пакет SDK для Bot Framework содержит несколько реализация для уровня хранилища.
- Хранилище в памяти создает хранилище в памяти для целей тестирования. Хранение данных в памяти следует использовать только для локального тестирования, так как это хранилище является временным и ненадежным. Данные очищаются при каждом перезапуске бота.
- Хранилище BLOB-объектов подключается к базе данных хранилища больших двоичных объектов Azure.
- Секционированное хранилище Azure Cosmos DB подключается к секционированной базе данных Cosmos DB NoSQL.
Важно!
Класс хранилища Cosmos DB является устаревшим. Контейнеры, изначально созданные с помощью CosmosDbStorage, не имели ключа секции и получили ключ секции по умолчанию "/_partitionKey".
Контейнеры, созданные с помощью хранилища Cosmos DB , можно использовать с секционированием хранилища Cosmos DB. См. сведения о секционировании в Azure Cosmos DB.
Также обратите внимание, что, в отличие от устаревшего хранилища Cosmos DB, секционирование хранилища Cosmos DB не создает базу данных в учетной записи Cosmos DB автоматически. Необходимо создать новую базу данных вручную, но пропустить создание контейнера вручную, так как CosmosDbPartitionedStorage создаст контейнер.
Инструкции по подключению к другим системам хранения можно найти в статье Запись данных напрямую в хранилище.
Управление данными о состоянии
Управление состоянием автоматизирует получение и сохранение состояния бота на уровне хранилища. Состояние хранится в виде свойств состояния, то есть пар "ключ — значение", которые бот может считывать и записывать через объект управления состоянием, не беспокоясь о конкретной реализации. Свойства состояния определяют, как хранятся эти данные. Например, извлекая свойство со значением определенного класса или объекта, вы заранее знаете структуру этих данных.
Эти свойства состояния размещаются в "контейнерах" с определенной областью видимости, которые представляют собой коллекции для упорядочивания этих свойств. Пакет SDK поддерживает три таких "контейнера":
- состояние пользователя;
- состояние беседы;
- личное состояние беседы.
Все эти контейнеры являются подклассами класса bot state (состояние бота), на основе которого вы можете определить и другие типы контейнеров с другими областями действия.
Эти предустановленные контейнеры имеют определенные области видимости.
- Состояние пользователя доступно на любом шаге, который бот выполняет в любой беседе с определенным пользователем на определенном канале.
- Состояние беседы доступно в любом случае в определенной беседе, независимо от пользователя, например в групповых беседах
- Для личного состояния беседы область ограничивается как конкретным диалогом, так и конкретным пользователем.
Совет
Область действий для состояний беседы и пользователя ограничивается определенным каналом. Один человек, взаимодействующий с ботом через несколько каналов связи, будет восприниматься как несколько разных пользователей с разными состояниями, по числу используемых каналов.
В каждом из стандартных контейнеров используются ключи, определенные для пользователя, для беседы или для обоих этих объектов. При задании значения свойства состояния ключ определяется для вас внутренне с информацией, содержащейся в контексте поворота, чтобы убедиться, что каждый пользователь или беседа будут помещены в правильный контейнер и свойство. Определяются следующие ключи:
- Состояние пользователя создает ключ на основе идентификатора канала (Channel Id) и идентификатора источника (From Id). Например: {Activity.ChannelId}/users/{Activity.From.Id}#ИмяСвойства.
- Состояние беседы создает ключ на основе идентификатора канала (Channel Id) и идентификатора общения (Conversation Id). Например: {Activity.ChannelId}/conversations/{Activity.Conversation.Id}#ИмяСвойства.
- Личное состояние беседы создает ключ на основе идентификатора канала (Channel Id), идентификатора источника (From Id) и идентификатора общения (Conversation Id). Например: {Activity.ChannelId}/conversations/{Activity.Conversation.Id}/users/{Activity.From.Id}#ИмяСвойства
Использование разных типов состояния
С помощью сведений о состоянии беседы можно отслеживать контекст беседы, например:
- задавал ли бот пользователю вопрос, и какой именно;
- на какую тему ведется текущая беседа или о чем была последняя завершенная.
С помощью сведений о состоянии пользователя можно отслеживать сведения о пользователе, например:
- некритические сведения о пользователе, например имя и персональные предпочтения, настройки будильников и (или) оповещений;
- сведения о последней беседе этого пользователя с ботом.
- Например, бот службы поддержки может отслеживать список продуктов, о которых пользователь задавал вопросы.
Личное состояние беседы хорошо подходит для каналов, где поддерживаются групповые беседы, если в них есть смысл отслеживать определенные сведения о беседе и пользователе одновременно. Например, в боте для школьного класса можно выполнять следующие действия:
- собирать и отображать данные об ответах каждого учащегося на определенный вопрос;
- собирать сведения о результатах каждого учащегося и передавать их ему в частном порядке после каждого сеанса.
Дополнительные сведения о предопределенных контейнерах см. в практическом руководстве по работе с состоянием.
Подключение к нескольким базам данных
Если бот должен подключаться к нескольким базам данных, создайте слой хранилища для каждой из них. Вы можете использовать несколько баз данных, если бот собирает сведения, которые имеют разные требования к безопасности, параллелизму или расположению данных.
Для каждого слоя хранилища создайте объекты управления состоянием, которые потребуются для хранения свойств состояния.
Методы доступа к свойству состояния
Методы доступа к свойству состояния позволяют считывать и сохранять из текущего шага свойства состояния через предоставляемые методы get, set и delete. Чтобы создать метод доступа, укажите имя свойства. Обычно это происходит при инициализации бота. Позже вы сможете использовать этот метод доступа для получения и (или) изменения свойства в состоянии бота.
Методы доступа позволяют пакету SDK получать состояние из базового хранилища и самостоятельно обновляют кэш состояний бота. Кэш состояний представляет собой локальный кэш, который бот поддерживает для хранения объекта состояния и обработки чтения и записи без фактического доступа к базовому хранилищу. Если нужного состояния нет в кэше, вызванный метод доступа get получает его из хранилища и помещает в кэш. Полученное свойство состояния можно изменять так же, как и обычную локальную переменную.
Метод доступа delete удаляет свойство из кэша, а также из базового хранилища.
Важно!
При первом вызове метода доступа get ему необходимо предоставить фабричный метод, позволяющий создать объект, если он отсутствует в нужном состоянии. Если фабричные методы не заданы, вы получите исключение. Сведения об использовании фабричного метода можно найти в практическом руководстве по работе с состоянием.
Чтобы сохранить изменения, внесенные в полученное свойство состояния, обновите свойство в кэше состояния. Для этого можно вызвать метод доступа set, который устанавливает значение свойства в кэше, т. е. делает новое значение доступным для чтения и (или) обновления далее на том же шаге. Чтобы сохранить эти данные в базовом хранилище (т. е. сделать их доступными на следующем шаге бота), необходимо сохранить состояние.
Как работают методы доступа к свойству состояния
Методы доступа являются основным средством для взаимодействия бота с состоянием. Ниже описаны принцип работы и взаимодействие базовых уровней для каждого из них.
- Метод доступа get выполняет следующее:
- запрашивает данные из кэша состояний;
- Если нужное свойство находится в кэше, оно сразу возвращается. В противном случае оно извлекается из объекта управления состоянием. (Если он еще не находится в состоянии, используйте метод фабрики, предоставленный в методах доступа , получить вызов.)
- Метод доступа set выполняет следующее:
- Сохраняет в кэше состояний новое значение свойства.
- Метод save changes в объекте управления состоянием выполняет следующее:
- Проверяет изменения свойства в кэше состояний.
- Сохраняет нужное свойство в хранилище.
Состояние в диалоговых окнах
Библиотека диалогов использует метод доступа к свойству состояния диалога, определенный в состоянии беседы бота, для сохранения места диалога в беседе. Свойство состояния диалога также позволяет каждому диалогу хранить временные сведения между поворотами.
Адаптивные диалоги имеют более сложную структуру области памяти, что упрощает доступ к результатам конфигурации и распознавания, помимо прочего. Диспетчер диалогов использует объекты управления состоянием пользователя и диалога для предоставления этих областей памяти.
Сведения о библиотеке диалогов см. в статье о библиотеке диалогов .
- Сведения о компонентах и каскадных диалогах , относящихся к этим типам диалогов.
- Ознакомьтесь с введением в адаптивные диалоги и управление состоянием в статьях с адаптивными диалогами , чтобы получить сведения, относящиеся к адаптивным диалогам.
Сохранение состояния
Если вы вызываете метод доступа set для сохранения обновленного состояния, свойство состояния не сохраняется в постоянное хранилище, а обновляется только в кэше состояний вашего бота. Чтобы сохранить в постоянное хранилище все внесенные в кэше изменения, следует вызвать метод save changes в объекте управления состоянием, который доступен через вышеупомянутую реализацию класса состояния бота (например, состояния пользователя или состояния беседы).
Вызов метода сохранения изменений для объекта управления состоянием (например, контейнеров, упомянутых выше) сохраняет все свойства в кэше состояний, который вы настроили до этой точки для этого контейнера, но не для других контейнеров, которые могут быть в состоянии бота.
Совет
Состояние бота реализует подход "приоритет имеет последняя запись", т. е. последняя операция записи отменяет все ранее сохраненные состояния. Это допустимо для многих приложений, но имеет свои побочные эффекты, особенно в сценариях горизонтального масштабирования с определенным уровнем параллелизма и (или) задержек.
Если у вас есть пользовательское ПО промежуточного слоя, которое может обновлять состояние после завершения обработчика шага, есть смысл управлять состоянием в этом ПО промежуточного слоя.