使用活动处理程序的事件驱动聊天
本文内容
适用于 :SDK v4
活动处理程序是组织机器人聊天逻辑的一种事件驱动的方式。
每种不同类型或子类型的活动代表不同类型的对话事件。
在幕后,对于收到的任何类型的活动,机器人的轮次处理程序会调用单个活动处理程序。
例如,如果机器人收到了某个消息活动,轮次处理程序将会看到该传入的活动,并将其发送到 on message activity 活动处理程序。 生成机器人时,用于处理和响应消息的机器人逻辑将进入此 on message activity 处理程序。 同样,用于处理正在添加到聊天中的成员的逻辑将进入 on members added 处理程序,每次将成员添加到聊天时,都会调用该处理程序。
有关组织机器人逻辑的其他方法,请参阅“机器人的工作原理”中的机器人逻辑 部分。
若要实现这些处理程序的逻辑,需要在机器人中重写这些方法,如以下示例活动处理程序 部分中所示。 其中的每个处理程序没有基实现,因此,只需在重写中添加所需的逻辑。
在某些情况下,需要在轮次结束时重写基轮次处理程序,例如保存状态 。 执行此操作时,请务必先调用 await base.OnTurnAsync(turnContext, cancellationToken);
,以确保 OnTurnAsync
的基实现在其他代码之前运行。 除此之外,该基实现还负责调用剩余的活动处理程序,例如 OnMessageActivityAsync
。
JavaScript ActivityHandler
使用事件发射器和侦听程序模式。
例如,使用 onMessage
方法为消息活动注册事件侦听器。 可以注册多个侦听器。 当机器人收到了某个消息活动时,活动处理程序将会看到该传入的活动,并将其发送到每个 onMessage
活动侦听器(按照其注册顺序)。
生成机器人时,用于处理和响应消息的机器人逻辑会进入 onMessage
侦听器。 同样,用于处理正在添加到聊天中的成员的逻辑会进入 onMembersAdded
侦听器。每次将成员添加到聊天时,都会调用该侦听器。
若要添加这些侦听器,需在机器人中注册它们,如下面的机器人逻辑 部分所示。 对于每个侦听器,请包括机器人逻辑,并务必在最后调用 next()
。 调用 next()
可确保运行下一个侦听器。
确保在轮次结束之前保存状态 。 为此,可以在父项的 run
方法完成后重写活动处理程序的 run
方法并保存状态。
只有在非常规的情况下才需要重写基轮次处理程序,因此,在尝试重写时请保持谨慎。
有一个称为 onDialog
的特殊处理程序。 onDialog
处理程序在剩余的处理程序运行之后才最后运行,与特定的活动类型无关。 与使用上述所有处理程序时一样,请务必调用 next()
来确保完成剩余的过程。
若要实现这些处理程序的逻辑,需要在机器人中重写这些方法,如以下示例活动处理程序 部分中所示。 其中的每个处理程序没有基实现,因此,请在重写中添加所需的逻辑。
在某些情况下,需要在轮次结束时重写基轮次处理程序,例如保存状态 。 执行此操作时,请务必先调用 super.onTurn(turnContext);
,以确保 onTurn
的基实现在其他代码之前运行。 除此之外,该基实现还负责调用剩余的活动处理程序,例如 onMessageActivity
。
生成机器人时,用于处理和响应消息的机器人逻辑将进入此 on_message_activity
处理程序。 同样,用于处理正在添加到聊天中的成员的逻辑将进入 on_members_added
处理程序,每次将成员添加到聊天时,都会调用该处理程序。
例如,如果机器人收到了某个消息活动,轮次处理程序将会看到该传入的活动,并将其发送到 on_message_activity
活动处理程序。
若要实现这些处理程序的逻辑,需要在机器人中重写这些方法,如以下示例活动处理程序 部分中所示。 其中的每个处理程序没有基实现,因此,只需在重写中添加所需的逻辑。
在某些情况下,需要在轮次结束时重写基轮次处理程序,例如保存状态 。 执行此操作时,请务必先调用 await super().on_turn(turnContext);
,以确保 on_turn
的基实现在其他代码之前运行。 除此之外,该基实现还负责调用剩余的活动处理程序,例如 on_message_activity
。
活动处理
机器人逻辑处理来自一个或多个通道的传入活动,并在响应中生成传出活动。
主要机器人逻辑在机器人代码中定义。 若要将机器人实现为活动处理程序,请从实现 IBot
接口的 ActivityHandler
派生 bot 类。 ActivityHandler
为不同类型的活动定义各种处理程序,例如 OnMessageActivityAsync
和 OnMembersAddedAsync
。 这些方法受保护,但可将其重写,因为我们将从 ActivityHandler
派生。
ActivityHandler
中定义的处理程序为:
事件
Handler
说明
已收到任一活动类型
OnTurnAsync
根据收到的活动类型调用其他处理程序之一。
已收到消息活动
OnMessageActivityAsync
重写此方法可以处理 message
活动。
已收到聊天更新活动
OnConversationUpdateActivityAsync
收到 conversationUpdate
活动时,如果除机器人以外的成员加入或退出聊天,则调用某个处理程序。
非机器人成员加入了聊天
OnMembersAddedAsync
重写此方法可以处理加入聊天的成员。
非机器人成员退出了聊天
OnMembersRemovedAsync
重写此方法可以处理退出聊天的成员。
已收到事件活动
OnEventActivityAsync
收到 event
活动时,调用特定于事件类型的处理程序。
已收到令牌响应事件活动
OnTokenResponseEventAsync
重写此方法可以处理令牌响应事件。
已收到非令牌响应事件活动
OnEventAsync
重写此方法可以处理其他类型的事件。
已收到消息回应活动
OnMessageReactionActivityAsync
收到 messageReaction
活动时,如果已在消息中添加或删除了一个或多个回应,则调用处理程序。
消息回应已添加到消息
OnReactionsAddedAsync
重写此方法可处理添加到消息的回应。
从消息中删除了消息回应
OnReactionsRemovedAsync
重写此方法可处理从消息中删除的回应。
已收到安装更新活动
OnInstallationUpdateActivityAsync
对于 installationUpdate
活动,根据机器人是已安装还是已卸载来调用处理程序。
安装了机器人
OnInstallationUpdateAddAsync
重写此方法可以添加逻辑来确定何时在组织单位中安装了机器人。
已卸载机器人
OnInstallationUpdateRemoveAsync
重写此方法可以添加逻辑来确定何时在组织单位中卸载了机器人。
已收到其他活动类型
OnUnrecognizedActivityTypeAsync
重写此方法可以处理未经处理的任何活动类型。
这些不同的处理程序具有一个 turnContext
,用于提供有关对应于入站 HTTP 请求的传入活动的信息。 活动可以是各种类型,因此,每个处理程序在其轮次上下文参数中提供一个强类型化的活动,在大多数情况下,始终会处理 OnMessageActivityAsync
。
与在此框架的 4.x 旧版中一样,还有一个选项可以实现公共方法 OnTurnAsync
。 目前,此方法的基实现会处理错误检查,然后根据传入活动的类型调用每个特定的处理程序(例如本示例中定义的两个处理程序)。 在大多数情况下,可以不用理会该方法并使用单个处理程序,但如果你的情况要求使用 OnTurnAsync
的自定义实现,则仍可以考虑该方法。
重要
如果重写 OnTurnAsync
方法,则需要调用 base.OnTurnAsync
以获取用于调用其他所有 On<activity>Async
处理程序的基实现,或自行调用这些处理程序。 否则不会调用这些处理程序,并且不会运行该代码。
主要机器人逻辑在机器人代码中定义。 若要将机器人实现为活动处理程序,请扩展 ActivityHandler
。 ActivityHandler
为不同类型的活动定义各种事件,你可以使用特定方法(例如使用 onMessage
和 onConversationUpdate
)通过注册事件侦听器来修改机器人的行为。
使用以下方法为每种类型的事件注册侦听器:
事件
注册方法
说明
已收到任一活动类型
onTurn
注册一个侦听器,侦听何时收到活动。
已收到消息活动
onMessage
注册一个侦听器,侦听何时收到 message
活动。
已收到聊天更新活动
onConversationUpdate
注册一个侦听器,侦听何时收到 conversationUpdate
活动。
成员加入了聊天
onMembersAdded
注册一个侦听器,侦听成员(包括机器人)何时加入了聊天。
成员退出了聊天
onMembersRemoved
注册一个侦听器,侦听成员(包括机器人)何时离开了聊天。
已收到消息回应活动
onMessageReaction
注册一个侦听器,侦听何时收到 messageReaction
活动。
消息回应已添加到消息
onReactionsAdded
注册一个侦听器,侦听何时向消息添加了回应。
从消息中删除了消息回应
onReactionsRemoved
注册一个侦听器,侦听何时从消息中删除了回应。
已收到事件活动
onEvent
注册一个侦听器,侦听何时收到 event
活动。
已收到令牌响应事件活动
onTokenResponseEvent
注册一个侦听器,侦听何时收到 tokens/response
事件。
已收到安装更新活动
onInstallationUpdate
注册一个侦听器,侦听何时收到 installationUpdate
活动。
安装了机器人
onInstallationUpdateAdd
注册一个侦听器来确定何时在组织单位中安装了机器人。
已卸载机器人
onInstallationUpdateRemove
注册一个侦听器来确定何时在组织单位中卸载了机器人。
已收到其他活动类型
onUnrecognizedActivityType
注册一个侦听器,侦听何时没有为特定类型的活动定义处理程序。
活动处理程序已完成
onDialog
在任何适用的处理程序完成后调用。
从每个处理程序调用 next
延续函数,这样就可以继续进行处理。 如果未调用 next
,则活动处理结束。
主要机器人逻辑在机器人代码中定义。 若要将机器人实现为活动处理程序,请从实现 Bot
接口的 ActivityHandler
派生 bot 类。 ActivityHandler
为不同类型的活动定义各种处理程序,例如 onMessageActivity
和 onMembersAdded
。 这些方法受保护,但可将其重写,因为我们将从 ActivityHandler
派生。
ActivityHandler
中定义的处理程序为:
事件
Handler
说明
已收到任一活动类型
onTurn
根据收到的活动类型调用其他处理程序之一。
已收到消息活动
onMessageActivity
重写此方法可以处理 message
活动。
已收到聊天更新活动
onConversationUpdateActivity
收到 conversationUpdate
活动时,如果除机器人以外的成员加入或退出聊天,则调用某个处理程序。
非机器人成员加入了聊天
onMembersAdded
重写此方法可以处理加入聊天的成员。
非机器人成员退出了聊天
onMembersRemoved
重写此方法可以处理退出聊天的成员。
已收到事件活动
onEventActivity
收到 event
活动时,调用特定于事件类型的处理程序。
已收到令牌响应事件活动
onTokenResponseEvent
重写此方法可以处理令牌响应事件。
已收到非令牌响应事件活动
onEvent
重写此方法可以处理其他类型的事件。
已收到消息回应活动
onMessageReactionActivity
收到 messageReaction
活动时,如果已在消息中添加或删除了一个或多个回应,则调用处理程序。
消息回应已添加到消息
onReactionsAdded
重写此方法可处理添加到消息的回应。
从消息中删除了消息回应
onReactionsRemoved
重写此方法可处理从消息中删除的回应。
已收到安装更新活动
onInstallationUpdate
对于 installationUpdate
活动,根据机器人是已安装还是已卸载来调用处理程序。
安装了机器人
onInstallationUpdateAdd
重写此方法可以添加逻辑来确定何时在组织单位中安装了机器人。
已卸载机器人
onInstallationUpdateRemove
重写此方法可以添加逻辑来确定何时在组织单位中卸载了机器人。
已收到其他活动类型
onUnrecognizedActivityType
重写此方法可以处理未经处理的任何活动类型。
这些不同的处理程序具有一个 turnContext
,用于提供有关对应于入站 HTTP 请求的传入活动的信息。 活动可以是各种类型,因此,每个处理程序在其轮次上下文参数中提供一个强类型化的活动,在大多数情况下,始终会处理 onMessageActivity
。
还可以选择实现公共方法 onTurn
。 目前,此方法的基实现会处理错误检查,然后根据传入活动的类型调用每个特定的处理程序(例如本示例中定义的两个处理程序)。 在大多数情况下,可以不用理会该方法并使用单个处理程序,但如果你的情况要求使用 onTurn
的自定义实现,则仍可以考虑该方法。
重要
如果重写 onTurn
方法,则需要调用 super.onTurn
以获取用于调用其他所有 on<activity>
处理程序的基实现,或自行调用这些处理程序。 否则不会调用这些处理程序,并且不会运行该代码。
主要机器人逻辑在机器人代码中定义。 若要将机器人实现为活动处理程序,请从 ActivityHandler
派生 bot 类,而后者又从抽象 Bot
类派生。 ActivityHandler
为不同类型的活动定义各种处理程序,例如 on_message_activity
和 on_members_added
。 这些方法受保护,但可将其重写,因为我们将从 ActivityHandler
派生。
ActivityHandler
中定义的处理程序为:
事件
Handler
说明
已收到任一活动类型
on_turn
根据收到的活动类型调用其他处理程序之一。
已收到消息活动
on_message_activity
重写此方法可以处理 message
活动。
已收到聊天更新活动
on_conversation_update_activity
收到 conversationUpdate
活动时,如果除机器人以外的成员加入或退出聊天,则调用某个处理程序。
非机器人成员加入了聊天
on_members_added_activity
重写此方法可以处理加入聊天的成员。
非机器人成员退出了聊天
on_members_removed_activity
重写此方法可以处理退出聊天的成员。
已收到事件活动
on_event_activity
收到 event
活动时,调用特定于事件类型的处理程序。
已收到令牌响应事件活动
on_token_response_event
重写此方法可以处理令牌响应事件。
已收到非令牌响应事件活动
on_event_activity
重写此方法可以处理其他类型的事件。
已收到消息回应活动
on_message_reaction_activity
收到 messageReaction
活动时,如果已在消息中添加或删除了一个或多个回应,则调用处理程序。
消息回应已添加到消息
on_reactions_added
重写此方法可处理添加到消息的回应。
从消息中删除了消息回应
on_reactions_removed
重写此方法可处理从消息中删除的回应。
已收到安装更新活动
on_installation_update
对于 installationUpdate
活动,根据机器人是已安装还是已卸载来调用处理程序。
安装了机器人
on_installation_update_add
重写此方法可以添加逻辑来确定何时在组织单位中安装了机器人。
已卸载机器人
on_installation_update_remove
重写此方法可以添加逻辑来确定何时在组织单位中卸载了机器人。
已收到其他活动类型
on_unrecognized_activity_type
重写此方法可以处理未经处理的任何活动类型。
这些不同的处理程序具有一个 turn_context
,用于提供有关对应于入站 HTTP 请求的传入活动的信息。 活动可以是各种类型,因此,每个处理程序在其轮次上下文参数中提供一个强类型化的活动,在大多数情况下,始终会处理 on_message_activity
。
与在此框架的 4.x 旧版中一样,还有一个选项可以实现公共方法 on_turn
。 目前,此方法的基实现会处理错误检查,然后根据传入活动的类型调用每个特定的处理程序(例如本示例中定义的两个处理程序)。 在大多数情况下,可以不用理会该方法并使用单个处理程序,但如果你的情况要求使用 on_turn
的自定义实现,则仍可以考虑该方法。
重要
如果重写 on_turn
方法,则需要调用 super().on_turn
以获取用于调用其他所有 on_<activity>
处理程序的基实现,或自行调用这些处理程序。 否则不会调用这些处理程序,并且不会运行该代码。
示例活动处理程序
例如,可以处理 on members added 来欢迎用户参与聊天,并处理 on message 来复述他们发送给机器人的消息。
public class EchoBot : ActivityHandler
{
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
var replyText = $"Echo: {turnContext.Activity.Text}";
await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken);
}
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var welcomeText = "Hello and welcome!";
foreach (var member in membersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
await turnContext.SendActivityAsync(MessageFactory.Text(welcomeText, welcomeText), cancellationToken);
}
}
}
}
class EchoBot extends ActivityHandler {
constructor() {
super();
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.
this.onMessage(async (context, next) => {
const replyText = `Echo: ${ context.activity.text }`;
await context.sendActivity(MessageFactory.text(replyText, replyText));
// By calling next() you ensure that the next BotHandler is run.
await next();
});
this.onMembersAdded(async (context, next) => {
const membersAdded = context.activity.membersAdded;
const welcomeText = 'Hello and welcome!';
for (let cnt = 0; cnt < membersAdded.length; ++cnt) {
if (membersAdded[cnt].id !== context.activity.recipient.id) {
await context.sendActivity(MessageFactory.text(welcomeText, welcomeText));
}
}
// By calling next() you ensure that the next BotHandler is run.
await next();
});
}
}
public class EchoBot extends ActivityHandler {
@Override
protected CompletableFuture<Void> onMessageActivity(TurnContext turnContext) {
return turnContext.sendActivity(
MessageFactory.text("Echo: " + turnContext.getActivity().getText())
).thenApply(sendResult -> null);
}
@Override
protected CompletableFuture<Void> onMembersAdded(
List<ChannelAccount> membersAdded,
TurnContext turnContext
) {
String welcomeText = "Hello and welcome!";
return membersAdded.stream()
.filter(
member -> !StringUtils
.equals(member.getId(), turnContext.getActivity().getRecipient().getId())
).map(channel -> turnContext.sendActivity(MessageFactory.text(welcomeText, welcomeText, null)))
.collect(CompletableFutures.toFutureList()).thenApply(resourceResponses -> null);
}
}
class EchoBot(ActivityHandler):
async def on_members_added_activity(
self, members_added: [ChannelAccount], turn_context: TurnContext
):
for member in members_added:
if member.id != turn_context.activity.recipient.id:
await turn_context.send_activity("Hello and welcome!")
async def on_message_activity(self, turn_context: TurnContext):
return await turn_context.send_activity(
MessageFactory.text(f"Echo: {turn_context.activity.text}")
)
后续步骤
Microsoft Teams 通道引入了一些特定于 Teams 的活动,机器人需要支持这些活动才能正常与 Teams 配合工作。 若要了解有关开发 Microsoft Teams 机器人的重要概念,请参阅 Microsoft Teams 机器人的工作原理
活动处理程序是设计不需要跟踪轮次之间对话状态的机器人的很好方式。 对话库 提供用于管理与用户进行的长时间聊天的方式。