0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Salesforce】Agentforce Models APIの使い方|Apex・LWC・FlowからLLMを呼び出す実装ガイド

0
Posted at

はじめに

「Agentforceの標準UIを使わず、自前の画面で生成AIを動かせないか」と聞かれる場面は、Salesforce開発の現場で増えてきています。

私自身もLWCにAI生成機能を組み込もうとして、最初の一歩でしばらく手が止まりました。

そこで使えるのがAgentforce Models APIです。ApexとLWCという普段の開発スキルのまま、Anthropic・Google・OpenAIなど複数プロバイダーのLLMを呼び出せます。

Flowからも@InvocableMethod経由で利用できるため、ノーコード/ローコードの構成にも組み込めます。

この記事では、Models APIの基本構造から、Apex・LWC・Flowそれぞれでの呼び出し方、Einstein Trust Layerが裏で行っている処理、そして実装時にハマりやすいポイントまで一通り整理します。

出典:Access Models API with Apex | Agentforce Developer Guide

Models APIとは何か

Models APIは、Salesforceが提供するLLM呼び出し用のAPIです。
Anthropic・Google・OpenAIなど複数のプロバイダーのモデルを、Apexから統一されたインターフェースで呼び出せる設計になっています。

名前空間は aiplatform、中心クラスは ModelsAPI クラスです。開発者は、このクラスが持つ4つのメソッドを呼び出すだけで生成AI機能をアプリに組み込めます。

メソッド名 機能
createGenerations() テキスト生成(プロンプトに対して回答を生成)
createChatGenerations() チャット生成(メッセージ履歴を元に回答を生成)
createEmbeddings() 埋め込みベクトルの生成
submitFeedback() 生成テキストへのフィードバック送信

submitFeedback()以外のメソッドは、呼び出す際にモデルのAPI名を指定します。

たとえば
GPT-4o Miniを使う場合は
sfdc_ai__DefaultOpenAIGPT4OmniMini

Claude Sonnet 4.6なら
sfdc_ai__DefaultBedrockAnthropicClaude46Sonnet
を指定します。

つまり「どのLLMを使うか」をコード側で動的に切り替えられる、ということです。
GPT系からClaude系への切り替えも、API名を変えるだけで済みます。

出典:Supported Models | Agentforce Developer Guide

利用可能なエディション: Enterprise Edition、Performance Edition、Unlimited Edition、Developer Edition(Lightning Experience)

Einstein Trust Layerを経由するとはどういうことか

Models APIへのすべての呼び出しは、Einstein Trust Layerを経由します。これは開発者が意識的に設定する必要はなく、Models APIを使う時点で自動的に適用されます。

Einstein Trust Layerが提供する主な保護機能は以下の通りです。

  • 機密データのマスキング:プロンプトに含まれる個人情報などをLLMに渡す前にマスクする
  • ゼロリテンション:LLMプロバイダー側にデータが保持されない
  • 有害性検出:生成されたテキストの有害コンテンツをチェック
  • 監査証跡:すべてのやり取りを記録

正直なところ、最初は「Trust Layerを経由すると遅くなるのでは」と思っていました。
ただ実際に触れてみると、体感の遅延はあまり気にならない水準で、特にセキュリティ要件が厳しい本番環境では安心感があります。

注意点として、データマスキングがONの状態ではコンテキストウィンドウが65,536トークンに制限されます。非常に長いテキストを処理する場合は、この上限を意識した設計が必要です。

ApexからModels APIを呼び出す

テキスト生成(createGenerations)

ModelsAPI.createGenerations()は、与えたプロンプトに対してLLMがテキストを生成する機能です。

呼び出しの基本パターンはこうです。

// リクエストオブジェクトを作成
aiplatform.ModelsAPI.createGenerations_Request request = new aiplatform.ModelsAPI.createGenerations_Request();
// モデルを指定
request.modelName = 'sfdc_ai__DefaultGPT4Omni';
// ボディを作成してプロンプトをセット
aiplatform.ModelsAPI_GenerationRequest requestBody = new aiplatform.ModelsAPI_GenerationRequest();
requestBody.prompt = 'Salesforceの特徴を3つ教えてください。';
request.body = requestBody;

try {
    // 実行
    aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI();
    aiplatform.ModelsAPI.createGenerations_Response result = modelsAPI.createGenerations(request);
    // 生成されたテキストを取得
    String generatedText = result.Code200.generation.generatedText;
    System.debug(generatedText);
} catch(aiplatform.ModelsAPI.createGenerations_ResponseException e) {
    System.debug('Response code: ' + e.responseCode);
    System.debug('The following exception occurred: ' + e);
}

リクエストが成功した場合は Code200.generation.generatedText にテキストが格納されます。
エラー時は ModelsAPI.createGenerations_ResponseException がスローされるため、try-catchで適切にハンドリングする必要があります。


開発者コンソールのデバッグ

チャット生成(createChatGenerations)

チャット形式の場合は createChatGenerations() を使います。
過去のメッセージ履歴を渡すことで、文脈を踏まえた応答が得られます。

// チャットメッセージのリストを組み立てる
List<aiplatform.ModelsAPI_ChatMessageRequest> messages = new List<aiplatform.ModelsAPI_ChatMessageRequest>();

// システムプロンプト(エージェントの振る舞いを定義)
aiplatform.ModelsAPI_ChatMessageRequest systemMsg = new aiplatform.ModelsAPI_ChatMessageRequest();
systemMsg.role = 'system';
systemMsg.content = 'あなたはSalesforceの専門家です。簡潔に回答してください。';
messages.add(systemMsg);

// ユーザーのメッセージ
aiplatform.ModelsAPI_ChatMessageRequest userMsg = new aiplatform.ModelsAPI_ChatMessageRequest();
userMsg.role = 'user';
userMsg.content = 'Agentforceとは何ですか?';
messages.add(userMsg);

// リクエスト作成
aiplatform.ModelsAPI.createChatGenerations_Request request = new aiplatform.ModelsAPI.createChatGenerations_Request();
request.modelName = 'sfdc_ai__DefaultBedrockAnthropicClaude46Sonnet';

// ボディを作成してメッセージをセット
aiplatform.ModelsAPI_ChatGenerationsRequest body = new aiplatform.ModelsAPI_ChatGenerationsRequest();
body.messages = messages;
request.body = body;

try {
    // 呼び出し
    aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI();
    aiplatform.ModelsAPI.createChatGenerations_Response result = modelsAPI.createChatGenerations(request);
    System.debug('Models API response: ' + result.Code200.generationDetails.generations);
} catch(aiplatform.ModelsAPI.createChatGenerations_ResponseException e) {
    System.debug('Response code: ' + e.responseCode);
    System.debug('The following exception occurred: ' + e);
}

チャット形式は、ユーザーとの連続した会話や、システムプロンプトでAIの振る舞いを細かく制御したい場面に向いています。


開発者コンソールのデバッグ

LWCからModels APIを呼び出す構成

LWCからModels APIを直接呼ぶことはできません。LWC → Apex → Models API という3層構成がパターンです。

この構成のポイントは、LWC側がUIとプロンプト組み立てを担当し、Apex側がModels APIとの通信を担当するという役割分担です。

Apexクラスの作成

まず、LWCから呼び出せるApexメソッドを作ります。@AuraEnabledアノテーションをつけることでLWCから呼び出せるようになります。

public with sharing class ModelsApiController {
    
    @AuraEnabled
    public static String getGeneratedText(String prompt, String modelName) {
        try {
            // リクエスト作成
            aiplatform.ModelsAPI.createGenerations_Request request = 
                new aiplatform.ModelsAPI.createGenerations_Request();
            request.modelName = modelName;

            // ボディにプロンプトをセット
            aiplatform.ModelsAPI_GenerationRequest requestBody = 
                new aiplatform.ModelsAPI_GenerationRequest();
            requestBody.prompt = prompt;
            request.body = requestBody;

            // 呼び出し
            aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI();
            aiplatform.ModelsAPI.createGenerations_Response result = 
                modelsAPI.createGenerations(request);

            return result.Code200.generation.generatedText;

        } catch (aiplatform.ModelsAPI.createGenerations_ResponseException e) {
            throw new AuraHandledException('生成エラー: ' + e.getMessage());
        }
    }
}

LWCのJavaScript側

Apexメソッドをimperative(命令型)で呼び出します。

import { LightningElement } from 'lwc';
import getGeneratedText from '@salesforce/apex/ModelsApiController.getGeneratedText';

export default class ModelsApiDemo extends LightningElement {
    prompt = '';
    generatedText = '';
    isLoading = false;

    handlePromptChange(event) {
        this.prompt = event.target.value;
    }

    async handleGenerate() {
        this.isLoading = true;
        try {
            this.generatedText = await getGeneratedText({
                prompt: this.prompt,
                modelName: 'sfdc_ai__DefaultGPT4Omni'
            });
        } catch (error) {
            console.error('エラー:', error);
        } finally {
            this.isLoading = false;
        }
    }
}

LWCのHTML側

<template>
    <lightning-card title="AI文章生成">
        <div class="slds-p-around_medium">
            <lightning-textarea
                label="プロンプト"
                value={prompt}
                onchange={handlePromptChange}
            ></lightning-textarea>
            
            <lightning-button
                label="生成する"
                onclick={handleGenerate}
                disabled={isLoading}
            ></lightning-button>
            
            <template if:true={generatedText}>
                <p class="slds-m-top_medium">{generatedText}</p>
            </template>
        </div>
    </lightning-card>
</template>

SalesforceのレコードIDやオブジェクトデータをプロンプトに組み込む場合は、@wireデコレータでレコードデータを取得してJavaScript側でプロンプト文字列に埋め込みます。
つまり「CRMのデータを使ってAIに文章を書かせる」という構成が、既存の開発スキルで実現できるということです。


商談レコードにLWCを置いてみた例

出典:LWC & Flow Examples | Agentforce Developer Guide

出典:LWC と Models API で、高度にカスタマイズしたAIアプリを作る | Salesforce Developers Blog(日本語)

FlowからModels APIを呼び出す

Flowから呼び出す場合は、@InvocableMethodアノテーションを使います。このアノテーションを付けることで、ApexクラスのメソッドがFlow Builderのアクションとして利用できるようになります。

public with sharing class ModelsApiFlowAction {
    
    public class ActionInput {
        @InvocableVariable(label='プロンプト' required=true)
        public String prompt;
        
        @InvocableVariable(label='モデルAPI名')
        public String modelName;
    }
    
    public class ActionOutput {
        @InvocableVariable(label='生成テキスト')
        public String generatedText;
    }
    
    @InvocableMethod(label='Models APIでテキスト生成' 
                     description='指定したプロンプトでLLMからテキストを生成します')
    public static List<ActionOutput> generateText(List<ActionInput> inputs) {
        List<ActionOutput> outputs = new List<ActionOutput>();
        
        for (ActionInput input : inputs) {
            ActionOutput output = new ActionOutput();
            try {
                String targetModel = String.isNotBlank(input.modelName) 
                    ? input.modelName 
                    : 'sfdc_ai__DefaultOpenAIGPT4OmniMini';
                
                // リクエスト作成
                aiplatform.ModelsAPI.createGenerations_Request request = 
                    new aiplatform.ModelsAPI.createGenerations_Request();
                request.modelName = targetModel;

                // ボディにプロンプトをセット
                aiplatform.ModelsAPI_GenerationRequest requestBody = 
                    new aiplatform.ModelsAPI_GenerationRequest();
                requestBody.prompt = input.prompt;
                request.body = requestBody;

                // 呼び出し
                aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI();
                aiplatform.ModelsAPI.createGenerations_Response result = 
                    modelsAPI.createGenerations(request);

                output.generatedText = result.Code200.generation.generatedText;

            } catch (Exception e) {
                output.generatedText = 'エラーが発生しました: ' + e.getMessage();
            }
            outputs.add(output);
        }
        return outputs;
    }
}

Flow Builder上では「Apex アクション」として登録されたこのクラスを選択し、プロンプトにFlow変数をバインドするだけで使えます。
AgentforceのエージェントアクションとしてこのApexを登録する場合も同様の仕組みです。


アクションでApexを呼び出すことができる

フローデバッグ画面

つまずきポイント・注意事項

① Apexのコールアウト制限に注意

Models APIの呼び出しは、内部的にはApexのコールアウトとして扱われます。1トランザクション内でのコールアウト上限(デフォルト100回)と、タイムアウト制限(最大120秒)の両方が適用されます。
複雑な処理とModels API呼び出しを組み合わせる場合は、この制限を意識した設計が必要です。

② レート制限:本番と開発環境でまったく異なる

環境によってレート制限が大きく異なるため、開発段階でうまく動いていても本番でハマることがあります。

環境 制限
本番環境 500 RPM(モデルによって変動)
サンドボックス(Apex経由) 200 req/時
デモ・トライアル 150 req/時

サンドボックスの制限は特に厳しく、連続テストを繰り返していると上限に当たることがあります。429エラーが返ってきたときはレート制限を疑うのが先決です。

出典:Rate Limits for Models API | Agentforce Developer Guide

③ 呼び出しはすべてEinstein Requestsとして課金対象

Models APIの呼び出しはすべてEinstein Requestsの消費となります。開発・テスト段階からFlexクレジットを消費するため、特にサンドボックスでの反復テストでは使用量の管理が必要です。
Digital Walletで定期的に消費量を確認する習慣をつけておくと安心です。

④ 非同期コンテキストからの呼び出しに注意

@futureアノテーションの非同期Apexからコールアウトするには callout=true の指定が必要です。
バッチApexからのModels API呼び出しは制限があるため、同期的なコンテキスト(LWCからのimperative call、Flowのアクション)で使うのが基本的に安全です。

まとめ

  • Models APIはaiplatform名前空間のApexクラスで提供。Apex・LWC・Flowから呼び出せる
  • 主要メソッドはcreateGenerations()(テキスト)、createChatGenerations()(チャット)、createEmbeddings()(埋め込み)の3種類
  • LWCからは「LWC → Apex → Models API」の3層構成が基本パターン
  • Flowからは@InvocableMethodでApexをアクション化して呼び出す
  • すべての呼び出しがEinstein Trust Layerを経由し、データマスキング・ゼロリテンションが自動適用される
  • 本番環境と開発環境でレート制限が大きく異なるため、早めに確認しておく

「既存のLWC開発スキルでここまでできるのか」と感じている方は、まずDeveloper Edition環境で試してみることをおすすめします。思ったより入り口は低いという印象を持っています。


AI×資格学習・Salesforce業務活用の情報をnoteでも発信しています。

https://note.com/pacific_creator1

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?