この記事は LayerX AI Agent ブログリレー 21日目の記事です。
バクラク申請・経費精算チームでテックリードをしている ktr です。私たちのチームでは、お客様のより複雑な課題を解決するため、AI Agent の PoC (Proof of Concept、概念実証) を進めています。今回は「申請の自動作成 AI Agent」に焦点を当て、開発における技術的な課題とその解決策を、試行錯誤の過程と共にご紹介します。
なお、本記事で紹介する機能はあくまで PoC 段階のものであり、正式なリリースが決定しているわけではないことをご了承ください。
申請作成 AI Agent の概要
バクラク申請・経費精算では日々の稟議や経費精算の申請を集約し、効率的に統制管理するための仕組みを提供しています。
ユーザーは目的に合った申請フォームを選び、証憑や必要な情報を入力して申請を作成します。例えば取引先から請求書を受領した場合、その支払いを行うために支払申請フォームを利用します。これらの作業は重要なプロセスですが、同時に煩雑で退屈なものでもあります。申請者は本来の業務から離れてこれらの作業を行う必要があり、生産的な活動ができる時間を犠牲にしています。
バクラクではこれまでもこうした作業を極力減らし、使いやすいプロダクトを実現するための機能開発を進めてきました。LLMの登場と急速な発展により、従来のルールベースでは解決が難しかった課題にも対応できるようになりました。
そこで、請求書や領収書といった証憑から申請を自動作成する AI Agent PoC を開発しました。
この機能では、証憑をアップロードするだけで、AI Agent が最適な申請フォームや関連する過去の申請を特定し、それらの情報をもとに新しい申請を自動で作成します。これにより、ユーザーは申請作成の手間を大幅に削減でき、最終的には AI Agent が作成した申請内容を確認・提出するだけで完了します。
ただし、この AI Agent の開発には多くの課題がありました。以降ではいくつか具体例を示しながら、これらの課題をどのように解決したのかを解説します。
既存 API の複雑性と LLM
バクラク申請・経費精算には非常に多くの構成要素があります。たとえば申請を作成するには、どの申請フォームを使うか、誰が承認者になるべきか、フォームに入力する日付や金額、添付ファイル、紐づく購買申請など、ここに書ききれないほどの入力値が存在します。
当然、これらの要素を扱う既存の API も非常に複雑な仕様になっています。一例を挙げると、もっとも単純な経費精算の申請を作成する API でさえ、40個以上のリクエストフィールドがあります。
加えて、申請フォームは管理者が自由にカスタマイズできるため、たとえばフォーム A では使われている入力フィールドがフォーム B では使われていない、といったことがしばしばあります。既存の申請作成 API では、どんな申請フォームからでも申請をつくれるようになっているため、リクエストのフィールドの数が多く、複雑になっています。
また、参照系 API はリソース指向の設計となっており、フロントエンドアプリケーションが柔軟にリソースをフェッチできる仕組みになっています。
AI Agent を構築する際、既存の API を薄くラップしたツールを作成するのは一つの方法です。特に、リソース指向の参照系 API であれば、一つの汎用的なツールで幅広いデータを取得できるため、一見すると理にかなっています。
しかし、このアプローチは LLM にとって最適ではありませんでした。汎用的なツールを使うと、LLM はまずデータを取得し、その結果を解釈してから次のアクションを推論するという多段階の思考を強いられます。このプロセスが複雑になるほどエラーの可能性が高まり、さらに必要以上のデータを取得してコンテキストウィンドウを圧迫するという問題も生じました。
実際、私たちが初期に開発した LLM へのコンテキストがデザインされていなかった PoC では、この問題が顕著でした。LLM にツールを使わせると、途中で使い方を間違えたり、存在しない ID や値を生成 (ハルシネーション) したりといった想定外の挙動が多発し、動作が安定しませんでした。
Anthropic の記事 Writing effective tools for agents — with agents でも次のように述べられています。
A common error we’ve observed is tools that merely wrap existing software functionality or API endpoints—whether or not the tools are appropriate for agents. This is because agents have distinct “affordances” to traditional software—that is, they have different ways of perceiving the potential actions they can take with those tools
私たちがよく目にするよくある誤りは、既存のソフトウェア機能やAPIエンドポイントを単にラップするだけのツールです。そのツールがエージェントに適しているかどうかは関係ありません。これは、エージェントが従来のソフトウェアとは異なる「アフォーダンス」を持っているためです。つまり、それらのツールを使って実行できる可能性のあるアクションを、エージェントは異なる方法で認識しているのです。
We recommend building a few thoughtful tools targeting specific high-impact workflows, which match your evaluation tasks and scaling up from there.
評価タスクに適した、影響の大きい特定のワークフローを対象とした、思慮深いツールをいくつか構築し、そこからスケールアップしていくことをお勧めします。
私達も既存の API を単純にラップするだけではうまくいかないと考え、より LLM フレンドリーな API やツールを新たに構築しました。
主に構築したのは次のようなツールです。
- 類似した過去申請の候補を取得するツール
- 過去申請の内容を取得するツール
- AI-OCR による入力補完を行うツール
- 申請作成ツール
これらのツールは状況に応じて統合することも可能です。例えば、2 と 3 を一つにまとめ、「過去申請と証憑を入力として今回の申請データを作成する」ツールにできるでしょう。しかし今回のケースでは、証憑に基づいて上書きされた項目を具体的に LLM に把握させるため、意図的にツールを分けて定義しています。
また、2 の申請内容取得ツールについては、既存 API のレスポンスをそのまま返すのではなく、「情報量を減らし、モデルが解釈可能な表現で」レスポンスを返すよう設計しました。
たとえば、もっとも単純な経費精算申請のレスポンスの例はこのような形になりました。申請の作成に必要なものだけを抽出し、不要なフィールドをすべて削ぎ落としています。フィールドの取捨選択は申請フォームの設定をもとに動的に行っています。
{ "formId": "testPreviousFormId", "request": { "title": "2025/09 経費精算", "requestDetails": [ { "detailDate": "2025-08-15", "expenseAccountItem": "会食費", "paymentAmount": 12000, "title": "バクラクレストラン", "description": "株式会社 XX の A さんとの会食です" } ] } }
前述したとおり、申請フォームは動的であり、各フォームで入力可能なフィールドが異なります。そのため、申請作成 API で受け取れるすべてのリクエストフィールドを公開するのではなく、実際に必要なフィールドのみに絞って提示することが重要です。
申請作成ツールでは input_schema に利用する JSON Schema を動的に生成しています。こちらもなるべく余計なパラメータを減らすための取り組みです。具体的な実装としては、その申請を作成するための申請フォーム専用のスキーマ取得エンドポイントを用意することで、特定の申請作成に特化した入力をつくれるようになっています。
curl https://test.invalid/api/forms/<申請フォームの ID>/schema
{ "type": "object", "properties": { "title": { "type": "string", "minLength": 1, "description": "申請名", "default": "2025/09 経費精算" }, "requestDetails": { "type": "array", "items": { "type": "object", "properties": { "detailDate": { "type": "string", "description": "支払日時" }, "paymentAmount": { "type": "number", "description": "金額" }, "title": { "type": [ "string", "null" ], "description": "支払先" }, "description": { "type": [ "string", "null" ], "description": "内容・メモ" } }, "required": [ "detailDate", "paymentAmount" ], "additionalProperties": false }, "minItems": 1 } }, "required": [ "requestDetails" ], "additionalProperties": false }
申請内容取得ツールで取得できる内容もこのスキーマに準拠しているため、取得したデータをそのまま申請作成ツールに渡すだけで、同一内容の申請を作成できます。このように、APIやツールを通じて必要最小限の情報だけをやり取りし、LLM の判断余地を極力減らす工夫により、動作の安定性が大きく向上しました。
バクラクの既存資産をフル活用する
前述したとおり、安定した動作をする AI Agent をつくるには LLM が扱うタスクの数を減らしたり小さく分解し、なるべく LLM が解く問題領域を狭めることが重要です。バクラクには精度の高い AI-OCR があり、これを使うことで高速かつ安定した証憑の読み取り、請求書の取引先や金額の読み取りなどを実現することができます。さらに、その取引先からの請求書を過去どの申請フォームで提出したかや、どのような申請だったかも取得することができるので多くの前処理を LLM を介さずに行うことができます。
一方で AI-OCR ではカバーできない箇所も当然あるので、そういったところでは LLM を使うことで解決していきました。
業務プロセスの理解
業務プロセスの深い理解が、私が個人的にもっとも重要だと考えている点です。日常的にどのような業務があり、どのような手順で進められているかを把握しなければ、要件定義はできません。AI Agent はおろか、基本的なシステム化さえ困難です。業務プロセスを詳細に理解し、具体的なユースケースや課題を特定することで、AI Agent で解決すべき課題とそうでない課題を明確に区別でき、適切な設計が可能になります。
私たちの PoC は、当初はチャット UI ベースの申請作成 AI Agent でした。しかし、ユースケースを絞り込み、請求書と過去申請から支払申請を作成する体験へと焦点を移しました。理想的には幅広い業務ドメインの多様なタスクを解決できることですが、それは特定ドメインの特定タスクより格段に難しくなります。そこで、まずは業務ドメインとタスクの両方を絞ることにしました。

検討の結果、取引先から毎月届く請求書メールをトリガーとして、過去申請を検索し、AI-OCR で読み取ったデータを活用して支払申請を作成するワークフロー型アプローチを採用しました。
このワークフロー型アプローチにより、あらかじめ定義された手順に沿って処理を進められるようになりました。チャットベースでは、ユーザーとの対話をもとに LLM が推論を行いながら tool call する必要がありますが、今回のアプローチでは LLM に複雑な推論や試行錯誤的な tool call を要求せず、定義された手順に従って必要な API を順次呼び出し、LLM の介入は必要な箇所に限定できます。

バクラク申請・経費精算との統合
PoC で一定レベルの AI Agent を開発できましたが、本機能としてリリースする際にはバクラク申請・経費精算に適切に組み込む必要があります。システムが想定通りに動作することと、お客様が自然に使える形で体験設計することは、考慮すべき点が異なります。具体的には、以下のような課題があります。
- ユーザーとのインタラクション
- 請求書メール受領後、いつユーザーに通知し、追加アクションを促すかが重要です。Human-in-the-Loop (HITL) が少ないほど AI Agent は自律的に動作しますが、タスク完遂の確実性は下がります。一方、HITL が多すぎると情報提供や安全なツール実行は可能になりますが、ユーザーの注意が頻繁に AI Agent に奪われ、業務効率化という本来の目的が達成できなくなる恐れがあります。
- AI が作成した申請と人間が作成した申請の区別
- この区別がないとユーザーが混乱する可能性があります。人間が作成した申請は後で編集したり、仮の値を入れたりする前提がありますが、AI が作成した申請は提出できる段階まで作り込まれており、人間による最終確認だけで済むはずです。
- AI Agent の認証・認可
- AI Agent が自律的にタスクを実行してくれるのは便利ですが、AI Agent はどのように認証され、どの程度の権限を持つべきでしょうか?ユーザーの代理として動作する場合、どのように認可を取得すべきでしょうか?
他にもまだまだあります。これらの課題は現時点でも「これだ!」という明確な答えは出ておらず、議論と試行錯誤を続けています。
まとめ
この記事では、申請の自動作成 AI Agent の PoC を通じて、私たちが直面した技術的な課題と、その解決に向けた試行錯誤のアプローチをご紹介しました。
AI Agent の開発は、業務ドメインやプロセスの理解といった今までのソフトウェア開発でも重要な要素に加えて、LLM の不安定さをどう解決し、性能を高めていくかというコンテキストエンジニアリングの両軸のスキルが求められます。
まだまだ業界でもベストプラクティスが固まりきっておらず、各社試行錯誤の段階だと思います。私達の PoC でも今回話すことができなかった課題や、本機能として組み込んでいく際に考えていかなければいけない課題などがたくさんあります。まだまだわからないことばかりですが、一つずつ手を動かして試行錯誤していきたいと思っています。
このように、LayerX では AI Agent による新しい体験・課題解決を届けるために日々取り組んでいます。もし少しでも興味を持っていただけたらぜひ一度お話しましょう!
最後までお読みいただき、ありがとうございました。明日以降もまだまだブログリレーは続くのでぜひお楽しみに!