Why this usecase?

In SaaS support, triage is the highest-leverage intervention point. Get it wrong and you have P1 production outages sitting in Tier 1 queues while engineers handle password resets. Get it right and you compress MTTR (mean time to resolve), protect SLAs, and reduce escalation noise dramatically.

Traditional approaches – Flow-based routing rules, static assignment criteria — break the moment a case arrives that doesn’t fit the template. A customer writes: “Our revenue dashboard shows $0 for all accounts since this morning.” Is that a UI rendering bug? A data sync failure? A permissions problem? A genuine data loss incident? A rule engine can’t distinguish them. An LLM can.

But here is the architect’s tension: you cannot let an LLM freely route cases in a production support queue. Misrouting a P1 to Tier 1 is an SLA breach. So the design question is never “should we automate triage?” — it’s “which triage decisions are safe to automate, and which need a human checkpoint?”

The Autonomy Problem – And the HSAD Answer

The HSAD (Human-Supervised Agentforce Design) framework is built on one core principle: autonomy level is a function of impact × confidence. The agent should not have a uniform posture — it should reason contextually about when to act and when to defer.

For escalation triage, the matrix looks like this:

ConditionAgent ActionStatusWhy
Sensitive keywords in caseSkip LLM, flag immediatelyHard GuardrailData loss, security, breach = mandatory human review regardless
P1 + confidence ≥ 85%Auto-route to Tier 3Auto-RoutedHigh impact, high certainty — delay is worse than rare misroute risk
P1 + confidence < 85%Flag, suggest Tier 3FlaggedNever auto-route P1 with doubt — SLA breach risk too high
P2/P3 + confidence ≥ 75%Auto-route to correct tierAuto-RoutedLower stakes, acceptable automation zone
P2/P3 + confidence < 75%Route, but flag for reviewFlaggedDon’t stall the case — mark for review without blocking
P4 (any confidence)Always auto-route to Tier 1Auto-RoutedLow stakes, high volume — human review defeats the purpose

Data Model — Why Separate AI Fields

This is the question I get most often: “Why not just write the AI’s severity call to the Case Priority field?” Here’s the architectural answer.

The Case Priority field represents the support team’s official severity call. The AI’s classification is an independent assessment. These must coexist separately — because the delta between them is your feedback loop. Without separate fields you can’t measure model accuracy, you can’t audit routing decisions, and you can’t learn from human overrides.

Field API NameTypePurpose
AI_Severity_Class__cPicklist (P1–P4)Agent’s classification output — independent of human Priority field
AI_Confidence_Score__cPercentModel confidence — the variable that drives your entire routing matrix
AI_Routing_Rationale__cLong Text AreaImmutable agent testimony — answers “why did it route here?” at any time
AI_Triage_Status__cPicklistPipeline state: Pending → Auto-Routed → Flagged → Human Reviewed
AI_Ambiguity_Reason__cText AreaWhy the agent was uncertain — the reviewer’s briefing note
Suggested_Tier__cPicklistAgent’s suggested routing — human confirms or overrides with one click

The Prompt Template — Designing for Ambiguity

The classification prompt is the most important artifact in this entire build. Get it wrong and your entire Autonomy Decision Matrix is running on bad input. The two most common mistakes I see: definitions that are too clean (the LLM always finds a bucket), and no instructions that tell the model when to be uncertain.

Here’s the template I use in Einstein Prompt Builder, with the ambiguity design deliberately baked in:

You are an expert support triage analyst for a B2B SaaS company.
Analyze the support case below and classify its severity.
CASE SUBJECT: {!CaseSubject}
CASE DESCRIPTION: {!CaseDescription}
ACCOUNT NAME: {!AccountName}
ACCOUNT TIER: {!AccountTier}
SEVERITY DEFINITIONS:
P1 - System down, data loss, security incident, revenue impact,
or affects multiple users / entire account
P2 - Major feature broken, workaround exists, limited scope
P3 - Minor issue, cosmetic bug, low-frequency path
P4 - Question, how-to, feature request, general feedback
HARD RULES:
- If description contains "data loss", "security", "breach",
or "compliance" — severity must be P1, confidence must be 95+
- Account Tier = Enterprise amplifies severity if description
is borderline between two levels
CONFIDENCE SCORING — READ CAREFULLY:
Score confidence LOWER when any of these are true:
- Description is vague, one sentence, or missing key details
- Subject and description suggest different severity levels
- Impact scope is unclear (one user? all users? unknown?)
- Customer uses emotional language without technical evidence
- Case could reasonably be classified as two different severities
Score confidence HIGHER only when ALL of these are true:
- Impact scope is clearly stated
- Technical symptoms are specific and unambiguous
- Severity bucket has no overlap with adjacent levels
Respond ONLY in this exact JSON format with no other text:
{
"severity": "P1|P2|P3|P4",
"confidence": <integer 0-100>,
"rationale": "<one sentence explaining classification>",
"ambiguity_reason": "<one sentence if confidence < 80, else null>"
}

Agent Script – Where the Autonomy Matrix Becomes Real

Agent Script is Salesforce’s answer to the reliability problem with instruction-only agents. It lets you define exactly where the LLM reasons and where deterministic logic takes over — giving you hybrid agents that are both flexible and predictable.

For triage, the separation of responsibilities is clear: the LLM handles classification from unstructured text. Agent Script handles routing logic, guardrails, and error handling. This is not a design preference — it is the correct architectural boundary.

// ============================================================
// ESCALATION TRIAGE AGENT SCRIPT
// HSAD Gates: Hard guardrail (keywords) + Pre-routing (confidence)
// ============================================================
// STEP 1: Fetch enriched case context
// Always first — downstream actions depend on this output
const caseContext = await actions.Get_Case_Context({
caseId: context.recordId
});
// Null guard — failed data fetch should never silently route a case
if (!caseContext || !caseContext.caseDescription) {
await actions.Update_Case_And_Route({
caseId: context.recordId,
triageStatus: "Flagged for Review",
ambiguityReason: "Could not retrieve case details for classification",
suggestedTier: "Human_Review_AI_Flagged"
});
return;
}
// STEP 2: Hard guardrail — check BEFORE calling the LLM
// Why before: Don't waste an Einstein API call on cases
// that must always go to human review regardless
const desc = caseContext.caseDescription.toLowerCase();
const subj = caseContext.caseSubject?.toLowerCase() || "";
const sensitiveKeywords = [
"data loss", "security", "breach",
"compliance", "gdpr", "hack", "exposed"
];
const hasSensitiveKeyword = sensitiveKeywords.some(k =>
desc.includes(k) || subj.includes(k)
);
if (hasSensitiveKeyword) {
await actions.Update_Case_And_Route({
caseId: context.recordId,
aiSeverity: "P1",
aiConfidence: 99,
rationale: "Sensitive keyword — mandatory human review",
triageStatus: "Flagged for Review",
ambiguityReason: "Hard guardrail triggered",
suggestedTier: "Tier_3_Engineering_Escalation"
});
return; // Done. Human reviews this.
}
// STEP 3: LLM Classification via Prompt Template
const classificationResult = await actions.Classify_Case_Severity({
CaseSubject: caseContext.caseSubject,
CaseDescription: caseContext.caseDescription,
AccountName: caseContext.accountName,
AccountTier: caseContext.accountTier
});
// Parse JSON output — if parse fails, flag immediately
// Never route on malformed classification data
let classification;
try {
classification = JSON.parse(classificationResult.result);
} catch (e) {
await actions.Update_Case_And_Route({
caseId: context.recordId,
triageStatus: "Flagged for Review",
ambiguityReason: "Prompt template returned malformed output"
});
return;
}
const { severity, confidence, rationale, ambiguity_reason } = classification;
// STEP 4: Autonomy Decision Matrix
// Principle: (impact of wrong decision) × (confidence) = autonomy level
let triageStatus, suggestedTier;
if (severity === "P1" && confidence >= 85) {
triageStatus = "Auto-Routed";
suggestedTier = "Tier_3_Engineering_Escalation";
} else if (severity === "P1" && confidence < 85) {
// Never auto-route P1 with doubt — SLA breach risk too high
triageStatus = "Flagged for Review";
suggestedTier = "Tier_3_Engineering_Escalation";
} else if (severity === "P2" && confidence >= 75) {
triageStatus = "Auto-Routed";
suggestedTier = "Tier_2_Technical_Support";
} else if (severity === "P2" && confidence < 75) {
triageStatus = "Flagged for Review";
suggestedTier = "Tier_2_Technical_Support";
} else if (severity === "P3" && confidence >= 75) {
triageStatus = "Auto-Routed";
suggestedTier = "Tier_1_General_Support";
} else if (severity === "P4") {
// P4 = always auto-route — low stakes, high volume
triageStatus = "Auto-Routed";
suggestedTier = "Tier_1_General_Support";
} else {
// Catch-all: when in doubt, always defer to human
triageStatus = "Flagged for Review";
suggestedTier = "Human_Review_AI_Flagged";
}
// STEP 5: Write decision back to record — every case, always
// Audit trail is non-negotiable in a supervised system
await actions.Update_Case_And_Route({
caseId: context.recordId,
aiSeverity: severity,
aiConfidence: confidence,
rationale: rationale,
triageStatus: triageStatus,
ambiguityReason: ambiguity_reason || null,
suggestedTier: suggestedTier
});

The most important design decision in this entire build isn’t the prompt template, the Agent Script, or the trigger. It’s the Autonomy Decision Matrix – and specifically, the act of making it explicit.

The confidence score is a designed output, not a natural one. The LLM defaults to certainty. If your prompt doesn’t explicitly define when uncertainty is the correct response, your human review gate will never fire. You’ll have built a supervised system that never actually routes anything to supervision.

Let me know your thoughts on this, what framework you think of while designing the Agentforce?

Leave a Reply

Discover more from CloudShetra

Subscribe now to keep reading and get access to the full archive.

Continue reading