Apex Code Example: Custom Apex Action for Complex Queries

This example walks you through the end-to-end steps to implement an agent that handles complex customer questions using a custom Apex action.

This example covers end-to-end implementation of a customer service agent that can handle complex queries about product inventory. Using Apex, we will create a custom action that converts a customer question with multiple parts into an actionable SOQL query.

By setting up each component individually, you’ll gain a thorough understanding of their configuration and how they fit into the Agentforce solution stack. You’re welcome to follow along with the instructions in a Salesforce Developer org. Note that your results may vary.

In this example, we’ll use Salesforce CLI to import existing product and price data from .csv files into Salesforce standard objects Product2 and PriceBook. Then, we’ll create a custom Apex class to dynamically query our products inventory based on inputs passed by our agent. Finally, we’ll build an agent, subagent, and action to call the custom Apex class when needed.

To sign up, click here.

If you’d prefer to use a different Salesforce org, verify that it offers comparable functionality: Einstein is enabled, Agentforce is enabled, and it’s OK for you to add cases. Note that your user permissions and other org settings can affect your ability to complete all the steps in this example.

If you’re following along with the instructions and your org runs into unexpected issues, try refreshing your browser window. You can also try going back and repeating previous instructions.

  1. Log into the Salesforce Developer Edition org.

  2. From Setup, in the Quick Find box, enter einstein setup, and then select Einstein Setup and Turn on Einstein. Einstein Setup Search

  3. Search for Agentforce Agents and open it.

  4. Turn on Agentforce. Agentforce Setup Search

Our custom Apex class queries structured data inside our org. That means we need to get our data cleaned, organized, and inside the appropriate Salesforce objects. Here is the sample data we are using for this example: Link. This .csv file contains 100 furniture items with a Name, Description, SKU, Price, Color, and Weight.

We’re going to store most of our data in the Product2 object. Let’s start by creating custom fields for Color and Weight, since they aren’t included by default.

  1. From Setup, click Object Manager, then scroll down to Product (API name Product2). Object Manager Search

  2. Click Fields & Relationships, then click New. Fields and Relationships

  3. Create the Color custom field with the following settings, then save the field.

    1. Field Type: Picklist
    2. Label: Color
    3. Values: Black, White, Brown, Grey, Navy, Beige, Green, Red, Oak, Walnut
    4. On the field-level security screen, check Visible for your profile
  4. Create the Weight (kg) custom field with the following settings, then save the field.

    1. Field Type: Number
    2. Label: Weight (kg)
    3. Length: 16
    4. Decimal Places: 2
    5. On the field-level security screen, check Visible for your profile

Because we’re importing inventory data to the Product2 object, we’re restricted to using Salesforce CLI or Salesforce Data Loader. You can also create the data entries manually, but that method is too time consuming for large data sets. For this example, we’ll use Salesforce CLI.

For the rest of this section, you need to download and install Salesforce CLI: Link. All commands should be run in Command Prompt (Windows) or Terminal (Mac).

  1. Authenticate to your org. Once authenticated, you can begin making changes to the org from the command line. Run the following command and log in when prompted. Replace your-org-alias with a short, repeatable name like “inventory-org”. We’ll use this alias in place of your-org-alias for the rest of our commands.
  1. Download this import-ready version of our product data: Link. Import the inventory data to Product2 using the command below. Replace /full/path/to/product2_import.csv with the direct path to import-ready .csv file.
  1. Retrieve the Standard Pricebook ID. Copy and save the ID value that starts with “01s…”.
  1. Export the Product2 IDs. Replace /full/path/to/product2_ids.csv with the location you want to save the file.
  1. Build the PricebookEntry .csv.

    1. Open your original spreadsheet in one tab Link, and the product2_ids.csv you just exported in a second tab.
    2. Add two new columns to your original spreadsheet named: “Pricebook2Id” and “Product2Id”.
    3. Under Pricebook2Id, paste the ID value you copied in step one in every row.
    4. Sort the rows on your spreadsheet alphabetically by ProductCode, then copy the entire Id Column from product2_ids.csv and paste it in the Product2Id column.
    5. Create a brand new spreadsheet with only these four columns: Pricebook2Id, Product2Id, UnitPrice, IsActive.
    6. Copy over the respective columns from your original spreadsheet. Under IsActive, enter “true” for every row.
    7. Save the new spreadsheet as a .csv file. Your final spreadsheet should look something like this: Link.
  2. Import the PricebookEntry .csv. Replace /full/path/to/pricebook_entry_import.csv with the file path to your own final spreadsheet.

  1. From the App Launcher, enter products, then select the Products app.

  2. Change the List View to All Products. You should see 100 furniture entries. All Products

  3. Click on one of the entries. Under Details, you should see Color and Weight (kg) fields. Product Example

  4. Click Related. Click Price Books. You should see a list price for the object. Price Books Example

If you see everything, then congratulations! Your data was imported successfully.

Now we need to create the custom Apex class our agent will be using to process customer questions. We’ll add it to an agent action later.

  1. From Setup, in the Quick Find box, enter apex classes, and then select Apex Classes. Custom Apex Search

  2. Click New.

  3. Add the Apex code. See full code below. Custom Apex Code

  4. Click Save.

This code has extensive code comments explaining each section, denoted by the ”//” syntax, like this: // This is a code comment.

Now it’s time to build our agent, a custom subagent, and a custom action. The agent will connect to our customer support channel, find the new subagent when asked a question about product inventory, and invoke the action containing our custom Apex class to get an answer.

  1. From the App Launcher, enter Agent, and then select the Agentforce Studio app. Agentforce Studio Search

  2. Click New Agent.

  3. Select the Agentforce Service Agent template. Agentforce Template Select

  4. Give your agent a name, like “Furniture Helper Agent”.

  5. Select New User for the agent user record.

  6. Click Let’s Go. Name Your Agent

  1. In the Explorer, click the + icon next to subagents, then click New Subagent. Create a Subagent

  2. Give it a Subagent Name, like “Search Inventory”.

  3. Give it a Description, like “Handle all questions about products, furniture, inventory, pricing, colors, and availability.”

  4. Give it Reasoning Instructions, like: “You MUST call the ‘Search Furniture Inventory’ action for every product-related question. Pass the relevant category, color, and maxPrice values from the user’s message. Do not respond until you have received results from the action. If the action returns no results, tell the user no matching products were found.”

The subagent must explicitly instruct the agent to call an action, otherwise the agent may ignore it.

  1. In the Explorer, click the + icon next to your new subagent, then click New Action. Create an Action

  2. Give it an Action Name, like “Search Furniture Inventory”.

  3. Give it a Description, like “Searches the furniture inventory by category, color, and max price.”

The description is very important because the agent uses it to decide if it should run the action or not.

  1. For Reference Action Type, select Apex.

  2. Reference Action Category should be Invocable Method.

  3. For Reference Action, select the Apex action we created (Search Furniture Inventory) and click Create and Open. Select Reference Action

  4. Click Save to save your work.

In order for our agent to access both our inventory data and the custom Apex class, we need to give its agent user permissions in our org. Without those permissions, the agent isn’t allowed to see into our data or run any special code. See Best Practices for Agent User Permissions for more information.

  1. From Setup, in the Quick Find box, enter permission sets, and then select Permission Sets. Permission Set Search

  2. From the list, look for Agentforce Agent [your agent name] Permissions and open it. For this example, the permission set is named Agentforce Agent Furniture_Helper_Agent Permissions. Find Agent Permission Set

  3. Select Object Settings. Open Object Settings

  4. Scroll down the list until you find one of the objects your agent needs and open it. For this example, we need objects with the API names Product2, PricebookEntry, and Pricebook2.

  5. Click Edit, then check Read under Object Permissions, and Read Access for all Field Permissions. Give Read Access

  6. Repeat for all necessary objects.

  7. Click Save.

  1. Return to your custom Apex class.

  2. Click Security.

  3. Highlight your Einstein Agent User profile in Available Profiles and click Add so it moves to the Enabled Profiles list. Add Agent to Enabled Profiles

  4. Click Save.

Always test your agent thoroughly before activating it and making it available to your customers. Agenforce Builder has a suite of advanced testing features to ensure your agent behaves consistently, responsibly, and helpfully. See Preview and Test in Agentforce Builder for more information.

  1. Return to your agent in Agentforce Builder.

  2. Click Preview at the top of the canvas.

  3. Change Simulate to Live Test Mode.

  4. Ask your agent questions about the furniture inventory and evaluate the results.

    • For example, try asking “What chairs do you have under $400 that are white or grey?”
    • You can see the agent’s reasoning process in the Interaction Summary column. Test Your Agent
  5. If the results are satisfactory, you’re ready to activate your agent.

Once our agent is ready, we need to save our work and finalize the agent version. When we click Commit Version, we’re locking in the current state of the agent as version complete. Future changes will require us to create a new version, leaving the previous version intact in case we ever need to go back to it. After that, we’re ready to activate our agent and make it available to our customers.

  1. In your agent in Agentforce Builder, click Save.

  2. Click Commit Version, then click Commit Version again. You’ll need to create a new version to make further changes to your agent. Commit Version

  3. Click Activate, then click Activate again. Activate the Agent

  4. Your agent should now be live on its connected channels.