Skip to content
All case studies
Recruitment technology / applied AI2026

An Agentforce agent engineered so it cannot fabricate

A Salesforce and Agentforce agent that structures CVs, answers grounded questions about candidates, and ranks them explainably — where Apex verifies every claim against the source text before it is stored or shown.

Context
Independent build — technical assessment
Role
Sole designer and engineer
Period
2026
Systems
Agentforce ⇄ Invocable Apex ⇄ Claude API

At a glance

The output is usable for a decision about a person, because every claim in it can be traced to text in the CV.

  • A fact with no supporting quote never reaches the database.
  • An answer that cannot be verified is refused rather than guessed.
  • Missing, inferred, and conflicting information is visible and countable per candidate.
01

Overview

What this was

Anyone can prompt a model to pull skills out of a CV. The hard part is making the output trustworthy. This build treats grounding, uncertainty, and explainability as structure that Apex verifies — not as behaviour the prompt requests and hopes for. The prompt asks for honest output; Apex proves it before anything is stored or displayed. A claim that cannot point at CV text is dropped, however confident the model sounded.


Business context

Built as a technical assessment, and engineered as production work rather than a demonstration. It is included here because it is the clearest available example of a design principle that applies well beyond recruitment: when a system’s output will inform a decision, the parts that must be reproducible belong in code you can test, not in a component whose output varies between runs.

Delivery timeline

  1. 01

    Framing

    Established that the hard problem is trust, not extraction.

  2. 02

    Data model

    Modelled uncertainty as rows and fields rather than prose.

  3. 03

    Service seam

    Put the model behind one interface with a mock double.

  4. 04

    Grounding gate

    Built the verification that drops unsupported claims.

  5. 05

    Scoring

    Rubric as metadata; Apex computes and ranks.

  6. 06

    Proof

    58 Apex tests, with the trust guarantees as the assertions.

02

Business problem

A recruiter cannot act on an AI summary they have no way to verify. The failure mode is not a missing skill — it is a confident, invented one.

Fabrication is indistinguishable from extraction

A model states an invented qualification in exactly the same register as a real one. Without verification, the reader cannot tell them apart.

Uncertainty gets flattened into prose

Missing, inferred, and contradictory information ends up buried in a summary paragraph, where it cannot be filtered, counted, or surfaced.

A model-produced score explains nothing

A number the model asserts is not reproducible and cannot be traced to a criterion — which makes it useless for a decision about a person.

No audit trail on a consequential decision

Candidate evaluation needs to be reviewable after the fact, including what the system was told and what it answered.

03

Challenges

What made this harder than it looks

  1. 01

    A prompt cannot enforce honesty

    Asking a model not to fabricate reduces fabrication; it does not prevent it. Any guarantee has to be enforced somewhere deterministic.

  2. 02

    Uncertainty has more than one shape

    Missing, inferred, and conflicting are genuinely different states with different consequences, and collapsing them into "unknown" loses the distinction that matters.

  3. 03

    A score must be explainable to be usable

    Every point needs to trace to a criterion, a weight, an evidence quote, and a certainty level — otherwise it cannot be defended.

  4. 04

    The guarantees had to be provable without a live callout

    Anti-hallucination claims are worthless if they can only be checked by hand against a live API.

  5. 05

    Weak matches must not read as rejections

    "We do not know enough about this candidate" and "this candidate is weak" are different conclusions, and the system has to distinguish them.

04

Architecture

How the system fits together

Three layers under one rule: the model reasons, and Apex enforces honesty and does anything deterministic. Agentforce is orchestration only — the layer with the least control holds the least responsibility.

SALESFORCESystem of recordINTEGRATION LAYERBoundary & transportEXTERNAL SYSTEMSOutside our controlLWC UICard / comparison / uploadCVAgentControllerThin @AuraEnabled wrapperInvocable actionsThe five agent actionsGrounding gateCVParser — verify or dropCandidate + FactVerified data onlyAgent_Log__cAudit trailILLMServiceSwappable, mockable seamRecruiterNatural languageAgentforce topicOrchestration onlyClaude APIVia Named Credentialdelegatessame actionsNamed Credentialmodel outputverified onlyaudit
SynchronousAsynchronous, queued, or scheduled
  1. Recruiter to Agentforce topic
  2. Agentforce topic to Invocable actions: delegates
  3. LWC UI to CVAgentController
  4. CVAgentController to Invocable actions: same actions
  5. Invocable actions to ILLMService
  6. ILLMService to Claude API: Named Credential
  7. Invocable actions to Grounding gate: model output
  8. Grounding gate to Candidate + Fact: verified only
  9. Invocable actions to Agent_Log__c: audit

End-to-end flow

  1. 01

    The agent classifies intent

    An Agentforce topic interprets the recruiter’s natural-language request and delegates to an invocable Apex action. It holds no business logic.

  2. 02

    An action calls the model behind an interface

    Every action reaches the model through ILLMService, so the implementation is swappable and mockable.

  3. 03

    The grounding gate runs

    Model output is verified against the source CV text. Any claim whose cited quote does not verify is dropped or suppressed before it is stored or shown.

  4. 04

    Apex computes anything deterministic

    The model judges one candidate against one criterion. Apex computes the score and performs the ranking.

  5. 05

    Verified data is persisted and audited

    Only verified facts reach the data model, and every action writes to an audit log.

  6. 06

    The UI uses the same actions

    The Lightning Web Component controller delegates to the identical actions the agent uses, so the two cannot diverge.

Technologies

Salesforce

  • Agentforce (agent + topic)
  • Invocable Apex actions — five
  • Apex service layer with a mockable interface
  • Custom objects — Candidate, Fact, Bookmark, Agent Log
  • Custom Metadata — rubric, scoring config, LLM config
  • Lightning Web Components — three
  • Roll-up summaries for conflict and unknown counts
  • Permission set for scoped access

Integration

  • Named Credential
  • External Credential with custom auth headers
  • Claude API

Quality

  • 58 Apex tests across 9 test classes
  • HttpCalloutMock
  • Mock LLM service double
05

Solution design

The choices that shaped everything else

Uncertainty is data, not text

Every extracted claim is its own Fact__c row carrying a certainty label — Stated, Inferred, Conflicting, or Missing — and a verbatim evidence quote. Uncertainty becomes queryable, roll-up-summable, and renderable rather than buried in a paragraph. The recruiter sees "2 conflicts, 3 unknowns" on the record without opening a single fact.

The certainty vocabulary cannot drift

The four certainty values are a restricted picklist that exactly mirrors the Apex validation vocabulary, so the database and the code cannot fall out of step.

Grounding is enforced on both the write and the read path

Ingestion drops any fact whose evidence field is blank. Querying and scoring verify each cited quote against the source text and suppress anything that does not match — so an answer is either evidenced or it is "Not found in the CV."

Uncertainty moves the number

Each criterion’s contribution is discounted by the certainty behind it — Stated 1.0, Inferred 0.6, Conflicting 0.4, Missing 0.0. Missing counts as zero but is surfaced as a gap to validate, never as a confirmed weakness, and is paired with a coverage signal so "we do not know enough" stays distinguishable from "this candidate is weak."

A bookmark is a self-contained snapshot

Saving an evaluation stores the score, reason, and a JSON snapshot as shown at evaluation time — so a past decision can be reviewed as it was made, not as it would be recomputed today.

06

Technical decisions

What was decided, why, and what it cost

Every decision below is paired with its trade-off. A design choice without a stated cost usually means the cost was not examined.

01

Enforce grounding in code rather than requesting it in the prompt

Rationale

A prompt is a request; a verification gate is a guarantee. Any fact or cited quote that does not verify against the source is dropped or suppressed regardless of how confident the output appeared.

Trade-off

Verification is a strict normalised substring check, which biases toward false negatives — a near-verbatim quote can be rejected. Deliberate: for a trust-first system, refusing when it could have answered is far safer than answering when it should not have.

02

The model judges; Apex computes and ranks

Rationale

The model assesses one candidate against one criterion and cites evidence. It never produces an overall score and never compares candidates. Apex computes score = Σ(match × weight × discount) and sorts. Every point therefore traces to a criterion, a weight, a quote, and a certainty.

Trade-off

More orchestration and more calls than asking for one overall judgment. That is the cost of a reproducible number.

03

Scoring policy lives in Custom Metadata

Rationale

Rubric weights, certainty discounts, and the strong-match threshold are data. A reviewer can read every number that produces a score without reading Apex, and tuning does not require a deployment.

Trade-off

Behaviour depends on records that must exist. Apex carries a fallback identical to the seeded values so runtime is unaffected if they do not.

04

Prompts live in a version-controlled Apex constants class

Rationale

They began in Custom Metadata for hot tuning — until a length-255 field silently truncated a ~2,200-character prompt on every deploy, producing rounds of apparent model misbehaviour that were really the model working from two sentences. In Apex they are diffable, atomic with the code that depends on them, and immune to that class of bug.

Trade-off

Changing a prompt now requires a deployment. Acceptable — prompts are logic, and logic belongs under review.

05

One interface for the model, with a mock double

Rationale

A single ILLMService seam is what makes the honesty guarantees testable without a live callout — and it is why the anti-hallucination claims are assertions in a test suite rather than statements in a README.

Trade-off

One layer of indirection between the action and the API call.

06

Isolate and stub the document extraction boundary

Rationale

PDF and DOC to text conversion is an external concern. Treating it as a stubbed boundary kept a half-working parser out of the core rather than weaving it through.

Trade-off

Binary uploads are not supported end to end; the component reads .txt and accepts pasted text.

07

My responsibilities

What I personally owned

  • Sole designer and engineer — data model, architecture, prompts, Apex, LWC, and tests.
  • Designed the Candidate Card model that represents uncertainty as structured data.
  • Built the grounding gate that drops or suppresses any unsupported claim.
  • Built the five invocable actions and the thin controller the UI shares with the agent.
  • Designed the rubric-as-metadata scoring model with Apex-side computation and ranking.
  • Wrote 58 Apex tests structured to prove the trust guarantees rather than to reach a coverage number.
  • Documented the architecture, decisions and trade-offs, assumptions, and known limitations.
08

Implementation process

How it was actually built

  1. 01

    Named the real problem first

    Extraction was never the hard part. Framing the work as a trust problem is what produced a verification gate rather than a better prompt.

  2. 02

    Modelled uncertainty before building anything

    Deciding that certainty and evidence are fields on a row — not sentences in a summary — determined the shape of every layer above it.

  3. 03

    Established the mockable seam early

    Putting the model behind ILLMService from the start is what allowed the guarantees to be tested continuously rather than demonstrated manually.

  4. 04

    Moved the score out of the model

    The first design asked the model for an overall score. Replacing it with per-criterion judgment plus Apex arithmetic turned an opaque number into a traceable one.

  5. 05

    Debugged a configuration failure that looked like a model failure

    Rounds of apparent model misbehaviour turned out to be a 255-character metadata field silently truncating the prompt. The fix was architectural: prompts moved into version-controlled Apex.

  6. 06

    Made the tests the argument

    ungrounded_fact_is_rejected, fabricated_quote_is_suppressed, and fabricated_quote_collapses_to_a_gap are the three tests that back the central claim. The documentation points a reviewer at them directly.

09

Security considerations

What was protected, and how

The API key is never in source

Authentication runs through an External Credential principal and a Named Credential. The key is entered in the org and never committed.

Access is granted by permission set, not profile

A dedicated CV_Agent_Access permission set grants object and field access to the recruiter and to the agent user. There is no guest or external exposure.

The agent user is explicitly scoped

The agent user is granted Apex class access through the same permission set, so it can invoke only the intended actions.

Every action is logged

Agent_Log__c records the action, status, input, output, error, and duration — so an evaluation can be audited after the fact.

Candidate data stays inside the org boundary

CV text leaves the platform only on the single outbound path to the model API, through the credential store.

11

Business value

The output is usable for a decision about a person, because every claim in it can be traced to text in the CV.

  • A fact with no supporting quote never reaches the database.
  • An answer that cannot be verified is refused rather than guessed.
  • Missing, inferred, and conflicting information is visible and countable per candidate.
  • Every point in a score traces to a criterion, a weight, a quote, and a certainty level.
  • Weak evidence is surfaced as a gap to validate in interview, not as a confirmed weakness.
  • Scoring policy is readable and tunable as data, without a deployment.
  • Every agent action is logged with input, output, and duration.
12

Lessons learned

What I took from it

Guarantees belong in the deterministic layer

Anything a system promises has to be enforced somewhere that cannot vary between runs. The prompt asks; the code proves.

A silent truncation is worse than a loud failure

A 255-character field quietly cutting a prompt cost several debugging cycles chasing model behaviour. Configuration that can silently discard part of its value is a design defect, not an operational detail.

Choose your error direction deliberately

The grounding check errs toward false negatives. That is a decision with a stated cost — fewer good answers — rather than an accident, and it is written down as such.

Model capability is an architectural constraint

A smaller model could not reliably hold the six-field extraction schema. Reliability came from schema-first prompt ordering, explicit negative instructions, and response prefill — design choices, not prompt polish.

Honest asymmetries are worth documenting

Single-candidate certainty is weaker than multi-candidate certainty, because one reads from verified rows and the other from the model. Stating that plainly is more useful than implying uniform strength.

13

Future improvements

What I would do next

Listing the known gaps is part of the handover. A system described as finished usually means nobody looked hard enough.

  1. Span alignment instead of strict substring matching

    The one genuine improvement. Today the grounding gate rejects a truthful answer whose quote is lightly paraphrased. A token-overlap check against the source with a high threshold would keep the guarantee — no answer without real support — while refusing fewer good answers. It is the one place where the safe choice visibly costs recall.

    Improvement 1
  2. Real document extraction behind the existing boundary

    The extraction seam is already isolated, so a proper PDF and DOC extractor can be dropped in without touching the core.

    Improvement 2
  3. Per-role rubrics

    The metadata design already allows multiple rubrics; only one default is modelled today. Per-role weighting is a configuration extension rather than a rewrite.

    Improvement 3
  4. Component-level tests for the UI

    The Apex controller is fully tested and the components hold no business logic, but Jest coverage would protect the rendering contract.

    Improvement 4