過去の応募者の中から新しい求人に合う人を洗い出し、再接触の優先度とスカウト文の下書きを作る
新しく出た求人の要件を入力に、過去の応募者(不合格・辞退・保留)の職務経歴から近い人をベクトル検索で洗い出し、再接触の優先度とスカウト文の下書きを作ります。過去の応募者を思い出して探し直す作業が減ります。
- 生成AI
- ChatGPT/Claude/Gemini
- AIサービス
- Azure AI/Google Vertex AI/OpenSearch
- 対象業界
- IT・SaaS/人材/製造
- 対象部門
- 人事/採用
- 対象業務
- 情報検索/書類作成
- 主な課題
- 人手が足りない/属人化している/情報が見つからない
- AIで行う処理
- 検索(RAG)
- 主な効果
- 工数削減/検索時間短縮/機会損失防止
- 導入難易度
- ★★★☆☆
- 実装レベル
- 本格構成
- 費用感
- RAG・個別開発(大)
- 人間の確認
- 条件付き
01導入前 / 導入後の業務フロー
- 新しい求人票を読み、必須要件と歓迎要件から検索に使う言葉を書き出す
- ATSで職種名・技術名・資格名を1語ずつ検索し、応募日と選考結果で絞り込む
- 引っかかった応募者の職務経歴書を1人ずつ開き、要件に当たる経験があるかを読む
- 面接の評価記録を開き、前回なぜ見送ったか、なぜ辞退されたかを確かめる
- 声をかけてよい人か(連絡不要の申し出や保存期間)を台帳で確かめる
- 候補を数名に絞り、1人ずつスカウト文を書く
- 自動月に一度、保存期限を過ぎた人と連絡不要の人を検索の対象から外す
- 人採用担当が求人票を承認し、必須要件と歓迎要件を項目ごとに入力する
- 自動求人の承認をきっかけに、要件を1項目ずつ埋め込みベクトルにする
- 自動要件ごとにベクトル検索を行い、近い職歴を持つ応募者を集める
- 自動応募者ごとに、どの要件に何件の職歴が当たったかをまとめる
- 自動生成AIが、当たった職歴の根拠と、前回の見送り理由が今回の必須要件に重なるかを整理する
- 自動前回の選考結果と経過期間から、優先度 `A` / `B` / `C` / `hold` を規則で決める
- 自動`A` と `B` の人について、スカウト文の下書きを作る
- 人採用担当が候補一覧と根拠を確かめ、声をかける人を決める
- 人下書きを直し、ATSから送る
各工程の詳しい説明を読む
- 新しい求人票を読み、必須要件と歓迎要件から検索に使う言葉を書き出す
- ATSで職種名・技術名・資格名を1語ずつ検索し、応募日と選考結果で絞り込む
- 引っかかった応募者の職務経歴書を1人ずつ開き、要件に当たる経験があるかを読む
- 面接の評価記録を開き、前回なぜ見送ったか、なぜ辞退されたかを確かめる
- 声をかけてよい人か(連絡不要の申し出や保存期間)を台帳で確かめる
- 候補を数名に絞り、1人ずつスカウト文を書く
(a)言い換えを拾えない。 2番のキーワード検索は、求人票の言葉がそのまま書類にある人しか出しません。職務経歴書は人によって書き方がまるで違います。 同じ経験が「顧客折衝」「提案営業」「アカウント担当」と書かれ、検索語を増やすほど読む書類が増えます。
(b)読む量が多すぎる。 3番で1件の求人につき数十名の書類を開くと、それだけで1時間を超えます。忙しい月は、検索結果の上から数名を見て終わりにします。 下のほうにいた人は、見られないまま次の求人に移ります。
(c)前回の結果を見落とす。 4番と5番を省くと、前回と同じ理由で見送る人に声をかけたり、「今後の連絡は不要」と言われた人に送ったりします。 どちらも取り消せない失敗です。
(d)担当者の記憶に頼っている。 いちばん当たるのは「あの人が合いそう」という記憶で、担当者が替わると、その分の候補は消えます。
- 【自動】 月に一度、保存期限を過ぎた人と連絡不要の人を検索の対象から外す
- 【人】 採用担当が求人票を承認し、必須要件と歓迎要件を項目ごとに入力する
- 【自動】 求人の承認をきっかけに、要件を1項目ずつ埋め込みベクトルにする
- 【自動】 要件ごとにベクトル検索を行い、近い職歴を持つ応募者を集める
- 【自動】 応募者ごとに、どの要件に何件の職歴が当たったかをまとめる
- 【自動】 生成AIが、当たった職歴の根拠と、前回の見送り理由が今回の必須要件に重なるかを整理する
- 【自動】 前回の選考結果と経過期間から、優先度
A/B/C/holdを規則で決める - 【自動】
AとBの人について、スカウト文の下書きを作る - 【人】 採用担当が候補一覧と根拠を確かめ、声をかける人を決める
- 【人】 下書きを直し、ATSから送る
9番目が、この設計の分かれ目です。 AIが出すのは根拠つきの候補までで、声をかけるかどうかは人が決めます。 前回の面接の事情は、記録に残っていないこともあります。
1番目を検索の前に置いているのも、意図してのことです。 連絡してはいけない人を、後で外すのではなく、最初から検索の対象に入れません。
02今回想定するシステム構成
採用管理システム(ATS) │ 過去の応募者の職務経歴・選考結果・連絡の可否を書き出す ▼【月次】対象の入れ替え(保存期限切れ・連絡不要を外す) 職務経歴を職歴ごとに分割 → Amazon Titan Text Embeddings V2(ベクトル化) ▼ Amazon OpenSearch Service(k-NN インデックス) ▲ │【トリガー】求人の承認 求人の要件を1項目ずつベクトル化 ── 要件ごとに k-NN 検索(_msearch) ▼ 応募者ごとに集約(当たった要件・職歴・類似度) ▼ Claude API ── 根拠の整理/前回の見送り理由との重なりの確認 ▼ 優先度の規則(A / B / C / hold) ▼ Claude API ── A・B のスカウト文の下書き ▼ 【人が候補と根拠を確認】 ──▶ ATS から送信
| 役割 | 想定する製品 | 代替候補 |
|---|---|---|
| 検索基盤 | Amazon OpenSearch Service(ベクトル検索/k-NN) | Azure AI Search、Vertex AI Search(Agent Search) |
| 埋め込み | Amazon Titan Text Embeddings V2(Amazon Bedrock) | OpenAI Embeddings、Gemini Embedding |
| 生成AI | Claude API(根拠の整理とスカウト文の下書き) | OpenAI API、Gemini API |
| 保管 | 採用管理システム(ATS) | 応募者台帳のスプレッドシート |
| 定期実行 | AWS Lambda(月次の入れ替えと求人ごとの検索) | Amazon ECS のタスク |
ATSは新しく足すものではありません。 正本はATSに置いたままにし、選考結果は書き換えません。
検索の土台は、Amazon OpenSearch Service の k-NN です。 ベクトル空間の点に対して、ユークリッド距離またはコサイン類似度で最も近い点を探せるとされています。使うには、インデックスを index.knn の設定で作り、knn_vector 型のフィールドを1つ以上足します。knn_vector は最大10,000個の浮動小数点のリストで、その数は必須の dimension パラメータで決めるとされています。
埋め込みは Amazon Titan Text Embeddings V2 を想定します。 モデルIDは amazon.titan-embed-text-v2:0 で、最大8,192トークンまたは50,000文字を受け取り、出力は1,024次元(既定)、512、256から選べるとされています。英語に最適化されたモデルで、日本語は多言語対応の一覧に含まれています。 言語をまたいだ検索は最適でない結果を返すとされているため、求人票と職務経歴書は同じ日本語でそろえます。
類似度の計算と検索は、埋め込みモデルではなくベクトルデータベースの側で行うとされています。埋め込みを替えても、変わるのは dimension の値と全件の埋め込み直しです。
03どうやって実装するのか
処理の起点を決める
起点は2つあります。1つは月次の入れ替え、もう1つは求人の承認です。
月次の入れ替えは、毎月初めの夜間に動かします。ATSから過去の応募者の一覧を書き出し、保存期限を過ぎた人、連絡不要を申し出た人、入社した人を OpenSearch のインデックスから消します。 新しく不合格・辞退・保留になった人はこのとき足します。検索を始める前に、検索してよい人だけが入っている状態を作ります。
求人の承認は、ATSで求人票が承認済みになったことを起点にします。新しく出た求人と、募集を再開した求人の両方が対象です。 毎月25件前後が承認され、そのたびに1件ずつ検索を回します。まとめて月末に回すことはしません。 承認から数日のうちに声をかけられる人がいれば、媒体に出す前に面接を組めるからです。
入力データを集める
| データ | 中身 | 取得元 |
|---|---|---|
| 求人票 | 職種、必須要件と歓迎要件を1項目ずつ、勤務地、雇用形態 | ATSの求人情報 |
| 過去の応募者の職務経歴 | 職歴ごとの期間・業務内容・使った技術、応募した職種、応募日 | ATSの応募者情報 |
| 前回の選考結果 | rejected(不合格)/ declined(辞退)/ on_hold(保留)、見送り理由のコード、辞退の理由 | ATSの選考記録 |
| 連絡の可否 | 利用目的の範囲(他の求人の案内を含むか)、保存期限、連絡不要の申し出 | ATSの応募者情報と同意の記録 |
| 再接触の履歴 | 過去に再接触した日時、求人、返事の有無 | ATSの送信履歴 |
質を決めるのは、下の3つです。 職務経歴は近さを決めますが、声をかけるかどうかは前回の結果と連絡の可否で決まります。
見送り理由は、自由記述ではなくコードで持たせます。 「経験年数不足」「必須技術の不足」「条件の不一致」「ポジション充足」のように、あとで求人の必須要件と突き合わせられる粒度にします。自由記述の評価コメントは、生成AIへは渡しません(第13章)。
データの取得方法を決める
ATSからの書き出しは、APIが使えればAPIで、使えなければCSVの定期書き出しで行います。 どちらが使えるかはATSの製品によって違い、この部分は利用環境に応じた個別実装になります。
インデックスは、職歴1件を1文書にします。 Titan Text Embeddings V2 は長い文書も受け取れますが、検索では段落や節などの論理的なまとまりに分けることが推奨されています。経歴を丸ごと1本にすると、10年前と直近の職歴が混ざります。
| フィールド | 型 | 中身 |
|---|---|---|
candidate_id | keyword | ATSの応募者ID(氏名は入れない) |
chunk_id | keyword | 職歴1件ごとのID |
text | text | その職歴の業務内容と技術 |
embedding | knn_vector(dimension: 1024) | text の埋め込み |
period_end | date | その職歴の終わった時期 |
applied_at | date | 応募日 |
result | keyword | 前回の選考結果 |
retention_until | date | 保存期限 |
検索は、求人の要件1項目につき1回です。 「Kubernetesでの本番運用」「障害対応の一次受け」「チームの取りまとめ」は別々のベクトルにし、knn クエリで引きます。1件の求人で要件が8項目なら8回の検索を、_msearch で1回の要求にまとめます。 複数の検索をJSONで組み立て、1回の要求で送れるとされています。
k と size は両方指定します。 size を指定しないと、クエリ全体ではなくシャード(およびセグメント)ごとに k 件が返るとされています。k の上限は10,000です。
AIへ渡す前に整形する
- 対象外の人を入れない … 保存期限を過ぎた人、連絡不要を申し出た人、利用目的に他の求人の案内を含まない人は、インデックスに入れません
- 個人を特定する情報を外す … 氏名、連絡先、生年月日、顔写真、住所はインデックスにも生成AIにも渡しません。
candidate_idだけで扱います - 収集すべきでない情報を落とす … 書類に本籍や出生地、思想・信条に関わる記載があれば、埋め込む前に除きます
- 職歴ごとに分ける … 職務経歴書を会社・プロジェクトの単位で区切り、1件ずつ
textにします - 技術名の表記をそろえる … 「k8s」と「Kubernetes」、「AWS」と「アマゾン ウェブ サービス」のように、社内の対応表で片方に寄せます
- 求人票を要件ごとに分ける … 1項目1文にし、「〜の経験3年以上」のような年数は検索文から外して別に持ちます
- 次元をそろえる … インデックスの
dimensionと埋め込みの出力を同じ1,024にします
3番目を軽く見ないでください。 選考に関係のない事項が埋め込みに入ると、その情報が似た人どうしが近くに並びます。
AIに処理させる
ベクトル検索が出すのは「近い職歴」までです。生成AIにさせるのは、その近さを人が確かめられる形に整理することです。
| 見るもの | させること | 判断できないときの扱い |
|---|---|---|
| 要件ごとの当たり | どの職歴のどの文が、どの要件に当たるかを引用する | 引用できる文が無ければ not_found |
| 必須要件の充足 | 必須要件のうち、根拠のある項目と無い項目を分ける | 書類から読み取れなければ unknown |
| 前回の見送り理由との重なり | 見送り理由のコードが、今回の必須要件に当たるかを見る | コードが無ければ unknown |
| 経過期間 | 応募日からの月数と、その後に経験を積めた可能性があるか | 推測しない。月数だけを書く |
| スカウト文 | 根拠の職歴を1つ引き、応募時点の経歴として書く | 根拠が弱ければ下書きを作らない |
3行目が、この構成でいちばん大事な確認です。 2年前に「必須技術の不足」で見送った人が、今回もその技術を必須とする求人に上がってきたら、それは近いのではなく、前回と同じ書類を見ているだけです。 生成AIはこの重なりを conflict として書き出し、優先度は規則の側で下げます。
| させないこと | 理由 |
|---|---|
| 合否の見込みを書く | 選考の判断は面接官と採用担当が行う |
| 現在の勤務先や状況を推測する | 書類は応募時点のもの。決めつけた文面は相手を不快にさせる |
| 年齢・性別などで並べ替える | 選考に関係のない事項で候補を絞らない |
| 連絡してよいかを判断する | 利用目的と保存期限で決まる。前処理で済ませておく |
| 見送り理由を書き換える | 面接の記録は正本。AIが言い直さない |
2行目がいちばん起きやすい失敗です。 経歴が2年前で止まっていても、「現在は〇〇社で活躍中の」と書きがちです。
指示内容を固定する
あなたは中途採用の担当者として、過去の応募者を新しい求人に照らして整理する立場です。
渡された職歴の本文と選考記録だけを見て書いてください。推測で補わないでください。
【求人の要件】{requirements} … 必須/歓迎の区分と、要件ID付き
【検索で当たった職歴】{chunks} … chunk_id、本文、類似度、職歴の終わった時期
【前回の選考結果】{previous} … result、見送り理由のコード、応募日
【やること】
1. 要件ごとに、当たった職歴の中から根拠になる文をそのまま引用する
2. 必須要件を「根拠あり」「根拠なし」「読み取れない」に分ける
3. 前回の見送り理由のコードが、今回の必須要件に当たるかを書く
4. 応募日から今日までの月数を書く
【厳守事項】
- 根拠の文は、職歴の本文からそのまま写してください。言い換えないでください。
- 本文に書かれていない経験を、関連がありそうだという理由で補わないでください。
- 類似度が高いことを、要件を満たす根拠として扱わないでください。
- 現在の勤務先・役職・状況を推測して書かないでください。
- 合否の見込みや、採用すべきかどうかを書かないでください。
- 年齢、性別、国籍、家族構成に触れないでください。
- 見送り理由が今回の必須要件に当たる場合は conflict とし、理由を1文で書いてください。
- 見送り理由のコードが無い場合は unknown としてください。
【スカウト文の下書き(priority が A または B のときだけ)】
- 冒頭で、以前ご応募いただいたことへのお礼を書く
- 「ご応募いただいた当時の経歴を拝見し」と時点を明記する
- 根拠の職歴を1つだけ具体的に引く。求人票を貼り付けない
- 前回の選考結果や見送り理由には触れない
「類似度を根拠として扱わない」を明記しないと、類似度の数字をそのまま理由にします。 0.8と書かれた職歴を「要件を満たす」と言い換え、根拠の文を引かないまま A の候補ができあがります。 近さは検索の都合で、要件を満たすかは本文で決まります。
「前回の選考結果に触れない」は、下書きの側だけに書いています。 整理では見送り理由を読ませ、文面には出させません。
出力形式を固定する
次の形のJSONで受け取ります。
{
"job_id": "",
"candidate_id": "",
"matches": [
{ "requirement_id": "", "type": "must | nice",
"status": "evidenced | not_found | unknown",
"chunk_id": "", "quote": "", "similarity": 0 }
],
"previous": {
"result": "rejected | declined | on_hold",
"reason_code": "",
"reason_conflict": "none | conflict | unknown",
"conflict_note": "",
"months_since_applied": 0
},
"priority": "A | B | C | hold",
"scout_draft": ""
}
1つ目の理由は、matches と priority を別の層に置けることです。 matches と previous は生成AIが埋め、priority はワークフローが規則で決めます。優先度の考え方が変わっても、直すのは規則だけです。
priority | 条件 |
|---|---|
A | 必須要件がすべて evidenced、reason_conflict が none、前回が declined か on_hold |
B | 必須要件がすべて evidenced、reason_conflict が none、前回が rejected で応募から12か月以上 |
C | 必須要件に not_found が1つ以上。歓迎要件の当たりが多い人だけ一覧に残す |
hold | reason_conflict が conflict または unknown、あるいは直近3か月に再接触した人 |
要は、辞退した人と不合格だった人を同じ扱いにしないことです。 辞退した人は自社が「来てほしい」と判断した人で、時期や条件が変われば、いちばん話が早い相手です。 12か月は例で、自社の運用で決めてください。
2つ目は、quote と chunk_id で確認が速くなることです。 quote が空の evidenced は、規則の側で unknown に落とします。
システムへ連携する
| つなぎ先 | 方式 | 内容 |
|---|---|---|
| ATS | APIまたはCSVの書き出し | 応募者・職歴・選考結果・連絡の可否を取る |
| Amazon Titan Text Embeddings V2 | Amazon Bedrock の呼び出し | 職歴と要件をベクトルにする |
| Amazon OpenSearch Service | インデックスAPI、_msearch | 職歴の登録・削除と、要件ごとの k-NN 検索 |
| Claude API | API呼び出し | 根拠の整理と、スカウト文の下書き |
| ATS | 既存の画面 | 候補一覧を見て、下書きを直して送る |
ATSへの書き戻しは、候補一覧の添付までにします。 選考のステータスをこの構成から変えると、過去の記録が再接触のたびに上書きされます。
埋め込みは、月次の入れ替えでまとめて呼びます。 Titan Text Embeddings はスループット重視のバッチでも提供されているとされます。Bedrock の埋め込みモデルはトークン数ではなく1分あたりの要求数で制限されるとされ、月初に全件を入れ直すときは先にこの上限を確かめます。
人が確認する
人が見るのは、A と B の全員と、hold の一覧です。 C は件数だけを見て、歓迎要件の当たりが多い人がいれば開きます。
holdを先に見る …conflictの人は、見送り理由と今回の要件の関係を記録で確かめます。面接官に一言聞けば解けることが多い項目ですAとBの根拠を確かめる …quoteを読み、職務経歴書の該当箇所を開きます。類似度ではなく、本文で要件に当たるかを見ます- 声をかける人を決める … 1件の求人につき数名に絞ります
- 下書きを直して送る … 送信は人が行います。時点の書き方と、前回の結果に触れていないかを最後に見ます
- 判断を覆したら記録する …
Aを送らなかった理由、holdから送った理由を残します
2番目を省かないでください。 ベクトル検索は、同じ言葉が多く出てくる職歴を近いと判定しがちです。 「Kubernetes の勉強会に参加」と「Kubernetes で本番を3年運用」は、文としては近くに並びます。
目標は、1件の求人で60分です。 それより長い月は、要件の書き方が粗いか、見送り理由のコードが抜けています。
例外に対処する
| 起きること | 対応 |
|---|---|
| 候補が1人も上がらない | 要件の書き方を見直す。要件を1項目ずつ検索し、どの項目で当たりが消えたかを見る |
| 候補が多すぎる | size を絞るのではなく、必須要件を先に確かめ、C を一覧から外す |
| フィルタを足すと件数が減る | knn クエリに他の条件を混ぜると k 件より少なくなることがある。対象外の人は前処理で外しておく |
| 同じ人が複数の職歴で上がる | candidate_id で集約し、要件ごとに最も近い職歴だけを残す |
| 職務経歴書がPDFの画像で本文が無い | インデックスに入れず、no_text の一覧に出す |
| 見送り理由のコードが無い | reason_conflict を unknown にし、hold に回す |
| 連絡不要の申し出が月の途中で入る | 次の月次を待たず、その日のうちにインデックスから消す |
| 求人票の要件が1文にまとまっている | 要件を分けてから承認し直してもらう |
| 埋め込みやOpenSearchが応答しない | その求人の検索を止め、承認済みのまま再実行の一覧に残す |
3行目は仕組みの性質です。 OpenSearch Service の説明では、post_filter で2件が1件に減る例が示されています。「連絡不可」を検索のときに外すと候補が理由なく減るのも、対象外の人をインデックスに入れない理由です。
記録を残す
- 検索に使った求人の要件と、そのときの要件ID
- 要件ごとの検索結果(
chunk_id、類似度、順位) - 生成AIが返したJSONの全文(
matches、previous、priority、scout_draft) - そのとき検索の対象に入っていた人数と、月次の入れ替えで外した人数
- 人が判断を覆した記録 …
Aを送らなかった理由、holdから送った理由 - 送ったスカウト文の最終版と、返事の有無
4つ目を残すのは、保存期限を過ぎた人に送っていないことを示すためです。
ログにも保存期限を付けます。 検索結果のログには candidate_id と職歴の本文が残ります。応募者の保存期限を過ぎた人は、ログからも同じ時期に消します。 インデックスだけ消してログに残すと、消したことになりません。
04実装レベルの3段階
最小構成では人数がさばけません。 50名は貼れても、6,000名は貼れません。確かめるための段階です。 半自動化で、1件180分が100分程度になります。 検索は減りますが、前回の選考記録の確認とスカウト文の作成が残ります。本格構成で60分になり、この段階が本記事の想定です。 差が大きいのは、前回の結果の確認と文面の作成が、1人ずつの手作業だからです。 段階を飛ばさないでください。 半自動化の一覧を1か月見ると、見送り理由のコードが抜けている人と、書き方が粗い求人票が先に分かります。そこを直してから優先度の規則を足すほうが、hold の山ができません。
05工数削減シミュレーション
導入後 25件 × 60分 ÷ 60 = 25 時間/月
自社条件で導入効果を整理したい方へ
このユースケースを自社に当てはめた場合の前提値と削減見込みを、業務ヒアリングをもとに整理します。
06向いている企業・向いていない企業
- 過去数年分の応募者が数千名規模で採用管理システムにたまっており、不合格・辞退・保留の人に改めて声をかける運用が担当者の記憶に頼っている企業。毎月いくつもの求人が出るIT・SaaS企業、人材会社、製造業など。応募時の個人情報の利用目的に「他の求人のご案内」を含めているか、これから含められる場合。
- 過去の応募者が数百名以下で、担当者が顔と名前を覚えていられる場合。応募時の利用目的を「応募された求人の選考」に限って示しており、他の求人の案内に使うことを説明していない場合(先に利用目的と保存期間の見直しが必要)。職務経歴書をテキストで残していない場合。
07最小構成で試す方法
- 過去1年に出た求人から3件を選ぶ(うち1件は、実際に過去の応募者から採用できた求人を入れる)
- その3件の当時に、担当者が誰を思い浮かべ、誰に声をかけたかを聞き取る
- 過去の応募者から50名分の職務経歴書を選び、氏名と連絡先を消したテキストにする
- 手元のAIサービスに求人の要件と50名分の職歴を貼り、「要件ごとに、根拠になる文を引用して近い人を挙げてください。引用できない人は挙げないでください」と指示する
- 出てきた候補を、担当者が当時思い浮かべた人と突き合わせる
50名で必ずやってください。 ベクトル検索の仕組みを組む前に、「職歴の文から要件に当たる人を引けるのか」を確かめます。 手元のAIサービスに貼る前に、社内の規程で個人情報を入れてよいサービスかを必ず確かめてください。
| 出てきた内容 | 判断 |
|---|---|
| 担当者が思い浮かべた人が上がり、他にも根拠のある人が出た | ベクトル検索の構成に進む |
| 引用の無い候補が混ざる | 指示の書き方で直る。構成は有効 |
| 要件が曖昧で、誰でも当たる | 求人票の要件の書き方が先。 AIの問題ではない |
3行目が出ることは珍しくありません。 失敗ではなく、キーワード検索でも探しにくかった理由が1つ分かったということです。 要件を1項目1文に書き直し、同じ50名でもう一度試してください。
08実装時につまずきやすいポイント
| 問題 | 対策 |
|---|---|
類似度が高いだけで A になる | 本文からの引用を必須にする。 quote が空なら unknown に落とす |
| 前回と同じ理由で見送る人が上がる | 見送り理由をコードで持ち、必須要件との重なりを conflict で出す |
| 連絡不要の人に送ってしまう | インデックスに入れない。 検索のときのフィルタに頼らない |
| フィルタで候補が理由なく減る | knn に他の句を混ぜると k 件を下回ることがある。対象外は前処理で外す |
size を付け忘れて件数がおかしい | 付けないとシャードとセグメントごとに k 件が返る。両方指定する |
| 1人の経歴を1本のベクトルにする | 職歴ごとに分ける。 論理的なまとまりへの分割が推奨されている |
| 求人票が長い1段落で書かれている | 要件を1項目1文に分けてから検索する |
| 「3年以上」がベクトルで効かない | 年数は検索文から外し、職歴の期間から規則で数える |
| 英語と日本語が混ざった書類で当たらない | 言語をまたぐ検索は最適でない結果になるとされる。表記を日本語にそろえる |
| 埋め込みのモデルを途中で替える | dimension が変わる。インデックスを作り直し、全件を埋め込み直す |
| 文面が現在の状況を決めつける | 「応募いただいた当時の経歴」と時点を書かせ、送る前に人が見る |
| 月初の入れ替えで上限に当たる | 埋め込みは1分あたりの要求数で制限される。件数を分けて流す |
上の3行が、この構成の失敗のほとんどです。 どれも「近い人が上がった」という同じ見た目から出発しています。近さと、声をかけてよいかと、今かけるべきかを別の層に置いてあるかどうかで、運用に乗るかが決まります。
3行目と4行目は、同じ理由から来ています。 検索のときに条件で外す設計は、条件を書き忘れた日に、連絡してはいけない人がそのまま一覧に出ます。 条件を足すほど候補が減り、理由も見えにくくなります。インデックスに入れない形なら、忘れようがありません。
11行目は、送った後では直せません。 2年前の経歴を今の姿として書いた文面は、「自分のことを見ていない」連絡です。その1通は、削減した時間よりはるかに高くつきます。
09セキュリティ・AIガバナンス上の注意点
この構成で扱うデータ: 過去の応募者の職務経歴、応募した職種と応募日、選考の結果と見送り理由、辞退の理由、連絡の可否です。どれも応募者本人が選考のために出した、あるいは自社が選考の中で作った情報です。
- 利用目的に「他の求人の案内」が入っているかを先に確かめる … 職業安定法に基づく指針では、労働者の募集を行う者は、求職者等の個人情報がどのような目的で収集・保管・使用されるのかを、求職者等が一般的かつ合理的に想定できる程度に具体的に明示することとされています。「応募された求人の選考のため」とだけ示していた人を別の求人に使えるかは、法務・個人情報の担当部署と確かめてください。 個人情報保護委員会のQ&Aでは、利用目的の変更は変更前の目的と関連性を有すると合理的に認められる範囲で認められるとされ、事例が挙げられていますが、採用の場面にどう当てはまるかの判断は本記事では行いません。 これから集める応募者には、応募フォームで「今後、他の求人のご案内に利用すること」と保存期間をはっきり示すのが確実です
- 保存期間を自社で決め、インデックスとログの両方に効かせる … 個人情報保護委員会のQ&Aでは、個人情報保護法は保存期間や廃棄すべき時期を規定していないとされています。そのうえで、個人データを利用する必要がなくなったときは、遅滞なく消去するよう努めなければならない(法第22条)とされています。指針でも、収集目的に照らして保管する必要がなくなった個人情報を破棄または削除するための措置を講じることが求められています。「応募から3年」のように期限を決め、
retention_untilとして持たせ、月次の入れ替えで消します。 期限の長さは法務と決めてください
- 選考に関係のない情報を検索に入れない … 指針では、人種、民族、社会的身分、門地、本籍、出生地その他社会的差別の原因となるおそれのある事項や、思想及び信条、労働組合への加入状況は、特別な職業上の必要性がない限り収集してはならないとされています。本人が書類に書いてきた場合でも、埋め込む前に落とします。 検索結果の並びに見えない形で効いてしまうからです
- 生成AIとベクトルに渡す範囲を絞る … 渡すのは
candidate_id、職歴の本文、見送り理由のコードまでです。氏名・連絡先・生年月日・顔写真と、面接官の自由記述の評価は渡しません。 評価の言葉は、本人の知らないところで書かれた人物評です
- 学習への利用とデータの保持の設定を、契約と管理画面で確かめる … 埋め込みと生成AIのそれぞれについて、入力が学習に使われない設定か、どの期間保持されるかを、導入前に自社の情報システム部門が確かめてください。 本記事ではこの点の仕様を確認していません
- アクセスできる人を採用担当に限る … OpenSearch のインデックスとログには、6,000名分の職歴と選考結果がまとまっています。インデックスを読める権限を採用の担当者と運用者に限り、現場の部署の面接官には候補一覧だけを見せます
誤りが起きた場合のリスクは、連絡してはいけない人に送ることと、前回と同じ理由で見送る人に期待を持たせることの2つです。 前者は検索のときの条件で外そうとすると起き、後者は見送り理由を読まずに近さだけで並べると起きます。どちらも「近い」と「声をかけてよい」を混ぜたところから出ているので、そこだけは設計で守ります。
10まず何から始めるか
1週目:利用目的と保存期間を確かめる
応募フォームと応募時の案内で、個人情報の利用目的に「他の求人のご案内」が入っているか、保存期間を示しているかを確かめます。法務・個人情報の担当部署に、どの時期の応募者なら再接触に使えるかを相談します。
2週目:50名で試す
過去の応募者から50名を選び、氏名と連絡先を消した職歴で、求人3件に対して候補を挙げさせます。当時の担当者が思い浮かべた人と突き合わせ、引用の無い候補が混ざっていないかを最優先で見ます。
3週目:見送り理由のコードを決める
「経験年数不足」「必須技術の不足」「条件の不一致」「ポジション充足」のように、求人の必須要件と突き合わせられる粒度のコードを決めます。直近1年の不合格・辞退・保留の人から付け直します。
4週目:インデックスを作る
利用目的と保存期限の条件を満たす人だけを書き出し、職歴ごとに分けて埋め込み、OpenSearch Service のインデックスに入れます。この時点では優先度を出さず、要件ごとの検索結果の一覧だけを見ます。
2か月目: 前回の結果との照合と優先度の規則を足し、A / B / C / hold を出します。hold の件数を毎週数えます。3か月目以降: スカウト文の下書きを足し、1件180分が何分になったかを実測します。月次の入れ替えで外した人数を毎月記録し、連絡不要の申し出がその日のうちに反映される運用ができた時点で、この構成は完成です。
11関連ユースケース
12この仕組みを理解するための記事
13技術仕様の確認日・参考情報
| 確認した内容 | 情報源 | 確認日 |
|---|---|---|
k-NN がユークリッド距離またはコサイン類似度で近い点を探すこと。index.knn の設定と knn_vector 型が必要で、knn_vector は最大10,000個の浮動小数点を dimension で指定すること。size を指定しないとシャード(およびセグメント)ごとに k 件が返ること。k の上限が10,000であること。knn を他の句と組み合わせると k 件より少なくなることがあること。_msearch で複数の検索をまとめられること。32GiBのRAMで8GiB分のグラフを置けること | AWS: k-Nearest Neighbor (k-NN) search in Amazon OpenSearch Service | 2026-09-29 |
Titan Text Embeddings V2 のモデルIDが amazon.titan-embed-text-v2:0 で、最大8,192トークンまたは50,000文字を受け取り、1,024(既定)/512/256次元を出力すること。英語に最適化され、日本語が多言語対応の一覧に含まれること。言語をまたぐ検索は最適でない結果になること。検索では論理的なまとまりへの分割が推奨されること。類似度の計算はベクトルデータベースが行うこと。埋め込みモデルが要求数(RPM)で制限されること | AWS: Amazon Titan Text Embeddings models | 2026-09-29 |
| 個人情報保護法が保存期間や廃棄すべき時期を規定していないこと。利用する必要がなくなった個人データを遅滞なく消去するよう努めなければならないこと(法第22条) | 個人情報保護委員会: Q5-2 取得した個人情報はいつ廃棄しなければならないか | 2026-09-29 |
| 利用目的の変更が、変更前の利用目的と関連性を有すると合理的に認められる範囲で認められること。その事例 | 個人情報保護委員会: 利用目的の変更が認められる事例 | 2026-09-29 |
| 労働者の募集を行う者が、求職者等の個人情報の目的を一般的かつ合理的に想定できる程度に具体的に明示すること。社会的差別の原因となるおそれのある事項、思想及び信条、労働組合への加入状況を原則として収集しないこと。保管する必要がなくなった個人情報を破棄または削除する措置を講じること | 厚生労働省: 職業紹介事業者、求人者、労働者の募集を行う者等がその責務等に関して適切に対処するための指針 | 2026-09-29 |
過去の応募者に再び連絡してよいか、保存期間をどれだけにするかは、自社の法務・個人情報の担当部署と決めてください。 本記事は個人情報保護委員会と厚生労働省のページで確認できた範囲だけを扱っています。
実装ステータス:構成例。 公開仕様に基づいて設計した構成であり、当社で実際に構築・検証したものではありません。工数の数値はモデル条件による試算です。
自社の業務に使えるAI活用候補を整理します
このユースケース(UC-0290)についてのご相談はこちらから。
