Agentforceのカスタムアクションを作るとき、最初に迷うのが「Flowで組むか、Apexで書くか」という選択です。
Flow側の手順は資料も多くイメージしやすいのに、Apexから登録する方法はまとまった情報が少なく、最初は全体像をつかみにくいと感じました。
Flowで組める範囲ならFlowで十分です。外部API連携や複数オブジェクトをまたぐ複雑なロジックが必要になった時点で、Apexに切り替えるのが実務的な判断基準だと考えています。
この記事では、@InvocableMethodアノテーションを使ったApexクラスの実装方法から、Agentforce Builderへの登録手順、サブエージェントへの追加、そして実際にハマりやすいポイントまでをコードベースで整理します。
なぜApexでアクションを作るのか:FlowとApexの使い分け
Agentforceのカスタムアクションは、主にFlowかApexのどちらかで実装します。
どちらを選ぶかによって、できることと設計の方向性が変わります。
Flowが向いているケース:
- レコードの作成・更新・参照など、SOQL/DMLを組み合わせた標準的な業務処理
- ノーコード・ローコードで管理者が維持できる設計が望ましい場合
- 既存の自動起動フローをそのまま転用したい場合
Apexが向いているケース:
- 複雑な業務ロジックや複数オブジェクトをまたぐ処理
- 外部APIとの連携(コールアウトが必要な処理)
- バルク処理や条件分岐が多く、Flowだと管理しにくくなる場合
- 既存のApexコードベースを活用したい場合
つまり「Flowで表現できる範囲なら迷わずFlow、Flowでは難しい業務ロジックならApex」という判断基準が実務では合っていると感じています。
Apexクラスの実装:@InvocableMethodアノテーション
Agentforceのカスタムアクションとして登録するには、Apexメソッドに @InvocableMethod アノテーションをつけます。
このアノテーションをつけることで、Agentforce Builderのアクション設定画面からこのメソッドを参照できるようになります。
以下は基本的な実装パターンです。
public with sharing class GetAccountSummaryAction {
public class Input {
@InvocableVariable(label='取引先名' description='検索する取引先の名前を指定してください' required=true)
public String accountName;
}
public class Output {
@InvocableVariable(label='取引先サマリー' description='取引先の概要情報')
public String summary;
@InvocableVariable(label='エラーメッセージ' description='処理中にエラーが発生した場合のメッセージ')
public String errorMessage;
}
@InvocableMethod(
label='取引先サマリーを取得'
description='指定した取引先名で取引先を検索し、業種・年間売上・所在地をサマリー形式で返します'
)
public static List<Output> getAccountSummary(List<Input> inputs) {
List<Output> outputs = new List<Output>();
for (Input input : inputs) {
Output output = new Output();
try {
List<Account> accounts = [
SELECT Name, Industry, AnnualRevenue, BillingCity
FROM Account
WHERE Name LIKE :('%' + input.accountName + '%')
WITH USER_MODE
LIMIT 1
];
if (accounts.isEmpty()) {
output.summary = '該当する取引先が見つかりませんでした。';
} else {
Account acc = accounts[0];
output.summary = acc.Name + ' / 業種:' + acc.Industry
+ ' / 年間売上:' + acc.AnnualRevenue
+ ' / 所在地:' + acc.BillingCity;
}
} catch (Exception e) {
output.errorMessage = 'エラーが発生しました。管理者にお問い合わせください。詳細:' + e.getMessage();
}
outputs.add(output);
}
return outputs;
}
}
コードのポイント
@InvocableMethodのlabelとdescriptionが最重要
labelとdescriptionは、Atlas Reasoning Engineがこのアクションを「いつ使うべきか」を判断する根拠になります。
「何をするアクションか」を具体的に書かないと、エージェントが意図したタイミングでアクションを呼んでくれません。
実際に設定してみると、説明が曖昧なアクションは意図しないタイミングで呼ばれたり、まったく呼ばれなかったりすることがある印象です。label・descriptionへの投資がそのまま精度に返ってくると感じています。
@InvocableVariableで入出力変数を定義する
入力変数と出力変数はそれぞれ専用のクラス(ここではInput・Output)を作り、@InvocableVariableアノテーションで定義します。重要な属性は3つです。
-
label:Agentforce Builder上に表示されるラベル名 -
description:エージェントがこの変数に何を渡すべきか・何が返ってくるかの説明 -
required=true:入力必須の変数にはtrueを設定する(省略するとエラーになることがある)
セキュリティを意識した実装
SOQLにはWITH USER_MODEを指定し、クラスにはwith sharingキーワードを使います。Agentforceサービスエージェントは認証なしのチャネルから動作する場合もあるため、データアクセスの設計には注意が必要です。
バルク処理設計(Bulkify)
メソッドのシグネチャはList<Input>とList<Output>で定義します。
Agentforceはデフォルトでは1件ずつ呼び出しますが、複数件を一括処理させる指示をサブエージェントの指示(Instructions)に追加することで、より効率的な動作が可能になります。
出典:Best Practices for Building Agentforce Apex Actions | Salesforce Developers Blog
Agentforce Builderへの登録手順
Apexクラスが準備できたら、Agentforce Builderでカスタムアクションとして登録します。登録方法は2つあります。
方法A:Agentforce Builderのサブエージェント内から作成(推奨)
- 設定のクイック検索で「Agentforce スタジオ」を検索して開く
- 対象のエージェントを開き「Builderで開く」をクリック
- 左パネル(エクスプローラー)から対象のサブエージェントを選択
- 「ツール」横の「+」ボタンをクリック →「新しいツールを作成」を選択
- ツール名を入力し「作成して開く」をクリック
- 「参照ツール種別」で 「Apex」 を選択
- 「参照ツール」からApexクラスを選択
- ラベル・手順・入出力変数の設定を確認して「保存」
方法B:アセットライブラリから登録する
- Agentforce スタジオ →「アセットライブラリ」→「ツール」タブを開く
- 「新規エージェントツール」をクリック
- 以降は方法Aと同様
アセットライブラリから登録した場合、複数のエージェントやサブエージェントで同じアクションを再利用できます。
チーム開発や複数エージェントを管理する環境では、アセットライブラリ経由の管理が後々の保守コストを下げると感じています。
登録後の設定確認ポイント
設定画面では以下を確認・調整します。
手順(Instructions):このツールをいつ実行すべきかをエージェントが理解するための説明文。「〇〇のリクエストがあったときに実行する」という形で書く。
入力変数の「手順」:エージェントが各変数に何を渡せばいいかの説明。日本語で書いても動作するが、英語で書くとAtlas Reasoning Engineとの相性がよいケースがある。
入力変数の「入力が必要」チェックボックス:必須変数にはチェックを入れておく。未入力のままツールが実行されてエラーになるのを防ぐ。
出力変数の「会話に表示」チェックボックス:ユーザーに表示したい出力変数にはチェックを入れる。IDなど内部処理用の変数はチェックを外す。
出典:Build Custom Agent Actions Using Apex | Salesforce Developers Blog
つまずきポイント・注意事項
① @InvocableMethodのlabelとdescriptionと、アクション設定のlabel・手順の同期
Apexコードの@InvocableMethodに書いたlabelとdescriptionは、Agentforce Builderのアクション設定画面の「アクションラベル」「手順」にデフォルト値として自動反映されます。コードを更新したとき、設定画面側が古いままになっていないかを確認するクセをつけておくといいです。これを怠ると「コードは直したのに動きが変わらない」という事態になります。
② アクションがAgentforce Builderの選択肢に表示されない
Apexクラスが選択肢に出てこない場合、以下を確認してください。
-
@InvocableMethodアノテーションが正しくついているか - クラスが
publicスコープで定義されているか - Apexクラスのコンパイルエラーがないか(設定画面では事前チェックがされない場合がある)
- エディション要件を満たしているか
③ サブエージェントの指示内でのツール名はAPI名形式で記述する
サブエージェントの指示(Instructions)の中でこのツールを参照する場合は、表示名ではなくAPI名(スペースをアンダースコアに置き換えた形)で記述するとAtlas Reasoning Engineが認識しやすくなります。
例:ツール名が「取引先サマリーを取得」の場合 → Get_Account_Summary のように英語API名で書く方が安全です。
④ CPU時間制限・Governor Limitsに注意
Apexアクションは1トランザクション内で実行されます。複雑なループ処理や大量のSOQLクエリが含まれると、CPU時間の上限に達することがあります。処理が重い場合はロジックを複数のアクションに分割するか、非同期処理(Queueable Apex)への移行を検討してください。ただし非同期からは会話への即時応答ができないため、ユーザーへの通知方法を別途設計する必要があります。
まとめ
-
@InvocableMethodアノテーションをつけたApexクラスを作成することで、Agentforceのカスタムアクション(Agentforce Builderでは「ツール」として表示)として登録できる -
labelとdescriptionの記述が Atlas Reasoning Engine のルーティング精度に直結する - 入出力変数は
@InvocableVariableで定義。required=trueと「会話に表示」チェックボックスの設定を忘れずに - セキュリティ:
with sharingキーワードとWITH USER_MODEでユーザー権限に基づくアクセス制御を実装する - パフォーマンス:バルク処理設計(List/List)と try-catch によるエラーハンドリングが基本
- FlowとApexの使い分けは「Flowで表現できる範囲はFlow、複雑なロジックやコールアウトが必要ならApex」が実務的な基準
Apexコードを Agentforce のアクションに繋げると、既存のSalesforce開発スキルがそのままAIエージェントの拡張に活かせる、という感触がある。最初は少し設定の手間がかかりますが、一度仕組みを理解してしまえばパターンが見えてくる、という印象を持っています。
AI×資格学習・Salesforce業務活用の情報をnoteでも発信しています。
