通过 Apex 赋能 Einstein Bots,提升 Salesforce Digital Engagement 客户互动体验
背景与应用场景
在当今这个客户期望即时响应和个性化服务的时代,Digital Engagement(数字互动)已成为企业客户服务战略的核心。Salesforce 提供的 Digital Engagement 平台,整合了网页聊天 (Chat)、短信 (SMS)、WhatsApp、Facebook Messenger 等多种现代化沟通渠道,让企业能够在客户选择的平台上与他们无缝连接。而 Einstein Bots(爱因斯坦机器人)作为这一平台的前沿阵地,能够 7x24 小时自动化处理常见的客户查询,有效分担人工坐席的压力。
然而,标准的 Einstein Bots 主要擅长处理基于预设规则和知识库文章的对话流。当遇到需要处理复杂业务逻辑、查询后端系统数据或执行写操作的场景时,其能力就显得捉襟见肘。例如:
- 实时订单状态查询:客户希望输入订单号,立即获取物流信息。这需要机器人能够查询 Salesforce 内部的订单对象,甚至调用外部 ERP 系统的 API。
- 复杂案例创建:客户通过聊天反映一个产品质量问题,机器人需要根据对话内容,自动创建一个包含产品信息、问题描述和客户联系方式的 Case 记录,并关联到相应的 Account 和 Contact。
- 身份验证与授权操作:在处理敏感信息前,机器人需要验证客户身份,例如通过客户输入的会员号和手机号,查询系统数据进行匹配。
- 动态产品推荐:根据客户的浏览历史或过往购买记录,动态推荐个性化的产品或服务。
在这些场景下,我们就需要借助 Salesforce 强大的后端编程语言 Apex 来扩展 Einstein Bots 的能力。作为一名 Salesforce 开发人员,我们的核心价值之一就是通过编写高效、安全的 Apex 代码,将机器人的自动化能力与 Salesforce 平台的核心数据和业务流程深度集成,从而打造真正智能和强大的客户互动体验。
原理说明
Einstein Bots 调用 Apex 的核心机制是通过 Invocable Actions(可调用操作)实现的。Salesforce 平台允许开发人员将特定的 Apex 方法暴露给声明式工具(如 Flow Builder 和 Einstein Bot Builder)使用。这个“桥梁”就是 @InvocableMethod
注解。
整个工作流程如下:
- 开发 Apex 类:我们创建一个全局 (global) 或公共 (public) 的 Apex 类。
- 创建可调用方法:在类中,我们定义一个或多个使用
@InvocableMethod
注解的静态 (static) 方法。这个注解告诉 Salesforce 平台:“这个方法可以被机器人、流程等工具安全地调用。” - 定义输入/输出:为了结构清晰和可扩展性,最佳实践是为每个可调用方法创建内部包装类 (wrapper classes) 来定义输入参数和返回参数。方法必须接受一个输入参数列表 (
List<InputWrapper>
) 并返回一个输出参数列表 (List<OutputWrapper>
),这是为了支持批量处理,也是 Salesforce 平台设计的核心原则之一。 - 在机器人中配置:在 Einstein Bot Builder 的对话 (Dialog) 中,我们可以添加一个“操作 (Action)”元素,选择类型为 "Apex",然后就能在列表中找到我们刚刚创建的可调用方法。
- 数据传递:我们可以将机器人对话中收集到的变量(如客户输入的订单号)映射到 Apex 方法的输入参数。Apex 方法执行完毕后,其返回的输出参数可以被存储在新的机器人变量中,用于后续的对话流程(如向客户显示订单状态)。
通过这种方式,Apex 代码成为了机器人的“大脑”后台。机器人负责前端的对话交互,而 Apex 则在后端处理所有的数据查询、计算、DML 操作以及外部系统集成,两者各司其职,共同完成复杂的业务任务。
示例代码
以下是一个典型的应用场景:客户通过聊天机器人查询订单状态。我们将编写一个 Apex 类,该类提供一个可调用方法,根据传入的订单号查询订单的状态和预计送达日期。
注意:此代码示例严格遵循 Salesforce 官方文档中关于可调用方法的规范。
public with sharing class BotOrderStatusController { // 使用 @InvocableMethod 注解,将此方法暴露给机器人和流程 // label: 在 Bot Builder 中显示的方法名称 // description: 对该方法功能的详细描述,会显示给管理员 // category: 在 Bot Builder 中对操作进行分组的类别名称 @InvocableMethod(label='Get Order Status' description='Retrieves the status and estimated delivery date for a given order number.' category='Order Management') public static List<BotOutput> getOrderStatus(List<BotInput> inputs) { // 准备返回结果的列表 List<BotOutput> results = new List<BotOutput>(); // 由于 Invocable Method 设计为可批量处理,输入是一个 List // 但在机器人场景下,通常每次只会传入一个请求 if (inputs == null || inputs.isEmpty()) { return results; } String orderNumber = inputs[0].orderNumber; // 创建一个输出对象实例 BotOutput response = new BotOutput(); // 使用 try-catch 块来处理潜在的异常,例如查询无结果或数据库错误 try { // 在实际项目中,应考虑 orderNumber 字段是否建立了索引以优化查询性能 // 使用 with security_enforced 确保查询遵循当前用户的字段级安全 List<Order> orders = [SELECT Status, EstimatedDeliveryDate__c FROM Order WHERE OrderNumber = :orderNumber WITH SECURITY_ENFORCED LIMIT 1]; if (!orders.isEmpty()) { Order matchingOrder = orders[0]; response.status = matchingOrder.Status; response.estimatedDeliveryDate = matchingOrder.EstimatedDeliveryDate__c; response.isSuccess = true; } else { // 如果找不到订单,返回一个明确的提示信息 response.status = 'Order not found'; response.isSuccess = false; } } catch (Exception e) { // 如果发生任何异常,记录错误并返回失败状态 // 在生产代码中,这里应该加入更完善的日志记录机制 System.debug('Error querying order status: ' + e.getMessage()); response.status = 'An error occurred while fetching order details.'; response.isSuccess = false; } // 将处理结果添加到返回列表中 results.add(response); return results; } // 内部类,用于定义传入 Apex 方法的输入参数 // 变量使用 @InvocableVariable 注解,使其在 Bot Builder 中可见并可配置 public class BotInput { @InvocableVariable(label='Order Number' description='The order number entered by the customer.' required=true) public String orderNumber; } // 内部类,用于定义从 Apex 方法返回的输出参数 // 变量同样使用 @InvocableVariable 注解,以便机器人在后续对话中使用这些返回值 public class BotOutput { @InvocableVariable(label='Order Status' description='The current status of the order.') public String status; @InvocableVariable(label='Estimated Delivery Date' description='The estimated delivery date for the order.') public Date estimatedDeliveryDate; @InvocableVariable(label='Is Success' description='Indicates if the operation was successful.') public Boolean isSuccess; } }
注意事项
1. 权限与安全 (Permissions & Security)
机器人运行时有其特定的上下文用户。你需要确保该用户的 Profile 或 Permission Set 拥有执行此 Apex 类的权限。此外,Apex 代码中访问的任何对象(如本例中的 Order
)和字段(Status
, EstimatedDeliveryDate__c
, OrderNumber
)也需要对该用户可见。强烈建议在 SOQL 查询中使用 WITH SECURITY_ENFORCED
关键字来自动强制执行字段级和对象级安全检查。
2. Governor 限制 (Governor Limits)
每一次 Apex Action 的调用都受 Salesforce Governor 限制的约束,包括 SOQL 查询数量(100)、DML 语句数量(150)、CPU 时间等。虽然机器人单次调用通常不会触及这些限制,但在设计复杂的 Apex 逻辑时,必须始终保持代码的高效性和批量化思维,避免在循环中执行 SOQL 或 DML 操作。
3. 外部系统调用 (Callouts)
如果你的 Apex 方法需要调用外部系统的 API(例如,调用物流公司的 API 获取更详细的跟踪信息),你必须在 @InvocableMethod
注解中指定 callout=true
,即 @InvocableMethod(callout=true label='...')
。这会告诉 Salesforce 平台该方法将执行一个外部调用。请注意,执行 callout 的事务与执行 DML 操作的事务是分开的,你不能在执行了 DML 操作之后再进行 callout。
4. 错误处理 (Error Handling)
健壮的错误处理至关重要。如示例代码所示,应始终使用 try-catch
块来捕获任何潜在的异常。当错误发生时,不应让机器人崩溃或无响应,而应通过输出变量(如 isSuccess = false
和一个友好的错误消息)将失败状态明确地返回给机器人。在 Einstein Bot Builder 中,你可以基于这个 isSuccess
变量来设计不同的对话路径,一条用于成功,另一条(“失败”路径)用于向客户道歉并提供其他帮助选项,如转接人工坐席。
5. 测试覆盖率 (Test Coverage)
与所有 Apex 代码一样,用于机器人的 Apex 类也必须有至少 75% 的单元测试覆盖率才能部署到生产环境。你需要编写一个单独的测试类,模拟机器人调用该方法,并验证所有逻辑分支(包括成功和失败的场景)是否都按预期工作。
总结与最佳实践
将 Apex 与 Einstein Bots 相结合,是实现真正智能化、集成化 Digital Engagement 体验的关键。它将机器人的能力从简单的问答扩展到了能够执行复杂业务流程的虚拟助手。
作为 Salesforce 开发人员,在实践中我们应遵循以下最佳实践:
- 原子化与单一职责:让每个 Apex Action 只做一件事并且做好。例如,一个 Action 负责查询,另一个负责创建记录。这使得机器人对话流更清晰,Apex 代码也更易于维护和复用。
- 清晰的接口设计:使用内部包装类 (wrapper classes) 来定义输入和输出。为
@InvocableMethod
和@InvocableVariable
提供清晰、有意义的label
和description
,这将极大地帮助配置机器人的 Salesforce 管理员理解其功能。 - 为失败而设计:始终规划好失败路径。在 Apex 中捕获异常并返回明确的错误信息,在机器人中根据这些信息引导用户进行下一步操作。
- 文档与沟通:与负责配置机器人的管理员或咨询顾问保持密切沟通。清晰地记录你的 Apex Action 能做什么、需要什么输入、会返回什么输出,以及可能的错误情况。
通过遵循这些原则,我们可以构建出既强大又可靠的自动化解决方案,不仅能提升客户满意度,还能显著提高服务团队的运营效率,最大化 Salesforce Digital Engagement 平台的价值。
评论
发表评论