Skip to content

求人エンリッチメント

概要

求人エンリッチメントバッチは、Gemini API(Google Search Grounding 有効)を使って求人情報を自動拡充するスクリプトです。

項目内容
目的求人情報に AI 説明文・カテゴリ分類・構造化データを付与
使用 APIGemini 3 Flash Preview(Google Search Grounding 有効)
実行方法CLI: npm run enrich:jobs [OPTIONS] / UI: 求人詳細画面「AIで構造化」ボタン
対象enrichment_status = 'pending' の求人(デフォルト)

処理フロー

ステップ詳細

  1. CLI 起動: enrich-jobs.ts がコマンドライン引数をパースし、環境変数を検証
  2. 対象求人取得: jobs テーブルから companies(name) を JOIN して取得。enrichment_status でフィルタリング
  3. カテゴリマスタ取得: job_categories テーブルから全カテゴリを display_order 順で取得
  4. 求人ループ: 各求人に対して順次処理(2 秒間隔)
  5. 成功時: カテゴリマッピングの DELETE & INSERT → エンリッチメントデータ保存(status = 'success'
  6. 失敗時: エラーメッセージを記録(status = 'failed'

UI からの実行

求人詳細画面から個別の求人に対してエンリッチメントを実行できます。

操作方法

状態UI表示操作
未エンリッチ(structured_requirements = null「AIで構造化」ボタンボタン押下で実行
エンリッチ済み構造化データカード + 「再生成」ボタン再生成ボタンで再実行
処理中ローディングスピナー完了まで待機

API エンドポイント

メソッドパス説明
POST/api/v1/jobs/:id/enrich指定求人のエンリッチメントを実行
  • 成功時: 更新後の求人詳細データを返却
  • 失敗時: { error: { code: 'INTERNAL_ERROR', message: '...' } }
  • GEMINI_API_KEY 環境変数が未設定の場合は 500 エラー

CLI オプション

オプション短縮形説明
--company-id-cnumber企業 ID で絞り込み
--dry-run-dbooleanDB 保存せず結果を表示のみ
--force-fboolean処理済み(success/failed/skipped)も再実行
--limit-lnumber処理件数の上限を指定
--help-hbooleanヘルプを表示

使用例

bash
# 全 pending 求人を処理
npm run enrich:jobs

# 特定企業のみ処理(dry-run)
npm run enrich:jobs -- --company-id 42 --dry-run

# 処理済みを含めて最大10件を再処理
npm run enrich:jobs -- --force --limit 10

終了コード

コード意味
0全件成功
11 件以上の失敗、または致命的エラー

データモデル

jobs テーブル(エンリッチメント関連カラム)

カラム説明
ai_descriptiontextAI 生成の求人説明文
enrichment_statusvarchar(20)ステータス(下記参照)
enrichment_errortext失敗時のエラーメッセージ
enriched_attimestamptz最終エンリッチメント実行日時
structured_requirementsjsonb構造化要件データ(GIN インデックス)
ai_description_embeddingvector(3072)説明文の埋め込みベクトル(HNSW + halfvec インデックス)

enrichment_status 遷移

意味
pending未処理(新規求人のデフォルト)
successエンリッチメント完了
failedエンリッチメント失敗
skipped意図的にスキップ

structured_requirements フィールド一覧

構造化要件は 16 フィールドの JSONB データです。

基本マッチング項目

フィールド説明
min_salarynumber | null最低年収(万円)500
max_salarynumber | null最高年収(万円)800
required_skillsstring[]必須スキル(歓迎スキルは除外)["TypeScript", "React"]
min_experience_yearsnumber | null必須経験年数3
work_styleenum | null勤務形態"フルリモート" / "ハイブリッド" / "出社"
work_locationsstring[]勤務地(都道府県・エリア)["東京都", "大阪府"]

拡張マッチング項目

フィールド説明
target_seniorityenum | null対象レベル"ジュニア" / "ミドル" / "シニア" / "リード"
industry_domainstring | null業界ドメイン"SIer" / "Web系自社開発"
career_pathsstring[]キャリアパス["テックリード", "マネジメント"]
culture_keywordsstring[]社風キーワード["裁量が大きい", "フラット"]
english_requirementenum | null英語要件"不要" / "日常会話" / "ビジネス" / "ネイティブ"
team_sizeenum | nullチーム規模"少人数" / "中規模" / "大規模"

エージェント向けナラティブ項目

フィールド説明
position_summarystring候補者ができること(2-3 文)
environmentstringチーム・環境の説明(2-3 文)
selling_pointsstring[]求人のハイライト(3-5 点)
agent_notesstring | null非公開条件(年齢制限、学歴要件等)

バリデーションルール

  • enum フィールド(work_style, target_seniority, english_requirement, team_size): 不正値は null にフォールバック
  • category_ids: マスタに存在しない ID は自動除外
  • 年収: typeof === 'number' でない場合は null
  • 配列フィールド: 欠損・不正値は [] にフォールバック

Gemini API 連携

モデル設定

項目
モデルgemini-3-flash-preview
Temperature0.0(決定的出力)
レスポンス形式application/json
ツールGoogle Search Grounding

プロンプト構成

GeminiClient.buildJobPrompt() が以下の情報を含む単一プロンプトを構築します:

  • 入力データ: 企業名、求人タイトル、求人詳細(未設定時は "(求人詳細情報なし)"
  • タスク 1 — カテゴリマッピング: カテゴリマスタ一覧({id}: {name} 形式)を埋め込み、該当 ID を選択。どのカテゴリにも該当しない求人(事務職、販売職、製造業等の IT エンジニア・コンサルタント領域外)のみ「その他」を選択
  • タスク 2 — AI 説明文: 約 300 文字の差別化サマリーとターゲットペルソナ
  • タスク 3 — 構造化要件: 16 フィールドの抽出ルールと出力 JSON スキーマ

リトライ・エラーハンドリング

リトライ条件

以下のキーワードがエラーメッセージに含まれる場合にリトライ:

  • rate limit
  • timeout
  • 503
  • 429
  • temporarily

指数バックオフ

試行待機時間計算式
1 回目失敗1 秒1000 * 2^0
2 回目失敗2 秒1000 * 2^1
3 回目失敗最大試行回数に到達、エラー返却

JSON パースエラー

Gemini のレスポンスが JSON としてパースできない場合は即座にエラーとして処理されます(リトライ対象外)。

環境変数

変数名必須説明
GEMINI_API_KEYGemini API キー
SUPABASE_URLSupabase プロジェクト URL
SUPABASE_SERVICE_ROLE_KEYSupabase サービスロールキー(RLS バイパス)
NODE_ENVproduction 以外の場合 .env.local を自動読み込み

ローカル開発時は backend/.env.local に設定します(.env.example がテンプレート)。

関連ファイル

役割パス
CLI エントリーポイントbackend/src/scripts/enrich-jobs.ts
アプリケーションサービスbackend/src/application/services/JobEnrichmentService.ts
Gemini API クライアントbackend/src/infrastructure/external/gemini/GeminiClient.ts
Gemini 型定義backend/src/infrastructure/external/gemini/types.ts
Job エンティティbackend/src/domain/entities/Job.ts
JobRepository 実装backend/src/infrastructure/repositories/supabase/JobRepository.ts
MasterRepository 実装backend/src/infrastructure/repositories/supabase/MasterRepository.ts
API ルート(enrich)backend/src/interfaces/routes/jobs.ts
フロントエンド API 関数frontend/src/lib/api/jobs.ts
フロントエンド Hookfrontend/src/hooks/useJobs.ts
求人詳細ページfrontend/src/pages/JobDetailPage.tsx
環境変数テンプレートbackend/.env.example