HR 入社書類処理パイプライン:Dify Workflow による PDF 解析から人事システム連携までの実装ガイド
はじめに
新入社員の入社手続きにおいて、人事部門は大量の書類を処理する必要がある。履歴書、住民票、マイナンバー通知カード、銀行口座届出書、年金手帳のコピー、各種誓約書――これらの書類から必要な情報を正確に抽出し、人事システムに登録する作業は、1 名あたり数十分から 1 時間を要する。4 月の一括入社時期には、この作業が集中的に発生し、人事部門のボトルネックとなる。
本稿では、Dify の Workflow を活用して、PDF / 画像形式の入社書類から情報を自動抽出し、検証・人間確認を経て人事システムに登録するエンドツーエンドのパイプラインを設計・実装する方法を解説する。
背景と課題
入社書類処理の現実
| 課題 | 詳細 |
|---|---|
| 書類の多様性 | テキスト PDF、スキャン PDF、写真撮影の画像が混在 |
| 手書き情報の存在 | 住所変更届や銀行口座届出書には手書き項目がある |
| 転記ミスのリスク | 手動転記では氏名の漢字、口座番号、住所の誤りが発生しやすい |
| 個人情報の機密性 | マイナンバー、口座情報等の取扱いにセキュリティ制約がある |
| 繁忙期の集中 | 4 月入社の新卒採用では数十名分が同時に発生 |
| 書類の不備・不足 | 提出された書類に不備があると、差戻しと再提出のやり取りが発生 |
パイプライン化のメリット
| 項目 | 手動処理 | Dify パイプライン |
|---|---|---|
| 1 名あたりの処理時間 | 30-60 分 | 5-10 分(人間確認含む) |
| 転記ミス率 | 2-5% | 0.5% 未満(人間確認後) |
| 書類不備の検出タイミング | 入力時に発見 | アップロード直後に自動検出 |
| 処理のトレーサビリティ | 紙ベース | 全ステップがログに記録 |
全体アーキテクチャ
flowchart TD
A[書類アップロード<br>PDF / 画像] --> B[ファイル振分けノード]
B --> C{ファイル形式判定}
C -->|テキスト PDF| D[テキスト抽出]
C -->|スキャン PDF / 画像| E[VLM / OCR 処理]
D --> F[パラメータ抽出ノード<br>構造化 JSON 出力]
E --> F
F --> G[フィールド検証ノード]
G --> H{検証結果}
H -->|全項目 OK| I[Human-in-the-Loop<br>最終確認]
H -->|不備あり| J[不備通知<br>再提出依頼]
I --> K{承認?}
K -->|Yes| L[人事システム連携<br>HTTP Request]
K -->|修正| M[修正入力]
M --> G
L --> N[処理完了・ログ記録]
ノード設計の詳細
ノード 1: ファイル受信(開始ノード)
Dify Workflow の開始ノードで、以下の入力を受け付ける。
| 変数名 | 型 | 必須 | 説明 |
|---|---|---|---|
employee_name | text | Yes | 入社予定者の氏名 |
employee_id | text | Yes | 社員番号(仮番号可) |
entry_date | date | Yes | 入社予定日 |
documents | file[] | Yes | 入社書類(複数ファイル) |
document_types | text | No | 各ファイルの書類種別(カンマ区切り) |
ノード 2: ファイル形式判定・振分け
アップロードされた各ファイルについて、処理方法を振り分ける。
判定ロジック:
- 拡張子が .pdf でテキスト抽出可能 → テキスト PDF ルート
- 拡張子が .pdf でテキスト抽出不可 → スキャン PDF ルート(VLM)
- 拡張子が .jpg / .png / .heic → 画像ルート(VLM)
ノード 3: テキスト抽出
テキスト PDF の場合
PDF パーサーを使用して直接テキストを抽出する。最もコストが低く、精度も高い。
スキャン PDF / 画像の場合
Dify の Vision 対応モデル(GPT-4o、Claude 等)を使用し、画像から直接構造化データを抽出する。従来の OCR パイプライン(画像 → 文字認識 → 後処理)よりも、VLM による直接抽出の方が以下の点で優れている。
| 項目 | 従来 OCR | VLM 直接抽出 |
|---|---|---|
| 表形式への対応 | 構造解析が別途必要 | テーブル構造を理解して抽出 |
| 手書き文字 | 精度が大きく低下 | 文脈を踏まえた推定が可能 |
| 複合レイアウト | レイアウト解析が必要 | 視覚的に理解して処理 |
| 印影・証明写真の存在 | 認識エラーの原因に | 無視すべき要素を判断可能 |
ノード 4: パラメータ抽出(LLM ノード)
抽出したテキストまたは画像から、構造化された JSON を出力する。
System Prompt:
あなたは HR 書類処理の専門アシスタントです。
以下の入社書類から、指定されたフィールドを正確に抽出してください。
【抽出フィールド】
{
"personal_info": {
"full_name_kanji": "氏名(漢字)",
"full_name_kana": "氏名(カタカナ)",
"date_of_birth": "生年月日(YYYY-MM-DD)",
"gender": "性別",
"nationality": "国籍"
},
"address": {
"postal_code": "郵便番号(XXX-XXXX)",
"prefecture": "都道府県",
"city": "市区町村",
"street": "番地以降",
"building": "建物名・部屋番号"
},
"contact": {
"phone": "電話番号",
"email": "メールアドレス",
"emergency_contact_name": "緊急連絡先氏名",
"emergency_contact_phone": "緊急連絡先電話番号",
"emergency_contact_relationship": "続柄"
},
"bank_account": {
"bank_name": "銀行名",
"branch_name": "支店名",
"account_type": "口座種別(普通/当座)",
"account_number": "口座番号",
"account_holder": "口座名義(カタカナ)"
},
"tax_social": {
"my_number": "マイナンバー(12桁)",
"pension_number": "基礎年金番号",
"health_insurance_number": "健康保険証番号"
}
}
【重要ルール】
1. 書類に記載がないフィールドは null を設定すること
2. 読み取りに自信がないフィールドは
{"value": "読み取り値", "confidence": "low", "note": "理由"}
の形式で出力すること
3. マイナンバーは12桁の数字であること。桁数が合わない場合は
confidence を "low" に設定すること
4. 絶対に推測や補完を行わないこと
各フィールドには value、confidence(high / medium / low)、source_file を付与する。confidence が low のフィールドは後続の Human-in-the-Loop で必ず人間確認に回す設計とする。
ノード 5: フィールド検証
抽出されたデータに対して、ルールベースの検証を行う。
検証ルール:
1. 郵便番号: XXX-XXXX 形式であること
2. 電話番号: 0X-XXXX-XXXX または 0XX-XXX-XXXX 形式
3. メールアドレス: 有効な形式であること
4. マイナンバー: 12桁の数字であること
5. 口座番号: 7桁の数字であること
6. 生年月日: 入社日時点で18歳以上であること
7. 必須フィールド: 氏名、住所、銀行口座が全て入力済みであること
Dify Workflow では、コードノード(Python / JavaScript)を使用してこれらの検証を実装できる。
# コードノードでの検証例
import re
import json
def validate_fields(data):
errors = []
warnings = []
# 郵便番号チェック
postal = data.get("address", {}).get("postal_code", "")
if postal and not re.match(r"^\d{3}-\d{4}$", postal):
errors.append({
"field": "address.postal_code",
"value": postal,
"message": "郵便番号の形式が不正です(XXX-XXXX)"
})
# マイナンバーチェック
my_number = data.get("tax_social", {}).get("my_number", "")
if isinstance(my_number, dict):
# confidence が low の場合
warnings.append({
"field": "tax_social.my_number",
"value": my_number.get("value"),
"message": my_number.get("note"),
"requires_human_review": True
})
elif my_number and not re.match(r"^\d{12}$", str(my_number)):
errors.append({
"field": "tax_social.my_number",
"value": my_number,
"message": "マイナンバーは12桁の数字である必要があります"
})
# 口座番号チェック
account = data.get("bank_account", {}).get("account_number", "")
if account and not re.match(r"^\d{7}$", str(account)):
errors.append({
"field": "bank_account.account_number",
"value": account,
"message": "口座番号は7桁の数字である必要があります"
})
return {
"is_valid": len(errors) == 0,
"errors": errors,
"warnings": warnings,
"requires_human_review": len(warnings) > 0
}
ノード 6: Human-in-the-Loop(人間確認)
以下の条件で、人事担当者による確認を求める。
| トリガー条件 | 重要度 | 対応 |
|---|---|---|
confidence: low のフィールドが存在 | 高 | 該当フィールドをハイライトして確認依頼 |
| 検証エラーが存在 | 高 | エラー内容を表示し修正を依頼 |
| 必須フィールドが null | 高 | 不足書類の再提出を依頼 |
| マイナンバー・口座番号の抽出 | 必須 | 機密情報は必ず人間が最終確認 |
| 氏名の漢字・カナの不一致 | 中 | 正しい表記を確認 |
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
入社書類処理: 確認が必要です
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ 対象者: 山田 太郎(社員番号: EMP-2026-0501)
■ 入社予定日: 2026-05-01
■ 要確認項目:
⚠ マイナンバー: 123456789012
→ スキャン品質が低く、3桁目が不明確です。
原本を確認してください。
⚠ 基礎年金番号: 未検出
→ 年金手帳のコピーが提出されていない可能性があります。
■ 抽出結果(全項目):
[構造化データを表示]
■ アクション:
[承認] [修正して承認] [書類再提出依頼]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ノード 7: 人事システム連携(HTTP Request ノード)
確認済みのデータを、Dify Workflow の HTTP Request ノードから人事システムの API に送信する。構造化 JSON をそのまま POST するため、フィールドマッピングの設計が重要である。
連携先のシステム例:
| システム | 連携方法 | 登録内容 |
|---|---|---|
| 人事マスタ(COMPANY 等) | REST API | 基本情報・住所・家族情報 |
| 給与システム(freee 人事労務等) | REST API | 銀行口座・社会保険情報 |
| 勤怠システム(KING OF TIME 等) | REST API | 社員番号・所属部門 |
| Active Directory / IdP | LDAP / SCIM | アカウント自動作成 |
| Google Workspace / Microsoft 365 | Admin API | メールアドレス・グループ割当 |
セキュリティ設計
個人情報の取扱い
入社書類にはマイナンバー、銀行口座情報など、特に厳格な管理が求められる個人情報が含まれる。
| 対策 | 実装方法 |
|---|---|
| 通信の暗号化 | Dify と各システム間は HTTPS / TLS 1.3 |
| データの一時保存制限 | Workflow 実行完了後、一時ファイルを自動削除 |
| アクセス制御 | Dify のワークスペース権限で処理担当者を限定 |
| 監査ログ | 全操作(アップロード・抽出・確認・登録)をログに記録 |
| オンプレミスデプロイ | 機密性が高い場合、Dify セルフホスト版を閉域網で運用 |
| マイナンバーの特別管理 | 抽出後はマスキングして表示、人間確認時のみ全桁表示 |
個人情報保護の観点から、マイナンバーや口座情報を外部クラウドに送信できない場合は、Dify セルフホスト版(Docker Compose)を閉域網で運用し、ローカル VLM と組み合わせることでデータ外部送信を完全に回避できる。
エラーハンドリング
想定されるエラーと対処
| エラー | 検出方法 | 対処 |
|---|---|---|
| PDF が暗号化されている | ファイル解析時のエラー | 暗号化解除を依頼 |
| 画像の解像度が低い | VLM の confidence が全般的に低い | 再撮影・再スキャンを依頼 |
| 書類の種類が想定外 | 書類タイプ判定で「不明」 | 人事担当者にエスカレーション |
| 人事システム API エラー | HTTP レスポンスコードで検出 | 3 回リトライ後、保留キューに格納 |
| 抽出データの矛盾 | 検証ノードで不整合を検出 | 人間確認に回す |
導入ステップ
| Phase | 期間 | 内容 |
|---|---|---|
| Phase 1 | 2 週間 | 履歴書のみを対象に PoC。テキスト抽出 → JSON 変換の精度を検証。 |
| Phase 2 | 2-4 週間 | 書類種別を拡大(口座届出書、住民票等)。VLM によるスキャン対応を追加。 |
| Phase 3 | 1-2 ヶ月 | 検証ノード・Human-in-the-Loop を実装。人事システムとの API 連携。 |
| Phase 4 | 継続 | バッチ処理の整備。抽出精度のモニタリングと改善。 |
まとめ
HR 入社書類処理パイプラインの核心は、「AI が PDF を読めるか」ではなく、解析・抽出・検証・人間確認・システム登録という一連のプロセスを、追跡可能かつ再現可能な形で自動化することにある。
Dify Workflow は、ファイル入力の受付、VLM / OCR による情報抽出、コードノードによるバリデーション、Human-in-the-Loop による人間確認、HTTP Request ノードによる外部システム連携――これらすべてをビジュアルに設計・運用できる基盤を提供する。
特に重要な設計原則は以下の三点である。
- 構造化出力: 自然文ではなく、フィールド単位の JSON で出力し、
confidenceとsourceを付与する - 人間確認の必須化: 機密性の高いフィールド(マイナンバー、口座番号)は必ず人間が最終確認する
- セキュリティ設計: 個人情報の取扱いに応じて、セルフホスト版の採用やデータの一時保存制限を検討する
これらの原則を守ることで、人事部門の繁忙期における書類処理の負荷を大幅に軽減しつつ、正確性と安全性を担保するパイプラインを実現できる。