AvnishYadav
WorkProjectsBlogsNewsletterSupportAbout
Work With Me

Avnish Yadav

Engineer. Automate. Build. Scale.

Ā© 2026 Avnish Yadav. All rights reserved.

The Automation Update

AI agents, automation, and micro-SaaS. Weekly.

Explore

  • Home
  • Projects
  • Blogs
  • Newsletter Archive
  • About
  • Contact
  • Support

Legal

  • Privacy Policy

Connect

LinkedInGitHubInstagramYouTube
Beyond Einstein: Building a Custom AI Sales Agent in Salesforce
2026-02-21

Beyond Einstein: Building a Custom AI Sales Agent in Salesforce

7 min readAI AutomationEngineeringSalesforce DevelopmentAutomationDevOpsAI AgentsLLM IntegrationSalesforceApex

A developer's guide to bypassing the hype and building a real Salesforce AI integration. We architecture a 'Deal Closer' agent that enriches opportunities with real-time strategic insights.

If you work in the Salesforce ecosystem, you cannot escape the noise. Einstein 1, Copilot, Prompt Builder—Salesforce is going all-in on AI. And for enterprise clients with massive budgets, those native tools are fantastic.

But for the rest of us—builders, indie developers, and lean engineering teams—sometimes the native tools are too rigid, or simply too expensive for the specific use case we need to solve.

Today, I’m putting aside the marketing brochures. We aren't going to talk about what Salesforce AI might do in the future. We are going to build a working system today.

In this deep dive, we are engineering a Custom Opportunity Enrichment Agent. We will look at the architecture, the code (Apex), and the prompt engineering required to turn a static CRM record into a dynamic intelligence briefing.

The Use Case: The "Deal Closer" Dossier

The Problem: Sales reps spend 30% of their time selling and 70% of their time doing admin and research. When an Opportunity moves to the "Value Proposition" stage, a good rep stops to research the client's recent news, stock performance, and C-suite shifts to tailor their pitch.

The Solution: We will build an automation that triggers when an Opportunity stage changes. It will:

  1. Extract context (Account Name, Industry, Past Activity).
  2. Query an LLM (via OpenAI API for this demo) to generate a "Win Strategy" based on real-world data.
  3. Update the Opportunity record with a concise executive summary and suggested talking points.

The Architecture

We are avoiding middleware (like Zapier or Make) for this build to keep latency low and security high. We are going Metal-to-Metal using Salesforce Apex.

The Stack:

  • Trigger: Salesforce Record-Triggered Flow.
  • Orchestrator: Apex Class (Invocable Method).
  • Intelligence: OpenAI API (gpt-4o or gpt-3.5-turbo).
  • Security: Salesforce Named Credentials.
Architecture diagram showing Salesforce Flow calling Apex, which hits an external API, then updates the Salesforce database.
Data Flow: Event -> Processing -> Intelligence -> Persistence.

Step 1: Security First (Named Credentials)

Never hardcode API keys in your Apex code. If you do that, you aren't a senior developer yet. We use Named Credentials.

In Salesforce Setup, create a Named Credential for the OpenAI endpoint. This handles the authentication header securely so your code never touches the raw secret key. This also makes sandbox-to-production deployments cleaner.

Step 2: The Apex Controller

We need an InvocableMethod so our declarative Flow can call this code. This method needs to handle the HTTP callout limits and asynchronous processing (using @future or Queueable interface since we can't make a callout directly inside a Trigger context).

Here is the stripped-down logic for the OpportunityEnrichmentService:

public class OpportunityEnrichment {    @InvocableMethod(label='Enrich Opportunity' description='Generates sales strategy using AI')    public static void enrichOpp(List<Id> oppIds) {        enrichOppAsync(oppIds);    }    @future(callout=true)    public static void enrichOppAsync(List<Id> oppIds) {        Opportunity opp = [SELECT Id, Account.Name, Account.Industry, Amount FROM Opportunity WHERE Id = :oppIds[0]];        String prompt = 'You are a sales strategist. Analyze ' + opp.Account.Name +                         ' in the ' + opp.Account.Industry + ' industry. ' +                        'Suggest 3 talking points to close a deal worth ' + opp.Amount + '.';        // HTTP Request setup        Http http = new Http();        HttpRequest req = new HttpRequest();        req.setEndpoint('callout:OpenAI_Named_Cred/v1/chat/completions');        req.setMethod('POST');        req.setBody(JSON.serialize(new Map<String, Object>{            'model' => 'gpt-4-turbo',            'messages' => new List<Map<String, String>>{                new Map<String, String>{'role' => 'system', 'content' => 'Return valid HTML.'},                new Map<String, String>{'role' => 'user', 'content' => prompt}            }        }));        HttpResponse res = http.send(req);                if (res.getStatusCode() == 200) {            // Parse JSON and Update Record            Map<String, Object> result = (Map<String, Object>)JSON.deserializeUntyped(res.getBody());            // Extraction logic...            opp.AI_Strategy_Brief__c = extractedContent;            update opp;        }    }}

Step 3: The Flow Trigger

Code is great, but maintenance is easier with Low-Code. We use Flow Builder to control when this runs.

  1. Create a Record-Triggered Flow on the Opportunity Object.
  2. Condition: Stage equals "Value Proposition" AND "AI_Strategy_Brief__c" is IsNull = True. (This prevents infinite loops).
  3. Action: Drag in an "Apex Action" node and select our Enrich Opportunity class.
  4. Pass Record ID: Map {!$Record.Id} to the input.

By decoupling the trigger (Flow) from the logic (Apex), we can easily change the criteria later without deploying new code. Maybe we want to trigger it manually via a button? We can just build a Screen Flow that calls the same Apex action.

The Prompt Engineering Strategy

The code connects the pipes, but the Prompt determines the water quality. For a sales use case, generic prompts return generic garbage.

I use a technique called Context Injection. We don't just ask for a strategy; we feed the LLM data we already have.

The System Prompt Structure:

"You are an expert Enterprise Account Executive. Your goal is to provide a 'Cheat Sheet' for an upcoming meeting.
Tone: Professional, terse, bulleted.
Output Format: HTML (for Salesforce Rich Text Field compatibility)."

The User Prompt Injection:

"Target Account: [Account.Name]
Industry: [Account.Industry]
Deal Size: [Amount]
Competitors: [Competitors__c field]
Task: Identify 3 recent news events for this company and map them to our value proposition."

Notice we ask for HTML output? This allows us to update a Rich Text field in Salesforce directly, preserving bolding and lists for the end-user.

The Mock Demo: What the User Sees

Let's walk through the "Happy Path":

  1. 09:00 AM: Sarah, the AE, logs in. She moves the "Acme Corp" deal to "Value Proposition."
  2. 09:00:05 AM: The Flow fires. The Apex job is queued.
  3. 09:00:10 AM: The Apex class hits OpenAI. The LLM processes the request.
  4. 09:00:15 AM: The component on Sarah's Opportunity page flashes. The field "AI Strategy Brief" populates.

The Result:
Instead of a blank field, Sarah sees:

  • Recent News: Acme Corp just announced a merger with BetaInc.
  • Pain Point: Merger usually causes data migration issues.
  • The Pitch: "Position our solution as the data bridge between Acme and BetaInc systems."

She didn't leave Salesforce. She didn't Google anything. The system pushed value to her.

Real-World Limits & Governance

Building this is easy. Scaling it requires knowing the platform limits. Here is where the "Builder" mindset kicks in.

1. The 100-Callout Limit

Salesforce limits the number of callouts in a single transaction. If you try to bulk update 200 opportunities at once, this code will crash (System.LimitException).
Fix: You must implement batch processing (Batchable Interface) or ensure the Flow runs asynchronously per record.

2. The 120-Second Timeout

If OpenAI takes longer than 120 seconds (which happens with complex reasoning chains), Salesforce will sever the connection.
Fix: Use a middleware architecture (AWS Lambda) if you are doing heavy RAG (Retrieval Augmented Generation) workflows, or optimize your prompts for speed.

3. Data Privacy

Do not send PII (Personally Identifiable Information) to public LLMs.
Fix: We only sent Company Name and Industry. We did not send the contact's email, phone number, or specific contract terms. Always sanitize the payload in Apex before serialization.

Summary: Build vs. Buy

Salesforce's Einstein Copilot is coming for this space. It will be easier to set up but will likely cost $50/user/month or more. The architecture we built today costs pennies in API credits and gives you total control over the prompt logic.

The future belongs to engineers who can bridge the gap between CRM data and Generative Intelligence. Start building these micro-agents now.

Share

Comments

Loading comments...

Add a comment

By posting a comment, you’ll be subscribed to the newsletter. You can unsubscribe anytime.

0/2000