Your model, your contract, your region — with the Einstein Trust Layer still in the path. Part 2 of the External AI series.
Helix Pharma runs clinical-trial recruitment on Salesforce. The medical affairs team wants AI drafts of investigator outreach emails — but pharma compliance killed the first proposal in one meeting: model traffic must run on the company's existing Azure OpenAI enterprise agreement (negotiated retention, EU region, committed pricing), not on a new provider relationship.
That constraint rules out the plain native Models API path, which serves Salesforce-managed models under Salesforce's provider agreements. But it does not mean writing raw callouts and rebuilding masking and audit by hand. The middle path is BYO LLM: register the company's own Azure OpenAI deployment in Einstein Studio (Model Builder), and Salesforce treats it as a first-class model — usable from Prompt Builder, Agentforce and the Models API, with the Einstein Trust Layer in front of every request.
For beginners: Einstein Studio is the model management workspace inside Data 360 / Einstein setup. Its generative AI side ("Model Builder") is where you configure foundation models — including connecting external ones on supported providers: Azure OpenAI, OpenAI, Amazon Bedrock and Google Vertex AI. If you chose your path with the decision guide (Part 1), this is Path 2.
Everything Salesforce needs comes from your provider console. For Helix's Azure OpenAI deployment that means:
helix-outreach-v2.Bedrock and Vertex AI differ in auth details (IAM-style credentials instead of a flat key) but the shape is the same: region, model identifier, credentials.
In Setup, with Einstein generative AI enabled:
Helix_Outreach_Model.That's the whole registration. No Named Credential, no Apex callout plumbing, no remote site settings — Model Builder owns the connection and the secret.
Here's the payoff: the Apex is identical to the native path — only the model name changes. Helix's email-draft service:
public with sharing class OutreachDraftService {
// Configured model API names are referenced as
// 'sfdc_ai__<YourConfiguredModelApiName>' — check the model's
// detail page in Einstein Studio for the exact value.
private static final String MODEL = 'sfdc_ai__Helix_Outreach_Model';
public static String draftOutreach(Id contactId, String trialCode) {
Contact inv = [SELECT Name, Title,
Account.Name, Account.BillingCountry
FROM Contact WHERE Id = :contactId
WITH USER_MODE];
aiplatform.ModelsAPI.createGenerations_Request request =
new aiplatform.ModelsAPI.createGenerations_Request();
request.modelName = MODEL;
aiplatform.ModelsAPI_GenerationRequest body =
new aiplatform.ModelsAPI_GenerationRequest();
body.prompt =
'Draft a short, formal outreach email inviting this ' +
'investigator to discuss trial ' + trialCode + '. ' +
'Use ONLY the details below. Do not promise outcomes ' +
'or mention compensation.\n\n' +
'Investigator: ' + inv.Name + ', ' + inv.Title + '\n' +
'Institution: ' + inv.Account.Name +
' (' + inv.Account.BillingCountry + ')';
request.body = body;
aiplatform.ModelsAPI.createGenerations_Response res =
new aiplatform.ModelsAPI().createGenerations(request);
return res.Code200.generation.generatedText;
}
}
Compare this with the summarizer in the Models API post — same namespace, same request classes, same response handling. Which means:
Honest limits, so you pick this path for the right reasons:
Sources: Bring Your Own Large Language Model — Salesforce Help · AI Models (Einstein Studio) — developer guide · Supported Models · Access Models API with Apex