Sunil Bhardwaj
10 min readJun 27, 2023

Preparatory Notes for The Einstein AI Next Best Action Accredited Professional exam

Einstein AI Fundamentals — Please refer to the related section on the following story — https://rb.gy/ix8ad

Einstein AI Next Best Action: Advanced Topics

Recommendation Automation with Einstein Next Best Action

  1. Harness the Power of Generate, Enhance, and Map

There are a couple of things in particular you should probably have under your belt before you begin.

  • First, you should probably have at least some Apex coding background.
  • Second, you should be familiar with Einstein Prediction Builder and Next Best Action.
  • Third, we describe using Flow Builder.

In brief, theprocess is:

  1. You define and Einstein builds a prediction (for example, how likely a customer is to pay a bill).
  2. You create recommendations (for example, “Send payment reminder”).
  3. You create a strategy that automatically sorts and filters the recommendations and assigns them to objects (such as Contacts), based on predictions.

Generate, Enhance, and Map to the Rescue

  • Use Next Best Action’s Generate element to create recommendations on the fly, either from a Salesforce object (an Account, for example) or an external source, such as a SQL database or a company product catalog.
  • The Enhance element can dynamically modify a recommendation. For example, if a given product is no longer available, recommendations are automatically updated.
  • You might discount the price of a bike with the Enhance element, but that discount won’t show up on a Contact page unless you can connect the price in the recommendation to your existing flow. Here, you’ll also see how to use the Map element to modify or create fields in recommendations and then map them to variables in flows.
Generalized view of using Generate, Enhance, and Map together

2. Automatically Create Recommendations with Generate

Sign up for a free Developer Edition org with Einstein Next Best Action and Einstein Prediction Builder.

Apex Classes for Generate

Now, you could create a set of recommendations by hand . . . for example, a recommendation for each bicycle (“Buy the ElectroMateo 3000”) with an associated action and purchase price, and have Einstein Prediction Builder assign a recommendation to each user in your Contacts list. However, it’s a lot easier to let the Generate element of Einstein Next Best Action create the recommendations for you.

The code below shows an example of how to generate recommendations. In this case, it takes input from a bike catalog and assigns suggested bicycles to customers. To do so, it has two global Apex classes, BikeRecommendationGenerator and BikeRecommendationGenerateRequest.

  • BikeRecommendationGenerateRequest sets a global invocable variable, contactID, which corresponds to the Contact ID label passed to it by the Generate element (as you’ll see below).
  • BikeRecommendationGenerator includes an invocable method called getBikes. getBikes takes input passed to it by the Generate element and returns a list of lists of recommendations. For each contact, BikeRecommedationGenerator either assigns bikes based on the customer’s preferences, or, if the customer has no preference, displays all the available bikes. It also populates custom fields you’ve added to the Recommendation object: Name, Description, and Price of the bike.

Class: BikeRecommendationGenerator

global class BikeRecommendationGenerator {
@InvocableMethod(
label=’Bike Recommendation Generator’
description=’This function returns recommendations for the bikes in our catalog.’)
global static List<List<Recommendation>> getBikes(List<BikeRecommendationGenerateRequest> inputRequests){
List<List<Recommendation>> outputs = new List<List<Recommendation>>();
for (BikeRecommendationGenerateRequest inputRequest : inputRequests)
{
Contact currentContact = [SELECT Bike_Type_Interest__c FROM Contact WHERE Id=:inputRequest.contactId];
List<Product2> products;
if (currentContact!=null && currentContact.Bike_Type_Interest__c!=’’)
{
//If we know the type of bike this customer likes, let’s recommend one of those
products = [SELECT Name, Description,Price__c FROM Product2 WHERE Family=:currentContact.Bike_Type_Interest__c];
} else {
//Otherwise grab all the bikes we have in stock
products = [SELECT Name, Description,Price__c FROM Product2];
}
List<Recommendation> recs = new List<Recommendation>();
for (Product2 prod:products) {
Recommendation rec = new Recommendation(
Name = prod.Name,
Description = prod.Description,
Price__c = prod.Price__c,
ActionReference = ‘Purchase_A_Bike’,
AcceptanceLabel = ‘Buy’
);
recs.add(rec);
}
outputs.add(recs);
}
return outputs;
}
global class BikeRecommendationGenerateRequest {
@InvocableVariable(label=’Contact ID’)
global String contactId;
}
}

The following requirements are true for both the Generate and the Enhance elements.

  • They require an Apex action marked as an invocable method.

@InvocableMethod(
label=’Bike Recommendation Generator’
description=’This function returns recommendations for the bikes in our catalog.’)

  • They can pass any number of inputs to the Apex action, either as lists or as a list of lists of primitives, sObjects, and user-defined Apex objects. To provide more than one input, the input parameter must be a list or a list of lists of a user-defined Apex object (in this case, a custom class called BikeRecommendationGenerateRequest).

global static List<List<Recommendation>> getBikes(List<BikeRecommendationGenerateRequest> inputRequests)


global class BikeRecommendationGenerateRequest {
@InvocableVariable(label=’Contact ID’)
global String contactId;
}

  • They return a list of recommendations. Invocable methods support returning either a list of an sObject type or a list of lists of an sObject type. As both Generate and Enhance operate on a list of recommendations and not a single recommendation, the method must return a List<List<Recommendation>>.

global static List<List<Recommendation>> getBikes(List<BikeRecommendationGenerateRequest> inputRequests){

Add Generate to Your Strategy

Once you create the Apex classes, you create a strategy with a Generate element.

Steps: Setup >> Type Next Best Action in the Quick Find Box >> Next Best Action >> Click New Strategy to bring up Strategy Builder >> Name your strategy NBA >> In the Objects Where Recommendations Display field, enter Contact >> Done.

  1. Name the Generate element.

2. Connect the Generate element to the Apex class you created (BikeRecommendationGenerator) by entering Bike Recommendation Generator as the Apex Action.

3. As mentioned, this action expects input with a label Contact ID, which you set to the ID of the Contact ($Record.Id).

4. Click Done and Save.

Now getBikes will, for each contact that Generate sends to it, look up bikes in a catalog and produce a recommendation for that contact. That recommendation includes one or more bikes and its name, description, and price.

Let’s test the strategy by clicking Test. In the Contact field, search for and select Abagail Minci.

Sure enough, you’ve got some recommendations.

3. Automatically Modify Recommendations with Enhance

Apex Classes for Enhance

The code below shows an example of how to enhance recommendations. In this case, it looks at contacts passed to it and applies a discount when applicable. To do so, it has two Apex classes.

  1. The Enhance element IsVeloStarsMember passes a value which indicates whether or not each contact is a member of the VeloStars program. BikeRecommendationEnhanceRequest uses this information to set one global invocable variable, IsVeloStarsMember, and create another, recommendation.
  2. BikeRecommendationEnhance includes an invocable method called applyDiscounts.
  • applyDiscounts looks at the value of the global variable IsVeloStarsMember, set by BikeRecommendationEnhanceRequest.
  • If IsVeloStarsMember is true, applyDiscounts adjusts the value of the Price field in the associated recommendation.
  • applyDiscounts returns the updated recommendation.

global class BikeRecommendationEnhance {
@InvocableMethod(label=’Apply bike discounts for members’
description=’This function is meant to be used in an Enhance node in Einstein Next Best Action’)
global static List<List<Recommendation>> applyDiscounts(List<BikeRecommendationEnhanceRequest> inputRequests) {
List<List<Recommendation>> outputs = new List<List<Recommendation>>();
for (BikeRecommendationEnhanceRequest inputRequest : inputRequests)
{
List<Recommendation> singleRequestOutputs = new List<Recommendation>();
for (Recommendation inputRecommendation : inputRequest.recommendations)
{
if (inputRequest.isVelostarsMember)
{
//Apply a 10% discount for members
inputRecommendation.Price__c = inputRecommendation.Price__c * 0.9;
}
Integer price = inputRecommendation.Price__c.intValue();
//Adjust the description to include the price
inputRecommendation.Description = inputRecommendation.Description + ‘ $’ + price;
singleRequestOutputs.add(inputRecommendation);
}
outputs.add(singleRequestOutputs);
}
return outputs;
}
global class BikeRecommendationEnhanceRequest {
@InvocableVariable(label=’Is VeloStars Member?’)
global Boolean isVelostarsMember;
@InvocableVariable
global List<Recommendation> recommendations;
}
}

The Enhance element has the following requirements.

  • It requires an Apex action marked as an invocable method.
  • It can pass any number of inputs to the Apex action, either as lists or as a list of lists of primitives, sObjects, and user-defined Apex objects. To provide more than one input, the input parameter must be a list or a list of lists of a user-defined Apex object (in this case, a custom class called BikeRecommendationEnhance).
  • It returns a list of recommendations. Invocable methods support returning either a list of an sObject type or a list of lists of an sObject type. As both Generate and Enhance operate on a list of recommendations and not a single recommendation, the method must return a List<List<Recommendation>>.

Add Enhance to Your Strategy

In Strategy Builder, add an Enhance element to create the world’s second-simplest strategy.

Steps: Setup >> Type Next Best Action in the Quick Find box and select Next Best Action >> Select the NBA for Bike Purchase strategy that you created earlier >> Drag an Enhance element onto the Strategy Builder window. >> For Label, enter Apply Membership Discount >>For Apex Action, select Apply bike discounts for members >> For the Is VeloStars Member? field, enter $Record.VeloStars_Member__c

Click Done >> Rearrange the elements to that the strategy flows from Generate to Enhance to Output, and click Save. >> Then click Test >> Select the Contact Abagail Minci.

Enhance provides the value of the VeloStars Member field for each Contact; that is, whether this customer is a VeloStars member or not. If so, the applyDiscounts method adjusts the price field in the appropriate recommendation.

When you test your strategy, you see that a 10% discount on bike prices has indeed been applied to Abagail Minci, a VeloStars member. Before using Enhance, the price of the StreetMateo 2000 (a favorite of cyclists who prefer bikes with two — and only two — wheels) was $1000 for Abagail, and after Enhance, it’s ($900).

4. Map Data from Recommendations to Flows with Map

Add a Variable to a Flow

Fortunately, you can create a price variable in a flow, and then use Map to map the Price field in our recommendations to that variable. That flow’s price is what is ultimately displayed when you click Buy.

Let’s display the discounted price for VeloStarts members. You already have a custom Price field in the Recommendation object.

That’s the field you want to update. To do so, you’ll need to create a flow with a global variable that will be functionally parallel to the Price field in the recommendation, and then map that variable to the Price field.

Start by going to Flow Builder.

Steps: From Setup, type Flow into the Quick Find box and click Flows >> New Flow and Create >> Click the Manager tab >> Click New Resource.

For Resource Types, create a Variable called PurchasePrice with a Currency data type >> Select the Available for input and Available for output checkboxes >> Click Done >> Now that you’ve created a global variable, hover over o in the flow and click + to open the Add Element panel. Click Screen to bring up the New Screen dialogue.

In the Label box of the Screen Properties panel, name the screen Purchase a Bike. >> Click Currency to add a Currency component and name it Purchase Price. >> From the Default Value drop-down menu, set the value of Purchase Price to PurchasePrice (the variable that you created). Check the Required checkbox, and set the Decimal Places to 2. >> Click Done >> Save the flow as Purchase Bike.

Here’s your Purchase Bike flow.

Map That Price!

Now your flow is set, and you have a global price variable to go with it. It’s time to map the variable to the Price field in the recommendation. To do so, set up your Map element in Strategy Builder.

  1. Return to the Next Best Action — Strategy Builder screen. If you closed that view, you can get back to it by entering Next Best Action in the Setup screen’s Quick Find box and clicking Next Best Action.
  2. Select your NBA strategy under the My Strategy list.
  3. Drag a Map element onto the Strategy Builder main window to open up the Map editing window.

4. Name the map Purchase Price.

5. Under Map Values to Fields, enter:

  • Name: PurchasePrice
  • Value: Price__c
  • Type: Currency

6. Save it by clicking Done.

7. Make sure the strategy flows from Generate to Enhance to Map to Output, moving the elements if necessary. Here’s what your full strategy looks like.

Now it’s time to check your work. Back on a Contact page, find the Next Best Action pane and click Buy.

The discounted price produced by the Enhance element now shows up when you click the Buy button. Einstein is offering lucky VeloStars Club member Abagail Minci the amazing StreetMateo 3000 for $2250 — a 10% discount on the normal price of $2500.

*************************************************************************

Happy Learning! ✍️

Please follow me at Twitter : https://www.twitter.com/sunilbhardwaj1

LinkedIn : https://www.linkedin.com/in/sunilbhardwaj10

References:

Sunil Bhardwaj

I'm Salesforce CRM Analytics Ambassador (2023 & 2022). I'm working with HCL as Salesforce Lead Consultant. I always enjoy helping people & being a Trailblazer!