ooligo
n8n-flow

n8nによる採用ファネル異常検出

Difficulty
中級
Setup time
90min
For
recruiting-leader · talent-acquisition · recruiting-ops
Recruiting & TA

Stack

ほとんどの採用チームはファネルの問題を四半期のビジネスレビューで発見します。その時点でロールは60日間オープンになっており、3人の最良候補者のうち2人は他のオファーにサインしており、採用マネージャーはパイプラインへの信頼を失っています。このワークフローはそのギャップを埋めます。n8nフローが毎晩ATSに対して実行され、ロール別ステージ別のコンバージョン率とドウェルタイムを90日間のローリングベースラインに照らして計算し、統計的に意味のある偏差にフラグを立て、Claudeに各偏差を1〜2文で説明させ、次の朝のスタンドアップ前にルーティングを意識したSlackチャンネルに結果を投稿します。

apps/web/public/artifacts/hiring-funnel-anomaly-n8n/hiring-funnel-anomaly-n8n.json のバンドルには15の完全に設定されたノードが含まれています — 2つのスケジュールされたトリガー、Ashby引き出し、実際の異常ロジックを持つ集計コードノード、Postgresベースラインルックアップ、検出器、重複排除インサート、Claudeナラティブ呼び出し、Slackフォーマッター、並行した採用完了日数トレンドパス。_README.md には4つの認証情報、作成する必要がある3つのPostgresテーブル、すべてのブランチを実行する5ステップの初回実行検証が文書化されています。

使う場面

採用チームが少なくとも8〜10件のアクティブなロールを並行して実行しており、チームが少なくとも90日間同じATSAshbyGreenhouse、またはLever)を使用しているためベースラインが存在し、チームの誰かがファネルヘルスを自分の仕事の一部として所有している場合にこれを実装してください。それ以下のしきい値では、シグナルノイズ比が間違っています:ベースラインが有用なzスコアしきい値を設定するには不十分なノイズがあり、アラートが発火した時に実際に行動する人がいません。

もう一つの前提条件は分類上の規律です。ステージがロールごとに異なって命名されている場合、または採用マネージャーが検索の途中で新しいステージを自由に作成する場合、ロール別ステージ別の集計は(ロール、ステージ)のペアが1つのサンプルサイズの長いテールを生成します。検出器の MIN_SAMPLE = 20 ガードはそれらを抑制します。これは正しいですが、間違ったシグナルではなくシグナルがまったくないことになります。まずステージ分類を修正してください。

使わない場面

アクティブなロールが5件未満の場合は実装しないでください。数学が機能しません — (ロール、ステージ)ペアごとのイベントが少なすぎて意味のあるベースライン標準偏差を計算できず、スプレッドシートでの週次手動レビューよりも多くの時間をしきい値の調整に費やします。

ATSが候補者データが存在する唯一の場所であり、まだ別の分析ウェアハウスを持っていない場合は実装しないでください。フローは候補者データをミラーリングできるPostgresデータベースを立ち上げることができることを前提としています。プライバシーまたはAIポリシーチームがATSを離れる候補者データをまだ承認していない場合は、集計されたステージレベルのカウントのみに対してこの演習を実行し — 候補者レベルのドウェル計算を削除 — ポリシーが追いつくまで待ってください。

週次で変わるステージ分類の上にこれを実装しないでください。移動する定義の「ステージ」に対する異常検出は誰も解釈できないアラートを生成します。フローをオンにする少なくとも1四半期前から分類を安定させてください。

最後に、チームのファネルアラートへの対応が「それは知っていた」であれば実装しないでください。ワークフローの価値は60日で表面化するメトリクスの24時間レイテンシーです。それをすでにライブでレビューする毎日のスタンドアップがある場合、アラートは冗長です。

セットアップ

まずベースラインを構築します。ワークフローが使用するAshbyアプリケーションフィードエンドポイントを使用して過去90日間の1回限りのバックフィルを実行し、(role_id, from_stage, to_stage) でグループ化し、conversion_rate_meanconversion_rate_stddevdwell_seconds_p50stage_sla_secondssample_sizefunnel_baselines テーブルに書き込みます。そのテーブルのDDL — role_tth_baselinesanomaly_alerts も — はバンドルの _README.md にあります。

バンドルから hiring-funnel-anomaly-n8n.json をn8nにインポートします。ワークフローは意図的に非アクティブで提供されています。Settings を開き、タイムゾーンがチームの業務時間とマッチすることを確認します;両方のCronノードはワークフローのタイムゾーン(UTCではなく)でその式を評価します。JSONで名前で参照されている4つの認証情報を作成します:PLACEHOLDER_ASHBY_CRED_IDPLACEHOLDER_POSTGRES_CRED_IDPLACEHOLDER_ANTHROPIC_CRED_IDPLACEHOLDER_SLACK_CRED_ID。READMEはSlackスコープ(chat:writechat:write.public)とAnthropicヘッダー認証の形状を含む各一つについてのウォークスルーです。

有効化前に5ステップの初回実行検証を実行してください。ステップ2 — 確実にフラグが立つ合成ベースライン行の挿入 — がほとんどの人がスキップしてアラートが発火しない理由を疑問に思うものです;実行してください。ステップ3は重複排除キーが機能していることを確認します。これはClaude呼び出しのコストガードです。

ベースラインを毎月更新します。コンバージョン率は季節性、市場状況、チーム構成とともにドリフトし、古いベースラインはアラートスパムまたは見逃された退行を生成します。更新はベースラインを構築した同じクエリです;別のn8n ワークフローまたはPostgres側のSQLジョブとしてcronします。

フローが行うこと

午前2時のCronが過去24時間のAshbyアプリケーションフィード引き出しをトリガーします。集計コードノードは (role_id, from_stage, to_stage) でイベントをグループ化し、今日の各ペアのコンバージョン率と中央値ドウェルタイムを計算し、ペアごとに1つのアイテムを出力します。Postgres Lookup Baseline ノードは各ペアをそのベースライン行に結合します。Detect Anomalies コードノードは3つのルールを適用します:ベースライン平均に対して -2.0 を下回るステージコンバージョンzスコアは stage_conversion_drop としてフラグされ、stage_sla_seconds * 1.5 を超える中央値ドウェルは candidate_stalled としてフラグされ、今日ゼロイベントで20件未満の過去イベントを持つ(ロール、ステージ)ペアはしきい値が抑制されたという低重症度のノートで new_role_no_movement としてフラグされます。

各フラグは role::from_stage::to_stage::anomaly_type::yyyy-mm-dddedupe_keyON CONFLICT DO NOTHING 句の下に anomaly_alerts に書き込まれます。行を返したインサート — つまり、今日まだ存在しないアラート — のみがClaudeナラティブ呼び出しとSlack投稿に進みます。これがコストガードです:同じ日のワークフローの再実行はAnthropicに二重請求せず、Slackに二重投稿しません。Slackフォーマッターは異常タイプでルーティングします:ステージレベルのドロップと停滞した候補者は #recruiting-alerts に、採用完了日数のトレンドと新規ロールノームーブメントは #recruiting-leadership に、ソースチャンネルのドロップは #sourcing に送信されます。

午前3時のCronは並行する採用完了日数トレンドパスを hires テーブルに対して実行します。ローリング7日平均がしきい値を超える行をすべて同じアラートエンベロープに再形成し、同じ重複排除と投稿パスを通じて実行します。

コストの実態

30ロールのチームがこれを毎晩実行する場合、1日あたり約600の(ロール、ステージ)集計を期待します。Ashby引き出しとPostgresルックアップは実質無料です。Claudeナラティブ呼び出しは256トークンキャップで claude-sonnet-4-6 を使用し、新たに挿入されたアラートのみで発火します — 健全なチームの場合、これは通常1晩あたり0〜3件のアラート、つまり約0.05〜0.15ドルのトークン支出です。20件の同時退行のスパイクは約1.00ドルです。重複排除キーにより再実行は無料です。

月20ドルのVPS上のn8nセルフホストはこの負荷をマージンを持って処理します;n8n CloudのStarterプラン(月24ドル)も問題ありません。Postgresは他に実行しているものと同じインスタンスにすることができます — 3つのテーブルは小さく、トラフィックが少なく、単一の複合キーにインデックス付けされています。総限界コストはランタイムではなく、ベースラインを新鮮に保ちステージ分類を安定させるための人的時間に支配されています。

ナラティブ呼び出しにOpusを使う場合、約5倍のトークンコスト乗数を期待します;1〜2文の説明にはほとんどの場合価値がありません。

成功指標

(ロール、ステージ)の退行が実際に始まってから採用チームがそれに対してアクションを取るまでの中央値時間を追跡します。このフロー以前、そのレイテンシーは通常2〜6週間です(次のパイプラインレビュー)。フローが実装されて監視されると、24〜48時間に落とすべきです。落ちない場合 — アラートが発火しても誰も行動しない場合 — 問題は検出器ではなく、ルーティングまたはしきい値であり、修正はアラートが行動権限を持つ人物に届くまでチャンネルを絞るか、アラートボリュームがチームが吸収できるものとマッチするまでzスコアしきい値を緩めることです。

監視する価値のある二次指標:アクションなしで却下されたアラートの割合。30%を超えるとノイズでアラートしています;5%未満はおそらくアンダーアラートでシグナルを見逃しています。

代替手段との比較

DIYの代替手段は、同じ集計を実行してWebhook経由でSlackに投稿するPythonまたはSQLジョブです。機能し、イベントごとのコストは低いですが、n8nグラフがドキュメントです — 来月参加する採用オペレーションエンジニアは、コードを読まずにワークフローを開き、8つのノードを順に見て、システムを理解できます。DIYパスは通常、重複排除インサートとLLM呼び出しのコストガードもスキップします。それが請求が来る場所です。

市販の代替手段は採用ファネルレポートのためにGemAshby Analytics、またはDatapeopleを購入することです。これらは管理されたダッシュボードが必要でPostgresベースラインテーブルを所有したくないチームには良いプロダクトで正しい答えです。ナラティブが添付されたSlackの異常アラートが必要な場合には間違った答えです。なぜなら今日それをどれも提供していないからです;ダッシュボードを提供しており、誰かが確認することを覚えている必要があります。トレードオフ:ベンダーに支払いアラートレイテンシーを失うか、n8nフローを所有してPostgresを実行するコストで24時間シグナルを得るかです。

現状の代替手段 — 四半期ごとのパイプラインレビュー — がほとんどのチームがすでに行っていることです。何もかかりません、60日遅れて同じ退行を表面化します。ロールが充填に6ヶ月かかり、60日のシグナルでもまだ修正する時間がある場合、現状のままが本当に問題ありません。

注意点

アラート疲弊が支配的な失敗モードです。 毎朝10件のアラートを受け取るチームは1週間以内にすべて10件を無視するようになります。10件のうち重要だったものも含めて。ガードは Detect Anomalies コードノードの MIN_SAMPLE = 20Z_THRESHOLD = 2.0 定数、プラス停滞した候補者に対する DWELL_MULTIPLIER = 1.5 です。それらの値で始め、最初の3夜チャンネルを監視し、絞めてください — 緩めない — 毎朝0〜2件のアラートになるまで。本当の退行を見逃していることがわかった後で緩めてください。

ベースラインドリフトはサイレントなフォールスネガティブを生成する。 コンバージョン率は労働市場、チームのソーシングミックス、ロール自体とともに変わります。11月に熱い市場に対して計算されたベースラインは、ソフトな市場ではアンダーフラグし、タイトな市場ではオーバーフラグします。ガードは funnel_baselinesrole_tth_baselines の毎月の更新です — それらを構築した同じクエリから — それをn8nワークフローとしてスケジュールするか、Postgresジョブとし、その更新の失敗をP1インシデントとして扱います。

採用アラートへの自動アクションはほぼ常に間違っています。 Claudeが返すナラティブは相関であり、因果ではありません;指示として扱うこと(「コンバージョンが30%落ちた、電話スクリーンのノーショーを自動的に却下する」)は問題を悪化させます。ガードは構造的です:フローはATSへのライトバックパスを持っていません。将来のコントリビューターが追加を提案した場合は反対してください。AIが異常を表面化し;人間が診断してアクションします。

特権的な候補者データがATSを離れる。 Postgresテーブルは role_id、ステージ名、コンバージョン率、ドウェルタイムを保持します。これは設計上集計のみですが — ただし、よりリッチなナラティブを可能にするために候補者名や連絡先情報を追加する不注意な拡張は新しいプライバシーサーフェスを作ります。ガードは _README.md のスキーマです:テーブルには意図的に候補者識別列がありません。コントリビューターがそれらを追加したい場合は、プライバシーとAIポリシーレビューを通じて変更をルーティングしてください。

ソースチャンネルのアトリビューションはATSデータと同じ品質しか持ちません。 Slackルーティングマップで参照されているオプションの source_channel_drop アラート(ただしバンドルではデフォルトで有効になっていない)は、Ashbyですべての応募者がクリーンなソースアトリビューションを持つことに依存しています。チームがソースタグ付けについて不注意であれば、アラートは本当のチャンネル問題ではなくデータ品質の問題で発火します。ガードは前提条件チェックです:ソースアトリビューションがATSエクスポートで少なくとも90%完全になるまでそのアラートタイプを有効にしないでください。アプリケーションフィードに対して1行のSQLクエリで確認してください。

スタック

このフローは、オーケストレーションにn8n、ATSとしてAshby(またはGreenhouse/Lever)、ベースラインとアラートステートにPostgres、ナラティブの説明にClaude、配信にSlackを前提としています。採用ファネルメトリクスで定義されたメトリクスの操作的な補完であり、トレンドチェックパスで採用完了日数対充填日数の区別を使用します。

Files in this artifact

Download all (.zip)