Building a Smart Healthcare Assistant with Agentforce on Salesforce

DimpleDimpleJuly 21, 2025

banner

The Agentforce Healthcare Assistant is a smart Salesforce-based solution that assists users in:

Determining whether they need a medical checkup based on disease input.

  • Recommending nearby doctors or hospitals.

  • Collecting and storing doctor ratings from patients.

  • Displaying relevant doctor availability and advice.

  • In this blog, we’ll break down how to implement this solution in Salesforce using custom objects, fields, flows, and Apex code.

OBJECT STRUCTURE

  1. Health Check Request (Custom Object) This object stores user (patient) data, health Advice, and recommendation results.

Fields:

Name – Text(80)
Disease__c – Picklist
Phone__c – Phone
Age__c – Number(3, 0)
Gender__c – Picklist
CheckupRecommendation__c – Checkbox
Pin_Code__c – Text
Location__c – Geolocation
NearbyDoctorMap__c – Formula (Text)

IF( NOT(ISBLANK(PinCode__c)), HYPERLINK( "https://www.google.com/maps/search/doctor+near+" & PinCode__c, "View Nearby Doctors by Pin Code", "_blank" ), "Pin Code not available" )

HealthAdvice__c – Formula (Text)

CASE( TEXT(Disease__c), "Common Cold", "Rest well, stay hydrated, and consider steam inhalation. See a doctor if symptoms worsen.", "Mild Fever", "Take paracetamol, rest, and drink plenty of fluids. Consult a doctor if fever persists.", "Mild Headache", "Take rest, avoid screen time, and consider mild pain relief. Visit a doctor if it continues.", "No specific advice available for this condition." )
  1. Doctor Detail (Custom Object)

Fields:

Name – Text(80)
AverageRating__c – Number(2, 1)

  1. Rating (Custom Object)

Fields:

Name – Text(80)
DoctorsDetail__c – Lookup(Doctors Detail)
Phone__c – Phone
RatingScore__c – Number(1, 0)

FLOWS OVERVIEW

Flow 1: Health Check Requests Details

Type: Autolaunched Flow

  • Input Variables:

    • nameInput (Text)
    • phoneInput (Text)
    • ageInput (Number)
    • genderInput (Text)
    • diseaseInput (Text)
  • Logic:

    • If disease is Common Cold, Mild Fever, or Headache → "No Checkup Required"
    • Else → "Checkup Recommended"
  • Output Variable:

    • checkupRecommendationOutput

Flow 2: Update Pin Code Of Health Check Request

Type: Autolaunched Flow

  • Input Variables:

    • nameInput (Text)
    • phoneInput (Text)
    • ageInput (Number)
    • genderInput (Text)
    • diseaseInput (Text)
    • pinCodeInput (Text)
  • Logic:

    • Use Update Records to set the PinCode__c field.
  • Output Variable:

    • nearByDoctorMapOuput

Flow 3: Create Rating For Doctors

Type: Autolaunched Flow

  • Input Variables:

    • doctorNameInput (Text)
    • phoneInput (Text)
    • patientNameInput (Number)
    • ratingInput (Text)
  • Logic:

    • Create a new Rating record and link it to the doctor
  • Output Variable:

    • ratingRecordOutput

APEX CLASSES & TRIGGERS

HealthCheckRequestTrigger

Automatically enqueues a Queueable Apex job when a pincode is entered or updated:

HealthCheckRequestTrigger.apxt
trigger HealthCheckRequestTrigger on HealthCheckRequest__c (after insert, after update) { for (HealthCheckRequest__c h : Trigger.new) { if (h.PinCode__c != null) { System.enqueueJob(new PincodeToLocationQueue(h.Id, h.PinCode__c)); } } }

PincodeToLocationQueue

Fetches latitude and longitude from the OpenStreetMap API using a pincode.

PincodeToLocationQueue.apxc
public class PincodeToLocationQueue implements Queueable, Database.AllowsCallouts { private Id recordId; private String pincode; public PincodeToLocationQueue(Id recordId, String pincode) { this.recordId = recordId; this.pincode = pincode; } public void execute(QueueableContext context) { try { Http http = new Http(); HttpRequest req = new HttpRequest(); req.setEndpoint('https://nominatim.openstreetmap.org/search?postalcode=' + EncodingUtil.urlEncode(pincode, 'UTF-8') + '&country=India&format=json'); req.setMethod('GET'); req.setHeader('User-Agent', 'SalesforcePincodeLookup'); HttpResponse res = http.send(req); System.debug('HTTP Status: ' + res.getStatusCode()); System.debug('Raw Response: ' + res.getBody()); if (res.getStatusCode() == 200) { List<Object> rawList = (List<Object>) JSON.deserializeUntyped(res.getBody()); if (!rawList.isEmpty()) { Map<String, Object> first = (Map<String, Object>) rawList[0]; Double lat = Double.valueOf((String)first.get('lat')); Double lon = Double.valueOf((String)first.get('lon')); System.debug('Lat: ' + lat + ', Lon: ' + lon); HealthCheckRequest__c h = [SELECT Id FROM HealthCheckRequest__c WHERE Id = :recordId LIMIT 1]; h.Location__Latitude__s = lat; h.Location__Longitude__s = lon; update h; } else { System.debug('No results found for pincode.'); } } } catch (Exception e) { System.debug('Error fetching geolocation: ' + e.getMessage()); } } }

RatingTrigger

Handles recalculation of Doctor Average Ratings after insert, update, delete, or undelete:

RatingTrigger.apxt
trigger RatingTrigger on Rating__c (after insert, after update, after delete, after undelete) { Set<Id> doctorIds = new Set<Id>(); if (Trigger.isInsert || Trigger.isUpdate || Trigger.isUndelete) { for (Rating__c r : Trigger.new) { if (r.DoctorsDetail__c != null) { doctorIds.add(r.DoctorsDetail__c); } } } if (Trigger.isUpdate || Trigger.isDelete) { for (Rating__c r : Trigger.old) { if (r.DoctorsDetail__c != null) { doctorIds.add(r.DoctorsDetail__c); } } } if (!doctorIds.isEmpty()) { DoctorRatingService.updateAverageRatings(doctorIds); } }

DoctorRatingService

Calculates average ratings per doctor manually, bypassing the need for roll-up summary fields:

DoctorRatingService.apxc
public class DoctorRatingService { public static void updateAverageRatings(Set<Id> doctorIds) { Map<Id, List<Rating__c>> ratingsMap = new Map<Id, List<Rating__c>>(); for (Rating__c rating : [ SELECT Id, RatingScore__c, DoctorsDetail__c FROM Rating__c WHERE DoctorsDetail__c IN :doctorIds ]) { if (!ratingsMap.containsKey(rating.DoctorsDetail__c)) { ratingsMap.put(rating.DoctorsDetail__c, new List<Rating__c>()); } ratingsMap.get(rating.DoctorsDetail__c).add(rating); } List<DoctorsDetail__c> doctorsToUpdate = new List<DoctorsDetail__c>(); for (Id docId : ratingsMap.keySet()) { List<Rating__c> ratings = ratingsMap.get(docId); Decimal total = 0; Integer count = 0; for (Rating__c r : ratings) { if (r.RatingScore__c != null) { total += r.RatingScore__c; count++; } } Decimal avg = count > 0 ? total / count : null; doctorsToUpdate.add(new DoctorsDetail__c( Id = docId, AverageRating__c = avg.setScale(1) )); } if (!doctorsToUpdate.isEmpty()) { update doctorsToUpdate; } } }

Validation Rule (on Rating__c)

Name: Validate_RatingScore

OR(
    RatingScore__c < 1,
    RatingScore__c > 5
)

Error Message: Please enter a rating between 1 and 5.

AGENT INSTRUCTIONS

These are the custom instructions given to the Agentforce digital assistant:

Greeting Handling

When the user starts the conversation by saying hi, hello, or hlo, then ask: "Would you like to provide a rating for a doctor, or do you need information related to a health issue?"

Health Info Flow

If user selects health issue, ask: "Please provide your name, the disease you are experiencing, your phone number, age, and gender."

Once user provides the info, run action: "Health Check Requests Details"

If the user confirms checkup is needed, ask for pincode and run action: "Update Pin Code Of Health Check Request"

Doctor Rating Flow

If user selects doctor rating, ask: "Please provide the Doctor Name, your name (patient), your phone number, and the rating (1 to 5)."

Once info is provided, run action: "Give Rating to the Doctors"

Output:

banner

Summary

Agentforce combines custom objects, Apex logic, automation, and external API calls into a seamless healthcare assistant. It checks health eligibility, locates nearby doctors, and collects feedback, enhancing healthcare engagement with smart, structured flows.

Free Consultation