LLMを「主役」にしないための3つの原則〜求人票自動生成システムの本番開発を通じて学んだこと〜【AI機能実装知見/プロダクト開発エンジニア勉強会/イベントレポート】

※記事公開時点(2026年6月)の内容をレポートしたものです。

登壇者はこの方

*

宇賀神拓也

パーソルキャリア株式会社
データ・AIソリューション本部
リードエンジニア

2023年にパーソルキャリアに入社。前職ではAIベンチャーで自社サービスの開発に従事。現在はバックエンド開発を担当。

 

 

speakerdeck.com

宇賀神:2023年にパーソルキャリアに入社いたしました宇賀神と申します。前職のAIベンチャーでは自社サービス開発や社内PoC向けのシステム開発に従事し、現在は主にバックエンド開発や社内外向けのシステム開発を担当しております。本日は「LLMを「主役」にしないための3つの原則〜求人票自動生成システムの本番開発を通じて学んだこと〜」というテーマお話させていただきます。

求人票自動作成プロジェクトの概要

本プロジェクトの課題と目的、システム構成について説明します。

現状の課題は、お客様(求人企業)からの求人依頼を受けてから既存の「求人票管理システム」へ登録するまでに多くの工数がかかっている点です。本プロジェクトは生成AIを活用し、工数削減を目指します。

本システムは2026年3月に本番リリースを完了し、現在は実業務で活用されています。

従来のフローでは、リクルーティングアドバイザー(企業側の採用支援を行う担当者)が手作業で求人票を作成し、審査グループによる内容チェックを経た上で、求人票管理システムに登録していました。

本システムの導入後は、上図のように、AIが求人票の作成を行います。リクルーティングアドバイザーは生成された内容を確認・修正し、審査グループがチェックを行うという流れに変革しました。

なお、本システムを構築する前は、一部のリクルーティングアドバイザーが社内専用のLLMサービスを個別に活用し、工夫したプロンプトで求人票のひな形を作ってからシステムへコピー&ペーストするという作業を行っていました。今回の開発では、そうした一連の作業も含めてシステム化し、自動化・効率化を図っています。

LLMを「主役」にしないための3つの原則

ここからは、本プロジェクトを通じて得られた、LLMを業務システムに組み込むための具体的な設計原則について3つに分けてお話しします。

原則1 - LLMに苦手なことをやらせない

本番運用において直面した問題の一つに、既存システムと連携するための「コード値」の扱いがあります。

求人票を管理システムに登録する際、職種や業種といった項目はテキストではなく、正確なコード値でデータベース(DB)に保存する必要があります。PoCの段階では、LLMにプロンプトで職種などを自然言語で出力させ、それをそのまま利用しようとしていました。しかし、LLMは確率的に動くため出力が安定せず、DBへ正しく保存できないという課題が生じました。

また、職種や業種のマスターデータは非常に膨大であり、それらをすべてプロンプトに含めるとトークンを大量に消費します。さらに、すでに現場で効果を発揮していたプロンプトの構成を大きく変更せねばならず、出力性能が変化してしまうリスクもありました。

そのため、LLMの内部でコード値を直接出力させることは断念し、LLMが得意とする「自然言語の生成・抽出」のみに特化させ、苦手なコード値の選択には専用の仕組みを外側に用意するアプローチをとりました。

ベクトルの類似度を用いたコード値変換

代替案として採用したのが、ベクトルの類似度を用いたコード値変換の仕組みです。一般的にはRAG(検索拡張生成)やファインチューニングといった手法が挙げられますが、今回のマスターデータはRAGを使うほど大規模ではなく、ファインチューニングを行うのは過剰であると判断しました。よりシンプルで軽量な仕組みが適していると考え、この手法に至りました。

具体的な処理の流れは以下の通りです。

  1. リクルーティングアドバイザーが入力した「求人要件のメモ」をLLMに入力し、必要な資格情報などを自然言語で抽出させる。
  2. 抽出されたテキスト結果をエンベディングし、ベクトル化する。
  3. あらかじめシステム側で用意しておいた「職種・業種名」「コード値」「エンベディング結果(ベクトル)」の3つをペアにした変換表(マスタ)を用意する。
  4. LLMの出力結果のベクトルと、変換表の各行のベクトルとの類似度を1つずつ計算し、最も類似度が高い(一番近い)職種をマッピングして正しいコード値を返す。

この仕組みを構築したことにより、確実に正しいコード値を既存システムへ連携することが可能となりました。

原則2 - LLMは失敗する前提で設計する

LLMは、いつ、どの程度エラーを起こすか予測が困難です。事前に検証用スクリプトを作成して100回ほど連続でAPIを叩くテストを行いましたが、その際はエラーも発生せず、レイテンシーも安定していました。そのため初期は深く懸念していませんでしたが、実際のPoCを進めると、応答が返ってこないケースやエラーが発生するケースを確認しました。この経験から、「失敗を前提とした設計」が非常に重要であると実感しています。

システム側でのリトライ

システム側には、一般的なエラーハンドリングの手法を網羅的に実装しました。具体的には以下の通りです。

  • Exponential Backoff and Jitterを用いたリトライの最適化
  • 不正なレスポンスフォーマットが返却された場合のリトライ
  • タイムアウト発生時のリトライ
  • 不適切な出力(ハルシネーション等)が検出された場合のリトライ

処理時間の変動を見据えた非同期処理

リトライ処理を組み込むと、どうしても全体の処理時間が伸びてしまいます。

当初の画面設計では、ユーザーがデータ入力を終えてから生成が完了するまで画面の前で待機する「同期処理」のフローを検討していました。

しかし、処理の遅延やリトライを考慮するとこの設計は適切ではないため、LLMに関連する処理はすべて裏側で実行する非同期処理へと変更しました。

非同期化に伴い、処理完了をユーザーに伝えるための通知フローを別途設計する必要が生じますが、システムを安定させるためには非同期設計が必須であると言えます。

業務イベントとしてLLMの生成エラーを扱う

システム側でリトライを尽くしても、最終的に生成が失敗してしまうケースはゼロにはできません。そのため、処理結果のステータスに「生成失敗」や「再生成」という状態を定義し、業務エラーとして扱えるようにしました。これにより、システムが停止するのではなく、ユーザーが画面上で自らリカバリーできる設計にしています。

具体的な画面仕様としては、エラーの種類を「LLM起因のエラー」と、バグなどによる「システム起因のエラー」に明確に分離しています。

  • LLM起因のエラー(タイムアウトや不正出力など): 画面上に「生成失敗」と表示され、ユーザーが任意のタイミングで「再実行」ボタンを押してリトライできるようにしています。また、生成処理が長すぎる場合には「キャンセル」も可能です。
  • システム起因のエラー(プログラムの停止など): ユーザー側では回復できないため「システムエラー」と表示し、再実行ボタンは表示しない制御にしています。

LLMの処理が失敗した場合の運用フローの設計

異常を検知した際、エンジニア側へSlack等で通知が飛ぶ監視体制を構築することはもちろんですが、本番リリース前に「失敗時の運用フロー」をユーザー側と明確に合意しておくことが重要です。システムエラーの際はエンジニアが調査・即時リカバリーを行い、復旧後にステータスを更新してユーザーへメールで完了通知を出す、といった一連の対応フローをあらかじめ設計しておくことで、本番稼働後の混乱を防ぐことができます。

原則3 - 1番大変なのはLLMの外側

ここまでLLMの特性や扱い方について説明してきましたが、本プロジェクトにおいて最も開発工数がかかったのは、LLMのモデル選定やプロンプト調整の領域ではありません。実は、今回構築した新システムと、既存の「求人票管理システム」を結合・連携させる部分が最も大変であり、システム開発の大部分の工数をここに費やしました。

通常のシステム開発においても多システム連携は難所となりますが、本プロジェクトも例外ではありませんでした。

参考値としてソースコードのステップ数をツール(cloc)でカウントしたところ、全体の66%がLLM以外の外側の処理であり、LLMに関連する処理は34%に留まりました。もちろんステップ数の多さがそのまま作業工数に直結するわけではありませんが、本番環境で耐えうるシステムにおいて、LLMは全体を構成する一部の機能に過ぎないということを示しています。

既存システムが持つ複雑なビジネスルール

工数が肥大化した最大の理由は、既存の求人票管理システムに大量の複雑な依存ルール(仕様)が存在していたためです。

  • 賃金形態(年俸制、月給制、日給制など)が変更されると、連動して関連する十数個のフィールドの値をクリア、保持、あるいは初期値セットする連鎖処理が発生する。
  • 労働時間区分(通常、みなし、変形、フレックスなど)と就業時間区分、およびコアタイム・フレキシブルタイムの有無の組み合わせによって、クリアすべき対象フィールドが異なる。
  • 休日休暇区分(週休、月休)において、曜日指定の数と週休の日数が一致しているかどうかのバリデーションチェックが必要となる。
  • 「月給 × 12ヶ月 + 賞与」の計算結果と、登録される想定年収が一致しているかを検証する。

LLMが生成したテキストを既存システムへ正常にインポートするためには、これらと同等の複雑なビジネスルールに基づくチェックロジックを、今回開発したシステム側にも実装する必要がありました。この仕様を正確に理解し、システムへ落とし込む作業に後半で気づかされ、非常に苦労することとなりました。

運用・保守におけるリアルな課題

2026年3月のリリース以降、実際に運用を始めてからも、以下のような多くの課題に直面しています。

  • 利用率の向上: リリース直後の4月頃はなかなか利用率が上がらず、社内での利用促進に向けた対策やアプローチを打つ必要がありました。
  • 仕様変更への追随: 既存の求人票管理システムの仕様が変更された際、こちらのシステムもどのように追随していくかという保守体制の検討が必要です。
  • 運用体制の移管: LLMを用いたサービスの運用や障害対応は、従来のシステムと異なるノウハウが必要となるため、開発チーム以外への運用移管(受け入れ先の選定)に難航しました。
  • 想定外の利用方法への対応: ユーザーに対しては「顧客からヒアリングした要件メモを入力してください」とアナウンスしているものの、入力欄に企業のWebサイトのURLだけを別途貼り付けて「これで動くはず」と実行されるケースがあり、結果として何も生成されないという事象が発生しました。ハルシネーション(嘘の生成)対策も含めて、入力制御やエラーハンドリングの強化を迫られています。
  • 外部環境の激変: システム開発を進めている最中にも、技術トレンドは目まぐるしく変化しました。RAGが主流になったかと思えば、瞬く間にMCP(Model Context Protocol)やAIエージェントといった新しい概念が登場しています。今回開発したシステムは、技術的な構成としては目新しさのないオーソドックスなものかもしれませんが、外側のシステムや運用を構築している間にも周囲の技術環境が進化していくため、それらの新技術を今後どう取り込んでいくかという議論も必要だと感じています。

まとめ

今回お伝えした「LLMを主役にしないための3つの原則」を振り返り、まとめといたします。

  1. LLMに苦手なことをやらせない
    • 自然言語処理や抽出といったLLMが得意な領域だけを任せ、コード値の変換や厳密なデータ整合性の担保といった処理は、外側の専用ロジックに任せる設計が賢明です。
  2. LLMは失敗する前提で設計する
    • システム側で自動リトライを行うことは前提としつつ、処理時間の変動を見据えて完全な非同期処理でパイプラインを組むことが大切です。また、生成失敗という状態を仕様(業務イベント)として許容し、ユーザー自身で再実行やリカバリーができる画面・業務フローをあらかじめ考慮し、運用を握っておく必要があります。
  3. 1番大変なのはLLMの外側
    • 既存システムとの連携や、泥臭いビジネスルールの実装こそが開発の大半を占めます。LLMはプロダクトにおける「一つの機能(パーツ)」に過ぎないという視点を持ち、運用後に次々と出てくる課題に対して優先順位をつけながら対応していく体制が重要となります。

 

 

最後に1点紹介します。パーソルキャリアのエンジニアリング組織の「技術」「人」「組織」については技術ブログ「techtekt(テックテクト)」でも発信しています。また、私たちの組織に興味をお持ちの方は、採用サイトもご覧ください。

 

 

Community Members

さまざまなテーマで事例や知見を学ぶ
IT・テクノロジー人材のための勉強会コミュニティ

①上記ボタンをクリックするとTECH PLAY(外部サイト)へ遷移します。

②TECH PLAYへ遷移後、アカウントをお持ちでない方は、新規会員登録をお願いいたします。

③TECH PlAY会員登録後、TECH Streetページよりグループフォローをしてください。

今後のイベント参加・メンバー登録に関する重要なお知らせはこちら