krzznh/CHAOS-Redrob-TalentRank-AI
GitHub: krzznh/CHAOS-Redrob-TalentRank-AI
一个面向大规模招聘场景的AI候选人排名系统,通过多信号评分与语义相似度从十万级候选人中智能筛选Top候选人。
Stars: 0 | Forks: 0
# Redrob 黑客松 — 高级 AI 工程师候选人排名系统
## 快速开始
```
# 1. 安装 dependencies
pip install -r requirements.txt
# 2. 放置 dataset
cp /path/to/candidates.jsonl data/
# 3. 运行 ranker
python rank.py --candidates data/candidates.jsonl --out submission/submission.csv
# 4. 验证
python validate_submission.py submission/submission.csv
# 5. 启动 demo
streamlit run demo/app.py
```
## 仓库结构
```
hackathon/
├── rank.py # Main entry point
├── precompute_embeddings.py # Optional: pre-compute embeddings offline
├── requirements.txt
├── .gitignore
│
├── src/
│ ├── jd_config.py # JD taxonomy: skill lists, weights, thresholds
│ ├── features.py # 7 scoring dimensions (rule-based)
│ ├── honeypot_detector.py # Impossible profile detection
│ ├── semantic.py # MiniLM-L6-v2 embedding similarity
│ ├── ranker.py # Main orchestration pipeline
│ ├── reasoning.py # Factual reasoning string generation
│ └── writer.py # Submission CSV writer (tie-break aware)
│
├── demo/
│ └── app.py # Streamlit demo application
│
├── tests/
│ ├── test_features.py # 28 unit tests for feature scoring
│ ├── test_honeypot.py # 8 unit tests for honeypot detection
│ └── test_writer.py # 9 unit tests for CSV writer
│
├── submission/
│ ├── submission.csv # ✅ Validated, 100 candidates
│ └── submission_metadata.yaml # Team + methodology declaration
│
├── data/
│ └── sample_candidates.json # 500-candidate sample for demo/tests
│
└── docs/
├── architecture.md # System design
└── methodology.md # Ranking approach & JD analysis
```
## 架构

## 工作原理
### 挑战的隐藏难点
JD(职位描述)中包含一个明确的陷阱(直接引用):
天真的关键词匹配在两个方向上都会失败。我们的排名系统能同时处理这两种情况。
### 评分流水线(4 个阶段,总计约 15 秒)
```
Phase 1 — Rule-based scoring of ALL 100K candidates (~14s)
Phase 2 — Semantic embedding of TOP 2,000 only (~90s with MiniLM)
Phase 3 — Final score combination + select Top-100 (~1s)
Phase 4 — Reasoning generation (~1s)
```
**未预计算 embeddings**:约 15 秒(仅基于规则,semantic=0)
**预计算 embeddings**:总计约 15 秒(从缓存加载)
**实时生成 embeddings (top-2000)**:约 2.5 分钟
均完全符合 5 分钟的预算限制。
### 评分维度
| 维度 | 权重 | 衡量标准 |
|---|---|---|
| **技能匹配** | 30% | 技能与 JD 分类法的精确匹配(必备技能权重 ×2,按熟练度 × 持续时间 × 认可数进行质量加权) |
| **职位 + 职业** | 25% | 职位层级(理想/强相关/邻近/不合格)× 职业履历的 ML 相关性。不合格职位(Marketing Manager、HR Manager 等)将直接把该部分得分归零 |
| **语义相似度** | 15% | 候选人文本与 JD 文本之间的 MiniLM-L6-v2 余弦相似度 |
| **经验契合度** | 10% | 以 JD 的最佳区间(6-8 年)为中心的曲线 YoE(工作年限)评分 |
| **行为信号** | 10% | 作为基础得分的**软乘数**(×0.60-1.0),而不仅仅是累加。不活跃的“纸面完美”候选人 < 活跃但不完美的候选人 |
| **地域契合度** | 5% | Pune/Noida = 1.0 · 印度二线城市 = 0.80-0.95 · 印度以外 = 0.18-0.45 |
| **教育背景** | 3% | IIT/IISc 等顶尖(tier-1)院校小幅加分;tier-4 保持中性 |
| **GitHub 活跃度** | 2% | 开源信号(0-100 分) |
#### 行为信号作为软乘数
JD 指出:
我们通过将 `behavioral_score` 作为基础得分的乘数来实现这一点:
```
behavior_multiplier = 0.60 + behavioral_score × 0.40 # range [0.60, 1.00]
final = base × behavior_multiplier + behavioral × weight_behavioral
```
### 技能匹配:精确名称
`src/jd_config.py` 中的所有技能名称都与数据集中的技能名称**完全匹配**(已针对所有 10 万个个人资料进行验证)。这避免了 `"embedding"` 永远无法匹配 `"Embeddings"` 的关键词重叠 Bug。
**必备技能**(占分数的 30%,每项权重 ×2):
`FAISS, Pinecone, Qdrant, Milvus, Weaviate, OpenSearch, Elasticsearch, pgvector, Vector Search, Sentence Transformers, Embeddings, Semantic Search, Dense Retrieval, Hybrid Search, Learning to Rank, Information Retrieval, BM25, NDCG, MRR, Python, MLOps`
每个匹配的技能都会根据以下因素进行加权:
```
quality = proficiency_mult × duration_mult × endorsement_mult + assessment_bonus
```
### 蜜罐检测
该数据集包含约 80 个伪造的个人资料。Top-100 列表中的蜜罐率 > 10% 即意味着**不合格**。
我们的检测器会标记具有以下特征的个人资料:
1. **不可能的时间线** — 职业履历总时长 > 标明的 YoE + 4 年
2. **专家 + 零持续时间** — `proficiency=expert` 且 `duration_months=0`
3. **认可度矛盾** — 所有技能都有 50+ 个认可,但 `endorsements_received=0`
4. **GitHub 不可能存在** — `github_activity_score=100` 且 `connection_count=0`
5. **完美完整度 + 零互动率** — `completeness=100`,`response_rate=0`,`interview_rate=0`
检测结果:在 10 万名候选人中标记了 **38 个蜜罐**。前 100 名中均未出现蜜罐。
### 语义相似度
使用 **`all-MiniLM-L6-v2`**(22M 参数,384 维 embeddings):
- CPU 上运行速度快:每秒约处理 500 名候选人
- 在基于规则的预过滤后,应用于排名前 2,000 的候选人(而非全部 10 万人)
- 候选人文本 = headline + summary + 前 15 项技能(按熟练度排序)+ 前 4 段职业描述
- 得分为经过 L2 归一化的余弦相似度,范围偏移至 [0, 1]
预计算所有 embeddings(可选):
```
python precompute_embeddings.py \
--candidates data/candidates.jsonl \
--output outputs/embeddings.pkl
```
然后使用缓存运行排名系统:
```
python rank.py \
--candidates data/candidates.jsonl \
--embeddings-cache outputs/embeddings.pkl \
--out submission/submission.csv
```
## 运行测试
```
python3 -m unittest tests/test_features.py tests/test_honeypot.py tests/test_writer.py -v
```
输出:
```
Ran 45 tests in 0.019s
OK
```
## 演示应用
```
streamlit run demo/app.py
```
页面:
- **概览** — 前 10 名候选人,评分权重图表
- **排行榜** — 可排序/过滤的排名表
- **候选人审查器** — 每位候选人得分组成的多维度雷达图
- **蜜罐检测器** — 可疑个人资料浏览器
- **评分分析** — 特征分布,YoE 直方图,职位细分
演示默认使用 `data/sample_candidates.json`。通过侧边栏上传任何 `.jsonl` 文件即可对自定义数据集进行排名。
## 提交格式
```
candidate_id,rank,score,reasoning
CAND_0077337,1,0.698273,"Staff Machine Learning Engineer, 7.0 yrs — vector DB + embeddings..."
CAND_0071974,2,0.697377,"Senior AI Engineer, 7.8 yrs — vector DB + embeddings..."
...
```
- 100 行(排名 1-100)
- 得分非递增;同分情况下按 `candidate_id` 升序排序
- 推理依据:基于事实、具体且与排名一致(无幻觉)
## 设计决策与权衡
| 决策 | 依据 |
|---|---|
| 选择 MiniLM 而非 BERT-large | 在 CPU 上运行速度快 15 倍,符合 5 分钟预算限制,且对于此任务质量已足够 |
| 精确技能名称匹配 | 避免因关键词列表导致的子串重叠误报 |
| 行为信号作为乘数而非累加 | 保留了 JD 中的核心洞察:不活跃的候选人实际上并不具备可雇佣性 |
| 对 top-2000 进行预过滤后再进行语义分析 | 10 万人 embeddings = 200 秒;top-2000 = 4 秒;对排名的影响微乎其微 |
| 得分输出保留 6 位小数 | 防止因保留 4 位小数导致的虚假同分,避免破坏同分情况下的校验逻辑 |
| 不合格职位得分直接归零 | 根据 JD 的明确指导,拥有 ML 技能的 Marketing Manager = 不符合要求 |
## 环境要求
```
pandas>=2.0.0
numpy>=1.24.0
sentence-transformers>=2.7.0 # for semantic layer (optional)
scikit-learn>=1.3.0
streamlit>=1.32.0
plotly>=5.18.0
tqdm>=4.66.0
pyyaml>=6.0.0
```
该流水线在**未**安装 sentence-transformers 的情况下也能运行(语义得分 = 0,其他 7 个维度依然有效)。安装它以获得完整性能:
```
pip install sentence-transformers
```
标签:Kubernetes, Python, Streamlit, 人工智能, 候选人排名, 数据筛选, 无后门, 用户模式Hook绕过, 访问控制, 语义相似度, 逆向工具