If you've been keeping up with the latest AI releases, you've probably realized that Salesforce Prompt Templates are the backbone of any real-world AI implementation. It's one thing to play around in a playground, but it's another thing entirely to build these into your actual UI.
I've seen plenty of teams try to hardcode their AI instructions directly into Apex strings. Please, don't do that. It's a maintenance nightmare waiting to happen. Instead, you should be using the Prompt Builder to manage your logic and then calling those templates programmatically. It keeps your code clean and lets admins tweak the AI's "personality" without needing a deployment.
Why you should care about Salesforce Prompt Templates
Think of these templates as a central hub for your AI's brain. Instead of scattering "You are a helpful assistant" messages across ten different classes, you define it once. This is especially helpful when you start looking at practical Agentforce use cases where consistency is everything.
Here's what you get when you stick to this pattern:
- Centralized Guardrails: You set the rules once, and they apply everywhere.
- Dynamic Context: You can pass in record IDs or specific variables at runtime.
- Easier Testing: You can test the prompt in the builder before you even write a single line of LWC code.
So why does this matter? Well, if the business decides the AI should sound more professional and less casual, you change it in the Prompt Builder. No code changes. No unit tests to fix. That's the dream, right?

A split-screen illustration showing a low-code prompt configuration interface next to a professional code editor with Apex syntax highlighting.
How to call Salesforce Prompt Templates from Apex
Now, let's talk about the actual implementation. To trigger Salesforce Prompt Templates from code, we use the ConnectApi namespace. Specifically, the EinsteinLLM class. Now, I'll be honest, the boilerplate code for this is a bit wordy. It's not as simple as a one-line method call, but once you get the pattern down, it's very repeatable.
public with sharing class AIContentController {
@AuraEnabled
public static String generatePromotion(String recordId) {
// We need to map our inputs to what the template expects
Map<String, String> recordInput = new Map<String, String>();
recordInput.put('id', recordId);
ConnectApi.WrappedValue wrappedRecord = new ConnectApi.WrappedValue();
wrappedRecord.value = recordInput;
Map<String, ConnectApi.WrappedValue> inputParams = new Map<String, ConnectApi.WrappedValue>();
inputParams.put('Input:Adventure_Activity', wrappedRecord);
// Setting up the invocation
ConnectApi.EinsteinPromptTemplateGenerationsInput input = new ConnectApi.EinsteinPromptTemplateGenerationsInput();
input.additionalConfig = new ConnectApi.EinsteinLlmAdditionalConfigInput();
input.additionalConfig.applicationName = 'PromptBuilderPreview';
input.inputParams = inputParams;
input.isPreview = false;
try {
// This is the actual call to the LLM
ConnectApi.EinsteinPromptTemplateGenerationsRepresentation output =
ConnectApi.EinsteinLLM.generateMessagesForPromptTemplate('Adventure_Promotion', input);
return output.generations[0].text;
} catch (Exception e) {
throw new AuraHandledException('AI Generation failed: ' + e.getMessage());
}
}
}
One thing that trips people up is the
applicationNameparameter. In my experience, if you don't set this correctly - often to 'PromptBuilderPreview' during development - the API might throw a generic error that's hard to debug. Always double-check your config inputs first.
Breaking down the Apex logic
You'll notice we are wrapping our record ID into a ConnectApi.WrappedValue. This is because Salesforce Prompt Templates are flexible. They can take records, strings, or even integers as inputs. If you're wondering whether to use this or a standard Flow, check out my thoughts on Apex vs Flow for these types of decisions. Usually, if I need a custom UI in an LWC, Apex is the winner.
Showing the AI output in a Lightning Web Component
Once you have your Apex controller ready, the LWC side is pretty straightforward. You just need a button to trigger the call and a way to show the result. I like to use a lightning-spinner because LLM responses aren't instant. Users hate staring at a frozen screen.
import { LightningElement, api, track } from 'lwc';
import generatePromotion from '@salesforce/apex/AIContentController.generatePromotion';
export default class AiPromoter extends LightningElement {
@api recordId;
@track responseText;
isLoading = false;
async handleGenerate() {
this.isLoading = true;
try {
this.responseText = await generatePromotion({ recordId: this.recordId });
} catch (error) {
console.error('Error calling AI:', error);
} finally {
this.isLoading = false;
}
}
}
But here's where it gets interesting. If your template is designed to return JSON, you can parse that in your LWC to build a really rich UI. This is a common pattern when you're doing something like grounding AI data to show specific record details in a custom format.
Key Takeaways
- Salesforce Prompt Templates are your single source of truth for AI instructions.
- Use the ConnectApi namespace in Apex to call templates programmatically.
- Always handle errors and loading states in your LWC to keep the UX smooth.
- Don't hardcode prompts. Use the Prompt Builder so you can update logic without deployments.
Look, the setup might feel like a lot of steps the first time you do it. But once you've got your first template running in an LWC, you'll see why it's the right way to build. It's about making your AI features scalable and maintainable. If you're just starting out, try building a simple summary component first. It's the easiest way to get a win and show the business what's possible.
Leave a Comment