【Agentforce実践】freee × Agentforceで請求書トラブル対応を自動化してみた

freee for SalesforceとAgentforceを連携し、「未入金の請求書は?」と聞くだけで即座に回答が返ってくる請求書アシスタントを構築する方法を解説します。

本記事のコンセプト

Salesforce Agentforceを活用して、freee for Salesforceの請求書データに自然言語で問い合わせできる「請求書アシスタント」を構築します。Apex 1クラス + Agent Builder設定で、約2.5時間で完成します。

はじめに — なぜ freee × Agentforce なのか

freee会計を使っている企業にとって、請求書まわりの確認作業は日々の”小さなストレス”の積み重ねです。

  • 「A社への請求書、もう出した?」と営業から経理に都度チャットで確認
  • 月次締めのタイミングで入金消込の漏れに気づき、慌てて対応
  • freeeにログインして請求書を検索し、ステータスを一つひとつ確認

こうした作業は1件あたり数分で済むものの、月間で積み上げると無視できない工数になります。さらに、確認の抜け漏れが発生すると、キャッシュフローへの影響や取引先との信頼関係の毀損にもつながりかねません。

本記事では、Salesforce Agentforce を活用して、freee for Salesforceの請求書データに自然言語で問い合わせできる「請求書アシスタント」を構築する方法をステップバイステップで解説します。完成すると、Agentforceのチャット欄に「未入金の請求書は?」と入力するだけで、freeeの最新データをもとに即座に回答が返ってくるようになります。

項目内容
対象読者Salesforce管理者、freee利用企業の経理担当者
前提知識Salesforceの基本操作、freee for Salesforceパッケージ導入済み
構築方法Apex 1クラス + Agent Builder設定(ノーコード中心)
所要時間約2〜3時間(Apex開発含む)
環境Salesforce Enterprise Edition以上 + Agentforceライセンス

完成形のイメージ

まず、完成したエージェントがどのように動作するかを見てみましょう。

デモ 1 — 未入金の請求書を一括確認

ユーザー

未入金の請求書を教えてください

エージェント

未入金の請求書は以下の 5件 です。

請求書番号取引先合計金額請求日入金送信
INV-0000000003ひだまりネクスト株式会社¥1,100,0002026-03-16未入金未送信
INV-0000000008ひだまりネクスト株式会社¥13,200,0002026-03-11未入金未送信
INV-0000000006ひだまりネクスト株式会社¥02026-03-11未入金未送信
INV-0000000007ひだまりネクスト株式会社¥13,200,0002026-03-11未入金未送信
INV-0000000009ひだまりネクスト株式会社¥13,200,0002026-03-11未入金未送信

合計金額 ¥40,700,000 未入金件数 5件

Agentforceチャット画面で未入金の請求書一覧を表示しているデモ

デモ 2 — 取引先名で請求書を検索

ユーザー

ひだまりネクスト株式会社の請求書の状況を教えて

エージェント

ひだまりネクスト株式会社の請求書状況は以下の通りです。

請求書番号合計金額請求日入金送信
INV-0000000003¥1,100,0002026-03-16未入金未送信
INV-0000000008¥13,200,0002026-03-11未入金未送信
INV-0000000006¥02026-03-11未入金未送信
INV-0000000007¥13,200,0002026-03-11未入金未送信
INV-0000000009¥13,200,0002026-03-11未入金未送信

合計金額 ¥40,700,000 未入金件数 5件 未送信件数 5件

Agentforceチャット画面で特定取引先の請求書を検索しているデモ

事前準備

構築を始める前に、以下の環境が整っていることを確認してください。

必要なライセンス・エディション

項目要件
Salesforce EditionEnterprise Edition 以上
Agentforce ライセンスAgentforce for Service または Agentforce for Sales
freee for SalesforceAppExchangeからインストール済み

freee for Salesforce パッケージの確認

freee for Salesforceパッケージが正しくインストールされていると、以下のカスタムオブジェクトが利用可能になります。

オブジェクトAPI名用途
freee__IV_Invoice__cfreeeの請求書データ
freee__Partner__cfreeeの取引先データ

確認方法は、設定 > オブジェクトマネージャー で「freee」と検索し、上記オブジェクトが存在することを確認します。

Agentforce の有効化

Agentforceが有効化されていない場合は、設定 > Einstein > Agentforce から有効化してください。Agentforce Studioに既存のエージェントが一覧表示されていれば準備完了です。

Agentforce Studioのホーム画面

1 Invocable Apex の作成

最初のステップは、freee for Salesforceの請求書データを検索する Invocable Apex クラスの作成です。このクラスがAgentforceのActionとして機能し、エージェントが請求書データにアクセスする窓口となります。

FreeeInvoiceSearchAction の機能

機能説明
取引先名フィルタ部分一致で取引先名を検索
入金ステータスフィルタunsettled(未入金)/ settled(入金済み)で絞り込み
送信ステータスフィルタunsent(未送信)/ sent(送信済み)で絞り込み
請求日フィルタ開始日〜終了日の範囲指定
サマリー生成合計金額・未入金件数・未送信件数を自動集計

Apex コード全文

以下のApexクラスを開発者コンソールまたはVS Codeから作成してください。

/**
 * FreeeInvoiceSearchAction
 * freee請求書データをSalesforceから検索するAgentforceアクション
 */
public with sharing class FreeeInvoiceSearchAction {

    public class SearchRequest {
        @InvocableVariable(required=false
            label='取引先名'
            description='検索したい取引先名(部分一致)')
        public String partnerName;

        @InvocableVariable(required=false
            label='入金ステータス'
            description='unsettled=未入金, settled=入金済み')
        public String paymentStatus;

        @InvocableVariable(required=false
            label='送信ステータス'
            description='unsent=未送信, sent=送信済み')
        public String sendingStatus;

        @InvocableVariable(required=false
            label='請求日From'
            description='請求日の開始日(YYYY-MM-DD形式)')
        public String billingDateFrom;

        @InvocableVariable(required=false
            label='請求日To'
            description='請求日の終了日(YYYY-MM-DD形式)')
        public String billingDateTo;
    }

    public class SearchResponse {
        @InvocableVariable(label='検索結果')
        public String result;

        @InvocableVariable(label='件数')
        public Integer totalCount;

        @InvocableVariable(label='成功フラグ')
        public Boolean success;
    }

    @InvocableMethod(
        label='freee請求書検索'
        description='freee for Salesforceの請求書データを検索します'
        category='freee連携'
    )
    public static List<SearchResponse> searchInvoices(
            List<SearchRequest> requests) {
        List<SearchResponse> responses = new List<SearchResponse>();
        SearchRequest req = requests[0];

        try {
            String query = 'SELECT Name, freee__InvoiceNumber__c, '
                + 'freee__TotalAmount__c, freee__PaymentStatus__c, '
                + 'freee__DealStatus__c, freee__BillingDate__c, '
                + 'freee__DueDate__c, freee__SendingStatus__c, '
                + 'freee__TotalVat__c, freee__Partner__r.Name '
                + 'FROM freee__IV_Invoice__c';

            List<String> conditions = new List<String>();

            if (String.isNotBlank(req.partnerName)) {
                conditions.add(
                    'freee__Partner__r.Name LIKE \'%'
                    + String.escapeSingleQuotes(req.partnerName)
                    + '%\'');
            }
            if (String.isNotBlank(req.paymentStatus)) {
                conditions.add(
                    'freee__PaymentStatus__c = \''
                    + String.escapeSingleQuotes(req.paymentStatus)
                    + '\'');
            }
            if (String.isNotBlank(req.sendingStatus)) {
                conditions.add(
                    'freee__SendingStatus__c = \''
                    + String.escapeSingleQuotes(req.sendingStatus)
                    + '\'');
            }
            if (String.isNotBlank(req.billingDateFrom)) {
                conditions.add(
                    'freee__BillingDate__c >= '
                    + req.billingDateFrom);
            }
            if (String.isNotBlank(req.billingDateTo)) {
                conditions.add(
                    'freee__BillingDate__c <= '
                    + req.billingDateTo);
            }

            if (!conditions.isEmpty()) {
                query += ' WHERE '
                    + String.join(conditions, ' AND ');
            }
            query += ' ORDER BY freee__BillingDate__c DESC LIMIT 50';

            List<freee__IV_Invoice__c> invoices =
                Database.query(query);

            SearchResponse res = new SearchResponse();
            res.totalCount = invoices.size();
            res.success = true;

            if (invoices.isEmpty()) {
                res.result = '該当する請求書は見つかりませんでした。';
            } else {
                List<String> lines = new List<String>();
                lines.add('【freee請求書検索結果 '
                    + invoices.size() + '件】\n');

                for (freee__IV_Invoice__c inv : invoices) {
                    String partnerNameStr =
                        inv.freee__Partner__r != null
                        ? inv.freee__Partner__r.Name
                        : '(取引先未設定)';
                    lines.add('請求書番号 '
                        + (inv.freee__InvoiceNumber__c != null
                            ? inv.freee__InvoiceNumber__c : 'N/A'));
                    lines.add('取引先 ' + partnerNameStr);
                    lines.add('合計金額 ¥'
                        + (inv.freee__TotalAmount__c != null
                            ? String.valueOf(
                                inv.freee__TotalAmount__c.intValue())
                            : '0'));
                    lines.add('請求日 '
                        + (inv.freee__BillingDate__c != null
                            ? String.valueOf(inv.freee__BillingDate__c)
                            : '未設定'));
                    lines.add('');
                }

                Decimal totalAmount = 0;
                Integer unsettledCount = 0;
                Integer unsentCount = 0;
                for (freee__IV_Invoice__c inv : invoices) {
                    if (inv.freee__TotalAmount__c != null)
                        totalAmount += inv.freee__TotalAmount__c;
                    if (inv.freee__PaymentStatus__c == 'unsettled')
                        unsettledCount++;
                    if (inv.freee__SendingStatus__c == 'unsent')
                        unsentCount++;
                }
                lines.add('合計金額 ¥'
                    + String.valueOf(totalAmount.intValue()));
                lines.add('未入金 ' + unsettledCount + '件');
                lines.add('未送信 ' + unsentCount + '件');
                res.result = String.join(lines, '\n');
            }
            responses.add(res);
        } catch (Exception e) {
            SearchResponse errRes = new SearchResponse();
            errRes.success = false;
            errRes.totalCount = 0;
            errRes.result = 'エラーが発生しました '
                + e.getMessage();
            responses.add(errRes);
        }
        return responses;
    }

    private static String getPaymentStatusLabel(String status) {
        if (status == 'unsettled') return '未入金';
        if (status == 'settled') return '入金済み';
        return status != null ? status : '不明';
    }

    private static String getSendingStatusLabel(String status) {
        if (status == 'unsent') return '未送信';
        if (status == 'sent') return '送信済み';
        return status != null ? status : '不明';
    }
}

コードのポイント

設計上の重要ポイント
  • @InvocableMethod アノテーション — ApexクラスがAgentforceのActionとして認識されます。labelとdescriptionはAgent Builder上での表示名と説明文になります。
  • @InvocableVariable アノテーション — 各パラメータにlabelとdescriptionを設定することで、エージェントがユーザーの自然言語入力からパラメータを自動マッピングします。
  • with sharing — 実行ユーザーの共有ルールに従ったデータアクセスを保証します。
  • 動的SOQL — ユーザーの問い合わせ内容に応じて、必要なフィルタ条件のみを動的に組み立てます。

デプロイ方法

開発者コンソールからデプロイする場合の手順です。

  1. Salesforceの右上の歯車アイコンから 開発者コンソール を開く
  2. File > New > Apex Class を選択
  3. クラス名に FreeeInvoiceSearchAction と入力
  4. 上記コードを貼り付けて Save(Ctrl+S)
Agentforce アセットライブラリのアクションタブ

2 Agent Builder で Topic を追加

Apexクラスのデプロイが完了したら、Agent Builderでエージェントに新しいTopicを追加します。

Agent Builder を開く

  1. 設定 > Agentforce エージェント(または Agentforce Studio)に移動
  2. エージェント一覧から「請求トラブル応答用エージェント」をクリック
  3. 画面上部の New Draft をクリックして新しいドラフトを作成
Agent Builder画面

Topic「請求書ステータス確認」の作成

左サイドバーの Topics セクションで + ボタンをクリックし、新しいTopicを作成します。

新しいTopicを追加する画面
設定項目設定値
Topic Label請求書ステータス確認
Topic API NameInvoiceStatusCheck

Classification Description の設定

Classification Descriptionは、エージェントがユーザーの質問をこのTopicに振り分けるかどうかを判断するための説明文です。以下の内容を入力してください。

Classification Description の入力内容

このTopicは、ユーザーが特定の取引先やプロジェクトに関する請求書の発行状況・送付状態・入金状態を確認したい場合に使用します。

該当する質問の例

  • 「A社の請求書の状況は?」
  • 「今月発行した請求書の一覧を見せて」
  • 「まだ送付していない請求書はある?」
  • 「B社向けの3月分の請求書は発行済み?」
  • 「未入金の請求書を教えて」

該当しない質問の例

  • 入金の消込確認
  • freee会計の仕訳・取引データの検索
  • 請求書の新規作成依頼
ポイント

Classification Descriptionには、該当する質問例だけでなく「該当しない質問例」も記述することで、Topicの振り分け精度が大幅に向上します。

Topic エディタ画面

Scope の設定

Scopeは、このTopicでエージェントが「できること」と「できないこと」を定義します。

エージェントが実行できる操作
  • freee請求書データの検索・取得
  • Salesforce上の取引先情報との名寄せ(取引先名での照合)
  • 請求書のステータス(下書き・送付済み・入金済み等)の確認と報告
  • 複数請求書の一覧表示とフィルタリング(期間・取引先・ステータス別)
エージェントが実行できない操作
  • 請求書の新規作成・編集・削除
  • 入金の消込処理
  • freee会計の仕訳データへのアクセス
Topicに紐づけたアクションとパラメータの一覧

Instructions の設定

Instructionsは、エージェントがこのTopic内でどのように振る舞うかを制御する指示です。

Instructions の入力内容
  1. 取引先名を指定した場合 — Action「freee請求書検索」を呼び出し、取引先名をパラメータとして検索。件数、ステータス、金額、発行日を一覧形式で回答する。
  2. ステータスで絞り込んだ場合 — 該当するステータスコードにマッピングし(unsettled=未入金, settled=入金済み等)、フィルタ結果を件数とともに回答する。
  3. 期間を指定した場合 — 指定された期間を日付範囲に変換し(例 「今月」→ 2026-03-01〜2026-03-31)、検索を実行する。
  4. データが見つからない場合 — 「該当する請求書が見つかりませんでした」と回答し、取引先名の表記揺れの可能性を示唆する。

回答フォーマット

  • 必ず件数を最初に伝える(例 「A社の請求書は3件見つかりました」)
  • 各請求書は「請求書番号 / 金額 / 発行日 / ステータス」の形式で表示
  • 金額は3桁カンマ区切りで表示(例 ¥1,500,000)
InvoiceStatusCheck Topicが追加されたAgent Definition

3 Action を Topic に紐づける

Topicの設定が完了したら、Step 1で作成したInvocable ApexクラスをActionとして登録します。

Action の登録手順

  1. Agent Builderの左サイドバーで、作成した InvoiceStatusCheck Topicを展開
  2. Topic設定画面内の Actions セクションで + New Action をクリック
  3. 以下の内容を設定して Save をクリック
設定項目設定値
Action TypeApex Invocable Action
Actionfreee請求書検索(FreeeInvoiceSearchAction)
Action Labelfreee請求書検索
Apex呼び出し可能メソッドを選択している画面

Action のパラメータ確認

登録後、Actionの詳細画面でパラメータが正しく認識されていることを確認します。

パラメータ名必須説明
partnerNameStringNo検索したい取引先名(部分一致)
paymentStatusStringNo入金ステータスでフィルタ
sendingStatusStringNo送信ステータスでフィルタ
billingDateFromStringNo請求日の開始日
billingDateToStringNo請求日の終了日
Actionの入力/出力パラメータ設定画面
ポイント

すべてのパラメータが required=false であるため、ユーザーが条件を省略しても全件検索として動作します。「未入金の請求書は?」のような質問では、エージェントが自動的に paymentStatus=unsettled を設定します。

4 テスト実行

設定が完了したら、Agent Builderのプレビュー機能を使ってエージェントの動作を確認します。

テスト環境の確認

Agent Builder画面の右側に表示されているチャットパネルでテストを実行できます。テスト前に、freee for Salesforceの請求書データがサンドボックス内に存在することを確認してください。

本サンドボックスには以下のテストデータが登録されています。

請求書番号取引先合計金額入金送信
INV-0000000003ひだまりネクスト株式会社¥1,100,000未入金未送信
INV-0000000008ひだまりネクスト株式会社¥13,200,000未入金未送信
INV-0000000006ひだまりネクスト株式会社¥0未入金未送信
INV-0000000007ひだまりネクスト株式会社¥13,200,000未入金未送信
INV-0000000009ひだまりネクスト株式会社¥13,200,000未入金未送信

テスト会話パターン

以下の5パターンでテストを実行し、期待通りの回答が得られることを確認します。

パターン 1 全件検索

ユーザー 「現在の請求書の状況を教えて」
期待結果 5件の請求書一覧が表示される

テストパターン1の実行結果
パターン 2 ステータスフィルタ

ユーザー 「未入金の請求書はある?」
期待結果 paymentStatus=unsettledで検索され、5件が表示される

テストパターン2の実行結果
パターン 3 取引先名検索

ユーザー 「青空コーポレーションの請求書を見せて」
期待結果 partnerNameで検索され、該当件が表示される

パターン 4 該当なし

ユーザー 「株式会社テストXYZの請求書はある?」
期待結果 「該当する請求書が見つかりませんでした」と表示される

パターン 5 複合条件

ユーザー 「青空コーポレーションの未入金の請求書を確認して」
期待結果 partnerName + paymentStatus=unsettled で検索される

Reasoning Log の確認

テスト実行後、Agent BuilderのReasoning Logを確認して、エージェントが正しくTopicを選択し、適切なパラメータでActionを呼び出しているかを検証します。

確認項目期待値
Topic SelectionInvoiceStatusCheck が選択されている
Action Selectionfreee請求書検索 が呼び出されている
Parameter Mappingユーザーの入力から適切なパラメータが設定されている
Response Quality件数・金額・ステータスが正確に表示されている

5 freee MCP との連携(応用編)

ここまでの構成では、freee for Salesforceパッケージで同期されたSalesforce内のデータを検索しています。さらに一歩進めて、freee MCP(Model Context Protocol)を活用することで、freeeのAPIにリアルタイムでアクセスし、より幅広いデータを取得できるようになります。

freee MCP とは

freee MCPは、freee公式がOSSとして公開しているMCPサーバーです。freee Public APIをMCPツールとして網羅的に公開しており、Claude DesktopやClaude CodeなどのMCPクライアントから、自然言語でfreeeのデータにアクセスできます。

項目内容
認証方式OAuth 2.0 + PKCE(トークン自動更新対応)
対応サービス会計・人事労務・請求書・工数管理・販売(5サービス)

Agentforce と freee MCP の連携フロー

AgentforceのネイティブMCPクライアント機能を使うことで、Agent Builderから直接freee MCPサーバーに接続できます。

ユーザー Agentforce freee MCP freee API
注意事項

2026年3月時点では、AgentforceのネイティブMCPクライアント機能はPilot段階です。GA版のリリース時期はSalesforce公式発表をご確認ください。Pilot未参加の環境では、Step 1で紹介したApex Invocable Action方式でfreee for Salesforceのデータを活用してください。

応用ユースケース

本記事で構築したエージェントをベースに、さらに発展させることができるユースケースを紹介します。

1. 入金期限超過アラートの自動送信

スケジュールフロー(毎朝9時実行)で未入金かつ入金期限超過の請求書を検出し、Slack通知やメール送信を自動化します。

毎朝9時 自動実行 未入金請求書を検索 期限超過をフィルタ Slack / メール通知

2. Salesforce 商談金額との自動照合

商談のCloseDate到来時に、freeeの入金データと自動照合し、消込漏れをリアルタイムに検知します。金額の一致・不一致・振込手数料差異を自動判定できます。

3. 税理士事務所での顧問先請求管理

顧問先ごとにfreeeアカウントを切り替えて請求書ステータスを一元管理する構成です。AgentforceのマルチテナントTopicとして構築することで、1つのエージェントで複数のfreee事業所のデータを横断検索できます。

4. 月次決算前の請求書ステータス一括チェック

月末の経理業務として、全取引先の請求書ステータスを一括で確認するレポートを自動生成します。Agentforceに「今月の請求書ステータスサマリーを出して」と依頼するだけで、送信済み/未送信/入金済み/未入金の内訳を取引先別に集計してくれます。

まとめと本番運用に向けて

本記事で構築したもの

コンポーネント内容
Apex クラスFreeeInvoiceSearchAction(freee請求書データの検索)
Topic請求書ステータス確認(InvoiceStatusCheck)
Actionfreee請求書検索(Apex Invocable Action)
対応する問い合わせ取引先名検索、ステータスフィルタ、期間指定、複合条件

構築にかかった時間

作業所要時間
Apexクラスの開発・テスト約1時間
Agent BuilderでのTopic・Action設定約30分
テスト・チューニング約1時間
合計約2.5時間

導入効果の見積もり

指標BeforeAfter
請求書ステータス確認の時間5分/件(freeeにログイン→検索→確認)10秒/件(Agentforceに質問するだけ)
月間の確認作業工数(50件/月)約4時間約8分
確認漏れのリスク月次締めまで検知不可リアルタイムで検知可能

本番運用時の拡張ポイント

さらなる発展
  • Topic の追加 — 「入金消込チェック」「freee取引データ参照」Topicを追加することで、より包括的な請求管理エージェントに拡張できます。
  • freee MCP 連携 — Agentforce MCPクライアントのGA後、freee MCPとの直接連携に切り替えることで、リアルタイムデータにもアクセス可能になります。
  • Knowledge 記事との連携 — 「請求書が届いていないと言われた場合の対応手順」などのFAQ記事を登録することで、実務的なガイダンスも提供できるようになります。
freee × Agentforce 連携のご相談はこちら

freee for Salesforceの導入支援からAgentforceのカスタマイズまで、一貫してサポートいたします。

無料相談はこちら
Facebook
X
LinkedIn

関連記事