适用于:SDK v4
通常,机器人会直接向用户发送消息,以响应从用户接收的消息。 有时,机器人可能需要发送主动消息,即对并非源自用户的触发所作出的响应消息。
主动消息在各种场景中都可以发挥作用。 例如,如果用户之前已经请求机器人监控产品的价格,则机器人可以在产品价格下降了 20% 时提醒用户。 或者,如果机器人需要一些时间来编译对用户问题的响应,则可以通知用户延迟并允许会话在此期间继续。 当机器人编译完对问题的响应时,将与用户共享该信息。
本文将介绍有关机器人主动消息的一般信息。 有关 Microsoft Teams 中的主动消息的信息,请参阅
重要
Bot Framework SDK 和 Bot Framework Emulator 已在 GitHub 上存档。 项目不再更新或维护。 自 2025 年 12 月 31 日起,Bot Framework SDK 的支持票证将不再提供服务。
若要使用所选的 AI 服务、业务流程和知识生成代理,请考虑使用 Microsoft 365 代理 SDK。 代理 SDK 对 C#、JavaScript 或 Python 具有语言支持。 可以在 aka.ms/agents 了解有关代理 SDK 的详细信息。 如果现有的机器人是使用 Bot Framework SDK 生成的,则可以将机器人更新到代理 SDK。 查看 Bot Framework SDK 到代理 SDK 迁移指南的核心更改和更新。
如果要构建设计为在 Microsoft Teams 中工作的协作代理,请考虑使用 Teams SDK。 它为在 Teams 环境中运行的代理提供 Teams 特定的 API、自适应卡支持和内置 AI 协同调度功能。 可以在 Teams SDK(Teams AI 库)中了解详细信息。
如果要查找基于 SaaS 的代理平台,请考虑 Microsoft Copilot Studio。
先决条件
- 了解机器人基础知识。
- 以 C#、JavaScript、Java 或 Python 编写的主动消息示例的副本。 此示例用于解释本文中所述的主动消息。
关于主动式示例
一般而言,作为应用程序的机器人有几个层:
- 可以接受 HTTP 请求并专门支持消息传递终结点的 Web 应用程序。
- 处理与各通道连接的适配器。
- 用于处理该轮对话的处理程序,通常封装在 bot 类中,由该类负责处理机器人应用程序的对话推理。
为响应用户传入的消息,应用会调用适配器的 process activity 方法,该方法会创建一个轮次及其轮次上下文,调用中间件管道,然后再调用机器人的轮次处理程序。
若要发起主动消息,机器人应用程序需要能够接收其他输入。 用于发起主动消息的应用程序逻辑不在 SDK 的范围内。 在此示例中,除了标准的 messages 终结点外,还使用了一个 notify 终结点来触发主动轮次。
为了响应此通知终结点上的 GET 请求,应用将调用适配器的 continue conversation 方法,该方法的行为类似于 process activity 方法。 继续对话方法:
- 接收该用户的适当会话引用,以及用于主动轮次的回调方法。
- 为主动轮次创建事件活动和轮次上下文。
- 调用适配器的中间件管道。
- 调用提供的回调方法。
- 轮次上下文使用聊天引用向用户发送任何消息。
该示例包含一个机器人、一个消息终结点和一个用于向用户发送主动消息的额外终结点,如下图所示。
检索和存储对话引用
当 Bot Framework Emulator 连接到机器人时,机器人会收到两个对话更新活动。 在机器人的聊天更新活动处理程序中,会检索聊天引用并将其存储在字典中,如下所示。
Bots\ProactiveBot.cs
private void AddConversationReference(Activity activity)
{
var conversationReference = activity.GetConversationReference();
_conversationReferences.AddOrUpdate(conversationReference.User.Id, conversationReference, (key, newValue) => conversationReference);
}
protected override Task OnConversationUpdateActivityAsync(ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
AddConversationReference(turnContext.Activity as Activity);
return base.OnConversationUpdateActivityAsync(turnContext, cancellationToken);
}
会话引用包含一个 conversation 属性,用于描述活动所在的会话。 聊天包含一个 user 属性,用于列出参与聊天的用户;它还包含一个 service URL 属性,用于指示对当前活动的回复可发送到的位置。 若要向用户发送主动消息,需要有效的聊天引用。 (对于 Teams 通道,服务 URL 将映射到区域化服务器。)
注意
在现实场景中,你会将聊天引用持久保存在数据库中,而不是使用内存中的对象。
发送主动消息
第二个控制器为通知控制器,负责向用户发送主动消息。 它使用以下步骤生成主动消息。
获取要向其发送主动消息的会话引用。
调用适配器的 continue conversation 方法,并提供会话引用以及要使用的轮次处理程序委托。 (继续会话方法会为引用的会话生成轮次上下文,然后调用指定的轮次处理程序委托。)
在委托中,使用轮次上下文来发送主动消息。 在此处,委托是在通知控制器上定义的,它将主动消息发送给用户。
注意
虽然每个通道都应使用稳定的服务 URL,但该 URL 随时可能会更改。 有关服务 URL 的详细信息,请参阅“Bot Framework 活动架构”的基本活动结构和服务 URL 部分。
如果服务 URL 发生更改,以前的聊天引用将不再有效,并且调用 continue conversation 会生成错误或异常。 在这种情况下,你的机器人需要先获取该用户新的会话引用,之后才能再次发送主动消息。
Controllers\NotifyController .cs
每次请求机器人的 notify 页时,notify 控制器都会从字典中检索聊天引用。
该控制器然后使用 ContinueConversationAsync 和 BotCallback 方法来发送主动消息。
[Route("api/notify")]
[ApiController]
public class NotifyController : ControllerBase
{
private readonly IBotFrameworkHttpAdapter _adapter;
private readonly string _appId;
private readonly ConcurrentDictionary<string, ConversationReference> _conversationReferences;
public NotifyController(IBotFrameworkHttpAdapter adapter, IConfiguration configuration, ConcurrentDictionary<string, ConversationReference> conversationReferences)
{
_adapter = adapter;
_conversationReferences = conversationReferences;
_appId = configuration["MicrosoftAppId"] ?? string.Empty;
}
public async Task<IActionResult> Get()
{
foreach (var conversationReference in _conversationReferences.Values)
{
await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, conversationReference, BotCallback, default(CancellationToken));
}
// Let the caller know proactive messages have been sent
return new ContentResult()
{
Content = "<html><body><h1>Proactive messages have been sent.</h1></body></html>",
ContentType = "text/html",
StatusCode = (int)HttpStatusCode.OK,
};
}
private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken)
{
await turnContext.SendActivityAsync("proactive hello");
}
}
适配器要求提供机器人的应用 ID 才能发送主动消息。 在生产环境中,可以使用机器人的应用 ID。 若要使用 Emulator 在本地测试机器人,可以使用空字符串 ("")。
测试你的机器人
安装 Bot Framework Emulator(如果尚未安装)。
在计算机本地运行示例。
启动 Emulator 并连接到机器人。
加载到机器人的 api/notify 页面。 这会在 Emulator 中生成主动消息。
其他信息
要求
在发送主动消息之前,机器人需要一个会话引用。 机器人可以在它从用户那里收到的任何活动中检索聊天引用,但这通常需要用户至少与机器人交互一次,然后机器人才能发送主动消息。
许多通道禁止机器人向用户发送消息,除非用户至少向机器人发送过消息一次。 某些通道允许例外情况。 例如,Teams 通道允许机器人向已建立的包含该机器人的群组聊天中的个人发送主动(或一对一)消息。
设计注意事项
在机器人中实现主动消息时,不要在短时间内发送多条主动消息。 某些通道强制限制机器人向用户发送消息的频率,并且如果违反这些限制,将禁用机器人。
对于最简单的主动消息类型,机器人在触发时将消息插进对话中,而不考虑对话的当前状态或主题。 在此方案中,主动消息会中断对话的常规流。
若要更顺畅地处理通知,请考虑将通知集成到聊天流中的其他方法,例如在聊天状态中设置标志或将通知添加到队列。
关于主动式轮次
continue conversation 方法使用聊天引用和轮次回调处理程序来执行以下操作:
创建一个轮次,机器人应用程序可在其中发送主动消息。 适配器为此轮次创建一个
event活动,其名称设置为“ContinueConversation”。通过适配器的中间件管道传递该轮次。
调用轮次回调处理程序以执行自定义逻辑。
在 主动消息 示例中,轮次回调处理程序定义在通知控制器中,它会将消息直接发送到该会话,而不通过机器人的常规轮次处理程序来发送主动活动。 示例代码也不会访问或更新机器人在主动轮次中的状态。
许多机器人是有状态的,并使用状态来管理多个轮次的聊天。 当“continue conversation”方法创建轮次上下文时,该轮次将关联到正确的用户和会话状态,并且你可以将主动轮次集成到机器人的逻辑中。 如果需要机器人逻辑感知主动消息,可以通过几种方法来实现此目的。 您可以:
- 提供机器人的轮次处理程序作为轮次回调处理程序。 然后,机器人将收到“ContinueConversation”事件活动。
- 首先使用轮次回调处理程序将信息添加到轮次上下文,然后调用机器人的轮次处理程序。
在这两种情况下,你都需要设计机器人的逻辑来处理此类主动事件。