注释
Copilot Studio 机器人重命名为 Copilot 代理(代理或 AI 代理)。 人工代理现在更名为客户服务代表(服务代表或代表)。 在我们更新产品 UI、文档和培训内容时,您可能会遇到对新旧术语的引用。
本文介绍如何在 Azure 中对 AI 代理(代理)进行编程,以将对话路由到 Dynamics 365 联络中心中的客户服务代表(服务代表或代表)。 它还描述了如何对代理进行编程以结束对话。
重要
- 只有当代理被添加到基于推送的工作流时,代理才能接收对话。
- 咨询模式下不支持 AI 代理。
先决条件
- 您必须在 Azure 中有一个配置并与 Dynamics 365 Contact Center 集成的代理。 在集成 Azure 代理中了解详细信息
- 应启用基于技能的路由。
将对话上报给代表
在 Dynamics 365 Contact Center 中,代理可以将当前对话上报给代表。 对话的路由取决于为工作流配置的路由规则。
当对话从 AI 代理转移到代表时,当代表接受升级请求时,会自动 识别 客户和案例详细信息。 机器人使用与对话关联的 Dynamics 365 Contact Center 上下文变量路由对话。 机器人可以将上下文变量和关联值的列表与升级请求一起发送到 Dynamics 365 Contact Center。 机器人还可以设置技能查找器模型可以使用的上下文项来识别新技能并将其附加到对话的现有技能列表中。 然后,Dynamics 365 Contact Center 将使用指定的值更新上下文变量,并再次运行路由引擎。 这可确保将升级的对话路由到正确的队列。 有关上下文项和变量名称的信息,请参阅在 机器人升级或结束对话时将客户和案例链接到对话。
代表接受升级请求后,代理与客户的对话记录将在代表的对话小组件上可见。 然后,代表可以继续与客户进行对话。
注释
对话摘要对客户不可见。
结束对话
如果 Azure 机器人确定客户的问题已得到解答,或者客户不再响应,则可以选择结束对话。 机器人可以向 Dynamics 365 Contact Center 发送 EndConversation 请求。
代码示例
本部分包括可用于配置 Azure 机器人以升级和结束对话的代码示例。
- 实现命令类,以对与升级和结束对话相关的任务进行建模。
示例代码如下。
using System.Collections.Generic;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace EchoBot.OmniChannel
{
/// <summary>
/// Command types that bot can send to Omnichannel
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum CommandType
{
[EnumMember(Value = "Escalate")]
Escalate = 0,
[EnumMember(Value = "EndConversation")]
EndConversation = 1,
}
/// <summary>
/// Action
/// </summary>
[DataContract]
public class Command
{
/// <summary>
/// Type of action that bot can send to Omnichannel
/// </summary>
[DataMember(Name = "type")]
public CommandType Type { get; set; }
/// <summary>
/// Dictionary of Workstream Context variable and value pairs to be sent to Dynamics 365 Contact Center
/// </summary>
[DataMember(Name = "context")]
public Dictionary<string, object> Context { get; set; }
}
}
- 实现 Customer Service 全渠道客户端类以设置命令上下文。
示例代码如下。
using Microsoft.Bot.Schema;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace EchoBot.OmniChannel
{
/// <summary>
/// Extension class for middleware implementation management
/// </summary>
public static class OmnichannelBotClient
{
/// <summary>
/// Delivery mode of bot's reply activity
/// </summary>
private const string DeliveryMode = "deliveryMode";
/// <summary>
/// Delivery Mode value bridged
/// </summary>
private const string Bridged = "bridged";
/// <summary>
/// Custom data tag
/// </summary>
private const string Tags = "tags";
/// <summary>
/// Adds Omnichannel for Customer Service escalation context to the bot's reply activity.
/// </summary>
/// <param name="activity">Bot's reply activity</param>
/// <param name="contextVars">Omnichannel for Customer Service workstream context variable value pairs</param>
public static void AddEscalationContext(IActivity activity, Dictionary<string, object> contextVars)
{
Command command = new Command
{
Type = CommandType.Escalate,
Context = contextVars
};
string serializedString = JsonConvert.SerializeObject(command);
if (activity.ChannelData != null)
{
(activity as IActivity).ChannelData[Tags] = serializedString;
}
else
{
activity.ChannelData = new Dictionary<string, object>() { { Tags, serializedString } };
}
}
/// <summary>
/// Adds Omnichannel end conversation context to the bot's reply activity.
/// </summary>
/// <param name="activity">Bot's reply activity</param>
public static void AddEndConversationContext(IActivity activity)
{
Command command = new Command
{
Type = CommandType.EndConversation,
Context = new Dictionary<string, object>()
};
string serializedString = JsonConvert.SerializeObject(command);
if (activity.ChannelData != null)
{
(activity as IActivity).ChannelData[Tags] = serializedString;
}
else
{
activity.ChannelData = new Dictionary<string, object>() { { Tags, serializedString } };
}
}
/// <summary>
/// Sets delivery mode for bot as bridged so that Customer can see bot messages
/// </summary>
/// <param name="activity">Bot's reply activity</param>
public static void BridgeBotMessage(IActivity activity)
{
if (activity.ChannelData != null)
{
(activity as IActivity).ChannelData[DeliveryMode] = Bridged;
}
else
{
activity.ChannelData = new Dictionary<string, object>() { { DeliveryMode, Bridged } };
}
}
}
}
在 Bot ActivityHandler 类中调用相应的客户端方法。
根据您的要求更改
Escalate和EndConversation命令条件。在机器人代码中添加代码语句
OmnichannelBotClient.BridgeBotMessage(turnContext.Activity);,以将消息发送到 Customer Service 全渠道。 必须为发送给客户的每个活动消息调用此方法。
示例代码如下。
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using EchoBot.OmniChannel;
using Microsoft.Bot.Schema;
namespace Microsoft.Bot.Builder.EchoBot
{
public class EchoBot : ActivityHandler
{
/// <summary>
/// This method is called when the bot receives a message.
/// </summary>
/// <param name="turnContext">Turn Context object</param>
/// <param name="cancellationToken">CancellationToken</param>
/// <returns></returns>
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
if (turnContext.Activity.Type == ActivityTypes.Message)
{
// Replace with your own message
IActivity replyActivity = MessageFactory.Text($"Echo: {turnContext.Activity.Text}");
// Replace with your own condition for bot escalation
if (turnContext.Activity.Text.Equals("escalate", StringComparison.InvariantCultureIgnoreCase))
{
Dictionary<string, object> contextVars = new Dictionary<string, object>() { { "Bo-tHandoffTopic", "CreditCard" } };
OmnichannelBotClient.AddEscalationContext(replyActivity, contextVars);
}
// Replace with your own condition for bot end conversation
else if (turnContext.Activity.Text.Equals("endconversation", StringComparison.InvariantCultureIgnoreCase))
{
OmnichannelBotClient.AddEndConversationContext(replyActivity);
}
// Call method BridgeBotMessage for every response that needs to be delivered to the customer.
else
{
OmnichannelBotClient.BridgeBotMessage(replyActivity);
}
await turnContext.SendActivityAsync(replyActivity, cancellationToken);
}
}
/// <summary>
/// This method is called when there is a participant added to the chat.
/// </summary>
/// <param name="membersAdded">Member being added to the chat</param>
/// <param name="turnContext">TurnContext</param>
/// <param name="cancellationToken">CancellationToken</param>
/// <returns></returns>
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurn-Context<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
foreach (var member in membersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
//Set the bridge mode for every message that needs to be delivered to customer
OmnichannelBotClient.BridgeBotMessage(turnContext.Activity);
await turnContext.SendActivityAsync(MessageFactory.Text($"Welcome to Echo Bot."), cancellationToken);
}
}
}
}
}
该字典 contextVars 包含您要作为上报请求的一部分更新的所有 Customer Service 全渠道上下文变量名称值对。 这是 BotHandoffTopic 上下文变量名称, CreditCard 是上下文变量值。 如果存在规则 BotHandoffTopic 等于 CreditCar 的代表队列,则此升级的聊天将路由到该队列。
上下文变量名称的类型为 String。 上下文变量值必须是 Integer 或 String 类型,并且在升级期间应作为字典<字符串、对象> 传递。 示例代码如下。
Dictionary<string, Object> keyValues = new Dictionary<string, object>() {
{ "BotHandoffTopic", "CreditCard" },
{ "IDNumber", 101}
}
代理还可以发送升级摘要,在接受升级的聊天请求后,该摘要仅对代表可见。 要发送摘要,请在升级活动消息中适当设置活动文本。
相关信息
集成 Azure 聊天机器人
添加上下文变量
Azure 机器人服务
将机器人连接到频道
自带自定义消息传递渠道:Direct Line Bot
配置 Azure 和 Copilot Studio 机器人的最佳做法