APLICA-SE A: SDK v4
Um bot é inerentemente sem estado. Após a implantação do seu bot, talvez ele não seja executado no mesmo processo ou no mesmo computador de um turno para outro. Porém, talvez seu bot precise controlar o contexto de uma conversa, para que ele possa gerenciar seu comportamento e lembrar-se das respostas às perguntas anteriores. Os recursos de armazenamento e estado do SDK do Bot Framework permitem que você adicione um estado ao seu bot. Os bots usam o gerenciamento de estado e os objetos de armazenamento para gerenciar e manter o estado. O gerenciador de estado fornece uma camada de abstração que permite acessar propriedades de estado usando acessadores de propriedades, independentemente do tipo de armazenamento subjacente.
Observação
Para criar agentes com sua escolha de serviços de IA, orquestração e conhecimento, considere usar o SDK do Microsoft 365 Agents. O SDK de Agentes tem suporte para C#, JavaScript ou Python. Você pode saber mais sobre o SDK de Agentes em aka.ms/agents. Se você estiver procurando uma plataforma de agente baseada em SaaS, considere o Microsoft Copilot Studio. Se você tiver um bot existente criado com o SDK do Bot Framework, poderá atualizar o bot para o SDK de Agentes. Você pode examinar as principais alterações e atualizações nas orientações de migração do SDK do Bot Framework para o SDK do Agents. Os tíquetes de suporte para o SDK do Bot Framework não serão mais atendidos a partir de 31 de dezembro de 2025.
Pré-requisitos
Sobre este exemplo
Ao receber a entrada do usuário, esta amostra verifica o estado da conversa armazenada para ver se esse usuário já foi solicitado a fornecer seu nome anteriormente. Caso contrário, o nome do usuário será solicitado e essa informação será armazenada no estado do usuário. Caso seja, o nome armazenado no estado do usuário é usado para conversar com ele, e os dados de entrada, bem como a hora de recebimento e a ID do canal de entrada, são retornados ao usuário. Os valores de hora e ID do canal são recuperados dos dados da conversa do usuário e, em seguida, salvos no estado da conversa. O diagrama a seguir mostra a relação entre o bot, o perfil do usuário e as classes de dados da conversa.
Definir classes
A primeira etapa na configuração de gerenciamento de estado é definir as classes que contêm as informações a serem gerenciadas no estado do usuário e da conversa. O exemplo usado neste artigo define as seguintes classes:
- Em UserProfile.cs, você define uma classe
UserProfile
para as informações do usuário que o bot coletará.
- Em ConversationData.cs, você define uma classe
ConversationData
para controlar o estado da nossa conversa durante a coleta de informações do usuário.
Os exemplos de código a seguir mostram as definições para as classes UserProfile
e ConversationData
.
UserProfile.cs
public class UserProfile
{
public string Name { get; set; }
}
ConversationData.cs
public class ConversationData
{
// The time-stamp of the most recent incoming message.
public string Timestamp { get; set; }
// The ID of the user's channel.
public string ChannelId { get; set; }
// Track whether we have already asked the user's name
public bool PromptedUserForName { get; set; } = false;
}
Essa etapa não é necessária no JavaScript.
A primeira etapa na configuração de gerenciamento de estado é definir as classes que contêm as informações a serem gerenciadas no estado do usuário e da conversa. O exemplo usado nesse artigo define as seguintes classes:
- Em UserProfile.java, você define uma classe
UserProfile
para as informações do usuário que o bot coletará.
- Em ConversationData.java, você define uma classe
ConversationData
para controlar o estado da nossa conversa durante a coleta de informações do usuário.
Os exemplos de código a seguir mostram as definições para as classes UserProfile
e ConversationData
.
UserProfile.java
Aviso
Parece que o exemplo que você está procurando se moveu! Tenha certeza de que estamos trabalhando para resolver isso.
ConversationData.java
Aviso
Parece que o exemplo que você está procurando se moveu! Tenha certeza de que estamos trabalhando para resolver isso.
A primeira etapa na configuração de gerenciamento de estado é definir as classes que contêm as informações a serem gerenciadas no estado do usuário e da conversa. O exemplo usado neste artigo define as seguintes classes:
- O user_profile.py contém a classe
UserProfile
que armazena as informações do usuário coletadas pelo bot.
- O conversation_data.py contém a classe
ConversationData
que controla o estado da conversa durante a coleta de informações do usuário.
Os exemplos de código a seguir mostram as definições para as classes UserProfile
e ConversationData
.
user_profile.py
class UserProfile:
def __init__(self, name: str = None):
self.name = name
conversation_data.py
class ConversationData:
def __init__(
self,
timestamp: str = None,
channel_id: str = None,
prompted_for_user_name: bool = False,
):
self.timestamp = timestamp
self.channel_id = channel_id
self.prompted_for_user_name = prompted_for_user_name
Criar objetos de estado de conversa e de usuário
Em seguida, você registra o MemoryStorage
, que é usado para criar os objetos UserState
e ConversationState
. Os objetos de estado da conversa e do usuário são criados em Startup
e a dependência é injetada no construtor de bot. Outros serviços de um bot que são registrados: um provedor de credenciais, um adaptador e a implementação do bot.
Startup.cs
// {
// TypeNameHandling = TypeNameHandling.All,
// var storage = new BlobsStorage("<blob-storage-connection-string>", "bot-state");
// With a custom JSON SERIALIZER, use this instead.
// var storage = new BlobsStorage("<blob-storage-connection-string>", "bot-state", jsonSerializer);
/* END AZURE BLOB STORAGE */
Bots/StateManagementBot.cs
private BotState _conversationState;
private BotState _userState;
public StateManagementBot(ConversationState conversationState, UserState userState)
{
_conversationState = conversationState;
_userState = userState;
}
Em seguida, você registra o MemoryStorage
, que é então usado para criar os objetos UserState
e ConversationState
. Eles são criados em index.js e consumidos quando o bot é criado.
index.js
// Define state store for your bot.
// See https://aka.ms/about-bot-state to learn more about bot state.
const memoryStorage = new MemoryStorage();
// Create conversation and user state with in-memory storage provider.
const conversationState = new ConversationState(memoryStorage);
const userState = new UserState(memoryStorage);
bots/stateManagementBot.js
// The accessor names for the conversation data and user profile state property accessors.
const CONVERSATION_DATA_PROPERTY = 'conversationData';
const USER_PROFILE_PROPERTY = 'userProfile';
class StateManagementBot extends ActivityHandler {
constructor(conversationState, userState) {
super();
// Create the state property accessors for the conversation data and user profile.
this.conversationDataAccessor = conversationState.createProperty(CONVERSATION_DATA_PROPERTY);
this.userProfileAccessor = userState.createProperty(USER_PROFILE_PROPERTY);
// The state management objects for the conversation and user state.
Em seguida, você registra o StateManagementBot
em Application.java. ConversationState e UserState são fornecidos por padrão pela classe BBotDependencyConfiguration, e o Spring os injetará no método getBot.
Application.java
Aviso
Parece que o exemplo que você está procurando se moveu! Tenha certeza de que estamos trabalhando para resolver isso.
Em seguida, você registra o MemoryStorage
, que é usado para criar os objetos UserState
e ConversationState
. Eles são criados em app.py e consumidos quando o bot é criado.
app.py
CONVERSATION_STATE = ConversationState(MEMORY)
# Create Bot
BOT = StateManagementBot(CONVERSATION_STATE, USER_STATE)
# Listen for incoming requests on /api/messages.
bots/state_management_bot.py
def __init__(self, conversation_state: ConversationState, user_state: UserState):
if conversation_state is None:
raise TypeError(
"[StateManagementBot]: Missing parameter. conversation_state is required but None was given"
)
if user_state is None:
raise TypeError(
"[StateManagementBot]: Missing parameter. user_state is required but None was given"
)
self.conversation_state = conversation_state
self.user_state = user_state
self.conversation_data_accessor = self.conversation_state.create_property(
"ConversationData"
)
self.user_profile_accessor = self.user_state.create_property("UserProfile")
Adicionar acessadores de propriedade do estado
Agora você pode criar acessadores de propriedade usando o método CreateProperty
, que fornece um identificador ao objeto BotState
. Cada acessador de propriedade de estado permite que você obtenha ou defina o valor da propriedade de estado associada. Antes de usar as propriedades de estado, use cada acessador para carregar a propriedade do armazenamento e obtê-la no cache de estado. Para obter a chave de escopo corretamente associada à propriedade do estado, você pode chamar o método GetAsync
.
Bots/StateManagementBot.cs
var conversationStateAccessors = _conversationState.CreateProperty<ConversationData>(nameof(ConversationData));
var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
Agora, você pode criar acessadores de propriedade para UserState
e ConversationState
. Cada acessador de propriedade de estado permite que você obtenha ou defina o valor da propriedade de estado associada. Você usa cada acessador para carregar a propriedade associada no armazenamento e recuperar o seu estado atual contido no cache.
bots/stateManagementBot.js
constructor(conversationState, userState) {
super();
// Create the state property accessors for the conversation data and user profile.
Agora você cria acessadores de propriedade usando o método createProperty
. Cada acessador de propriedade de estado permite que você obtenha ou defina o valor da propriedade de estado associada. Antes de usar as propriedades de estado, use cada acessador para carregar a propriedade do armazenamento e obtê-la no cache de estado. Para obter a chave de escopo corretamente associada à propriedade do estado, você pode chamar o método get
.
StateManagementBot.java
Aviso
Parece que o exemplo que você está procurando se moveu! Tenha certeza de que estamos trabalhando para resolver isso.
Agora, você pode criar acessadores de propriedade para UserProfile
e ConversationData
. Cada acessador de propriedade de estado permite que você obtenha ou defina o valor da propriedade de estado associada. Você usa cada acessador para carregar a propriedade associada no armazenamento e recuperar o seu estado atual contido no cache.
bots/state_management_bot.py
self.conversation_data_accessor = self.conversation_state.create_property(
"ConversationData"
)
self.user_profile_accessor = self.user_state.create_property("UserProfile")
Estado de acesso do seu bot
As seções anteriores abordam as etapas de tempo de inicialização para adição dos acessadores de propriedade do estado ao nosso bot. Agora, você pode usar esses acessadores em tempo de execução para ler e gravar informações de estado. O código de exemplo abaixo usa o seguinte fluxo lógico:
- Se
userProfile.Name
estiver vazio e conversationData.PromptedUserForName
for true, você poderá recuperar o nome de usuário fornecido e armazená-lo no estado do usuário.
- Se
userProfile.Name
estiver vazio e conversationData.PromptedUserForName
for false, você poderá solicitar o nome de usuário.
- Se
userProfile.Name
foi armazenado anteriormente, você recupera a hora da mensagem e o ID do canal da entrada do usuário, reenvia todos os dados para o usuário e armazena os dados recuperados no estado da conversa.
Bots/StateManagementBot.cs
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
// Get the state properties from the turn context.
var conversationStateAccessors = _conversationState.CreateProperty<ConversationData>(nameof(ConversationData));
var conversationData = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationData());
var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
var userProfile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile());
if (string.IsNullOrEmpty(userProfile.Name))
{
// First time around this is set to false, so we will prompt user for name.
if (conversationData.PromptedUserForName)
{
// Set the name to what the user provided.
userProfile.Name = turnContext.Activity.Text?.Trim();
// Acknowledge that we got their name.
await turnContext.SendActivityAsync($"Thanks {userProfile.Name}. To see conversation data, type anything.");
// Reset the flag to allow the bot to go through the cycle again.
conversationData.PromptedUserForName = false;
}
else
{
// Prompt the user for their name.
await turnContext.SendActivityAsync($"What is your name?");
// Set the flag to true, so we don't prompt in the next turn.
conversationData.PromptedUserForName = true;
}
}
else
{
// Add message details to the conversation data.
// Convert saved Timestamp to local DateTimeOffset, then to string for display.
var messageTimeOffset = (DateTimeOffset)turnContext.Activity.Timestamp;
var localMessageTime = messageTimeOffset.ToLocalTime();
conversationData.Timestamp = localMessageTime.ToString();
conversationData.ChannelId = turnContext.Activity.ChannelId.ToString();
// Display state data.
await turnContext.SendActivityAsync($"{userProfile.Name} sent: {turnContext.Activity.Text}");
await turnContext.SendActivityAsync($"Message received at: {conversationData.Timestamp}");
await turnContext.SendActivityAsync($"Message received from: {conversationData.ChannelId}");
}
}
Antes de encerrar o manipulador de turno, você pode usar o método SaveChangesAsync() dos objetos de gerenciamento de estado para gravar todas as alterações no estado de volta no armazenamento.
Bots/StateManagementBot.cs
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
await base.OnTurnAsync(turnContext, cancellationToken);
// Save any state changes that might have occurred during the turn.
await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}
- Se
userProfile.Name
estiver vazio e conversationData.PromptedUserForName
for true, você poderá recuperar o nome de usuário fornecido e armazená-lo no estado do usuário.
- Se
userProfile.Name
estiver vazio e conversationData.PromptedUserForName
for false, você poderá solicitar o nome de usuário.
- Se
userProfile.Name
foi armazenado anteriormente, você recupera a hora da mensagem e o ID do canal da entrada do usuário, reenvia todos os dados para o usuário e armazena os dados recuperados no estado da conversa.
bots/stateManagementBot.js
this.userState = userState;
this.onMessage(async (turnContext, next) => {
// Get the state properties from the turn context.
const userProfile = await this.userProfileAccessor.get(turnContext, {});
const conversationData = await this.conversationDataAccessor.get(
turnContext, { promptedForUserName: false });
if (!userProfile.name) {
// First time around this is undefined, so we will prompt user for name.
if (conversationData.promptedForUserName) {
// Set the name to what the user provided.
userProfile.name = turnContext.activity.text;
// Acknowledge that we got their name.
await turnContext.sendActivity(`Thanks ${ userProfile.name }. To see conversation data, type anything.`);
// Reset the flag to allow the bot to go though the cycle again.
conversationData.promptedForUserName = false;
} else {
// Prompt the user for their name.
await turnContext.sendActivity('What is your name?');
// Set the flag to true, so we don't prompt in the next turn.
conversationData.promptedForUserName = true;
}
} else {
// Add message details to the conversation data.
conversationData.timestamp = turnContext.activity.timestamp?.toLocaleString();
conversationData.channelId = turnContext.activity.channelId;
// Display state data.
await turnContext.sendActivity(`${ userProfile.name } sent: ${ turnContext.activity.text }`);
await turnContext.sendActivity(`Message received at: ${ conversationData.timestamp }`);
await turnContext.sendActivity(`Message received from: ${ conversationData.channelId }`);
}
// By calling next() you ensure that the next BotHandler is run.
Antes de encerrar cada turno de diálogo, você pode usar o método saveChanges() dos objetos de gerenciamento de estado para persistir todas as alterações gravando o estado de volta no armazenamento.
bots/stateManagementBot.js
}
/**
* Override the ActivityHandler.run() method to save state changes after the bot logic completes.
*/
async run(context) {
await super.run(context);
// Save any state changes. The load happened during the execution of the Dialog.
await this.conversationState.saveChanges(context, false);
- Se
userProfile.getName()
estiver vazio e conversationData.getPromptedUserForName()
for true, você poderá recuperar o nome de usuário fornecido e armazená-lo no estado do usuário.
- Se
userProfile.getName()
estiver vazio e conversationData.getPromptedUserForName()
for false, você poderá solicitar o nome de usuário.
- Se
userProfile.getName()
foi armazenado anteriormente, você recupera a hora da mensagem e o ID do canal da entrada do usuário, reenvia todos os dados para o usuário e armazena os dados recuperados no estado da conversa.
StateManagementBot.java
Aviso
Parece que o exemplo que você está procurando se moveu! Tenha certeza de que estamos trabalhando para resolver isso.
Antes de encerrar o manipulador de turno, você pode usar o método saveChanges() dos objetos de gerenciamento de estado para gravar todas as alterações no estado de volta no armazenamento.
StateManagementBot.java
Aviso
Parece que o exemplo que você está procurando se moveu! Tenha certeza de que estamos trabalhando para resolver isso.
- Se
user_profile.name
estiver vazio e conversation_data.prompted_for_user_name
for true, o bot vai recuperar o nome fornecido pelo usuário e vai armazená-lo no estado do usuário.
- Se
user_profile.name
estiver vazio e conversation_data.prompted_for_user_name
for false, o bot solicitará o nome de usuário.
- Se
user_profile.name
tiver sido armazenado anteriormente, o bot vai recuperar a hora da mensagem e a ID do canal da entrada do usuário, vai ecoar os dados de volta para o usuário e vai armazenar os dados recuperados no estado da conversa.
bots/state_management_bot.py
async def on_message_activity(self, turn_context: TurnContext):
# Get the state properties from the turn context.
user_profile = await self.user_profile_accessor.get(turn_context, UserProfile)
conversation_data = await self.conversation_data_accessor.get(
turn_context, ConversationData
)
if user_profile.name is None:
# First time around this is undefined, so we will prompt user for name.
if conversation_data.prompted_for_user_name:
# Set the name to what the user provided.
user_profile.name = turn_context.activity.text
# Acknowledge that we got their name.
await turn_context.send_activity(
f"Thanks { user_profile.name }. To see conversation data, type anything."
)
# Reset the flag to allow the bot to go though the cycle again.
conversation_data.prompted_for_user_name = False
else:
# Prompt the user for their name.
await turn_context.send_activity("What is your name?")
# Set the flag to true, so we don't prompt in the next turn.
conversation_data.prompted_for_user_name = True
else:
# Add message details to the conversation data.
conversation_data.timestamp = self.__datetime_from_utc_to_local(
turn_context.activity.timestamp
)
conversation_data.channel_id = turn_context.activity.channel_id
# Display state data.
await turn_context.send_activity(
f"{ user_profile.name } sent: { turn_context.activity.text }"
)
await turn_context.send_activity(
f"Message received at: { conversation_data.timestamp }"
)
await turn_context.send_activity(
f"Message received from: { conversation_data.channel_id }"
)
Antes de cada final de turno do diálogo, o bot utiliza o método save_changes
dos objetos de gerenciamento de estado para persistir todas as alterações, gravando informações de estado no armazenamento.
bots/state_management_bot.py
async def on_turn(self, turn_context: TurnContext):
await super().on_turn(turn_context)
await self.conversation_state.save_changes(turn_context)
await self.user_state.save_changes(turn_context)
Testar seu bot
- Baixe e instale o Bot Framework Emulator mais recente
- Execute o exemplo localmente em seu computador.
Se você precisar de instruções, confira o arquivo LEIAME para C#, JavaScript, Java ou Python.
- Use o Emulator para testar seu bot de exemplo.
Este artigo descreveu como você pode adicionar estado ao seu bot. Para obter mais informações dos tópicos relacionados, confira a tabela a seguir.
Tópico |
Observações |
Privacidade |
se você pretende armazenar dados pessoais do usuário, garanta a conformidade com o Regulamento Geral sobre a Proteção de Dados. |
Gerenciamento de estado |
todas as chamadas de gerenciamento de estado são assíncronas e last-writer-wins por padrão. Na prática, você deve obter, definir e salvar o estado o mais próximo possível em seu bot. Para uma discussão sobre como implementar o bloqueio otimista, confira Implementar armazenamento personalizado para seu bot. |
Dados críticos de negócios |
Use o estado do bot para armazenar preferências, nome de usuário ou o último pedido feito, mas não o use para armazenar dados críticos de negócios. Para dados críticos, crie seus próprios componentes de armazenamento ou grave diretamente no armazenamento. |
Recognizer-Text |
o exemplo usa as bibliotecas Microsoft/Recognizer-Text para analisar e validar a entrada do usuário. Para obter mais informações, consulte a página de visão geral. |
Próximas etapas
Saiba como fazer uma série de perguntas ao usuário, validar suas respostas e salvar suas entradas.