Resume screener
简历筛选与评分系统(boss-hr-auto 工作流的 Step 3)。LLM 评 4 维度最终分(exp/skill/proj/major)+ 脚本查 school_tier 校准 edu + 公式重算 total。 **本 Skill 是 boss-hr-auto 编排流程的子步骤,通常由 boss-hr-auto 在 Step 3 阶段调用,不应作为入口 Skill 直接加载。** **唯一方案**:5 维度 weighted 求和(edu 25% / exp 25% / skill 25% / proj 15% / major 10%),Tier 阈值 ≥70 推荐 / 60-69 待定 / <60 不推荐。From its SKILL.md
npx -y skills add 1xiaoyueryuer/boss-hr-agent-toolkit --skill resume-screenerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- runs commandsInstructs the agent to run 4 commands, including `python score_resumes.py --input <llm_scores.json> --output <screening_results.json> --job-name "车架工程师" --job-info <JD JSON 字符串>` and 3 more.
SKILL.md
16.2 KB, ~6.1k tokens by cl100k_base, as published. Nobody here has run it
Resume Screener
评分架构
- LLM 评 4 维度最终分:
exp / skill / proj / major全部由 LLM 真实分析完整简历后给出 0–100 的最终分(已综合考虑年限、对口度、实操深度、复杂度等) - 脚本只覆盖 1 维度:用
scripts/school_tier.py查表覆盖edu - 公式重算:5 维度 × 权重 = total(按 25/25/25/15/10)
- Tier 判定:≥70 推荐 / 60-69 待定 / <60 不推荐
- 通用:不限岗位(任一 JD 都能用)
LLM 不输出
industry_fit之类的系数标签。exp分本身已综合考虑对口度,脚本不会再乘任何系数。
核心不变量
| 项 | 值 |
|---|---|
| 5 维度权重 | edu 25% / exp 25% / skill 25% / proj 15% / major 10% |
| Tier 阈值 | 推荐 ≥70 / 待定 60-69 / 不推荐 <60 |
| 公式 | total = Σ (raw × weight) |
| Tier 名称 | 推荐 / 待定 / 不推荐 |
| 学校分档 | 7 档(C9 / 985 / 211 / 双一流 / 一本公办 / 二本公办 / 民办) |
| 评分主体 | LLM 评 4 维度最终分 + 脚本查 edu(仅此一套) |
工具脚本
scripts/score_resumes.py
工具函数(agent 直接 import 调用):
| 函数 | 作用 |
|---|---|
_extract_school_name(score) | 智能拆纯校名(优先 school_name,兜底从 school 按 /·(( 拆分) |
validate_score(score) | LLM 评分收尾:用 school_tier 覆盖 edu + 重算 weighted + total + 判定 tier |
calc_tier(total) | ≥70 推荐 / 60-69 待定 / <60 不推荐 |
calc_weighted(dims) | 5 维度 × 权重 |
calc_total(weighted) | 求和 |
candidate_to_report(c, rank) | list 元素 → candidates[] 格式 |
build_actions(candidates) | 生成 actions 三段式(recommend/pending/reject) |
build_meta(job_name, job_info) | 构造报告 meta |
CLI:
python score_resumes.py --input <llm_scores.json> \
--output <screening_results.json> \
--job-name "车架工程师" \
--job-info <JD JSON 字符串>
scripts/school_tier.py
from school_tier import lookup
info = lookup("辽宁工业大学")
# → {"tier": "二本公办", "score": 62, "matched": "辽宁工业大学", "fuzzy": False}
info = lookup("江南大学")
# → {"tier": "211", "score": 85, "matched": "江南大学", "fuzzy": False}
支持精确匹配 + 模糊匹配(输入校名是表内校的子串或父串时也能命中)。
分批策略
按 boss-recommend-downloader 的下载批次逐批评分,每批独立写文件、最后合并。
- 批次大小:默认每批 25 份(下载侧默认
--batch-size 25) - 单批内部小批:若 25 份简历偏长或 JD 复杂,LLM 内部可按 10 份/次再分小批循环处理,结果合并到同一个
_llm_scores_batch_N.json - 中途容错:单批评分失败不影响其他批;可重跑该批
完整工作流
# === Step 3a: 逐批评分(与下载批次对齐)===
# 假设已有 batch_1_resumes.json / batch_2_resumes.json / ...(来自 boss-recommend-downloader)
# 对每批简历:
for batch_n in 1 2 3 ...:
# 1. LLM 读 batch_n_resumes.json + JD
# 2. LLM 真实分析每份简历,评 4 维度最终分(exp / skill / proj / major)
# — 单批 25 份时,可内部按 10 份/次循环
# 3. 对每份评分,agent 调 validate_score(score) 收尾:
# - 自动从 score 拆出纯校名
# - 自动用 school_tier 查 edu(强制覆盖 LLM 凭印象打的分数)
# - 自动重算 weighted + total(按公式)
# - 自动判定 tier
# 4. 写出 _llm_scores_batch_${batch_n}.json
# === Step 3b: 合并所有批次 ===
# 方式 1(推荐):LLM agent 在内存里把所有 batch 的 _llm_scores_batch_*.json
# 拼成一个 list,写 _llm_scores.json
# 方式 2:跑 python -c "import json,glob; json.dump(sum([json.load(open(f,encoding='utf-8')) for f in sorted(glob.glob('_llm_scores_batch_*.json'))], []), open('_llm_scores.json','w',encoding='utf-8'), ensure_ascii=False, indent=2)"
# === Step 3c: 跑评分脚本 ===
python score_resumes.py --input _llm_scores.json \
--output screening_results.json \
--job-name "车架工程师" \
--job-info <JD JSON 字符串>
# === Step 4: 生成 HTML 报告 ===
python generate_html_report.py --input screening_results.json --output <job_name>_统一方案.html
preview_url 在 IDE 内置浏览器打开
工作区路径约定
所有数据统一存放在 ~/Desktop/boss-hr-output/<job_name>/ 下,由 shared/output_manager.JobOutputManager 管理。
~/Desktop/boss-hr-output/<job_name>/
├── process/
│ ├── job_detail.json ← Step 1: boss_jd.py 输出
│ ├── recommend_geek_ids.json ← Step 2: recommend_list.py 输出
│ ├── batch_N_resumes.json ← Step 2: recommend_download.py 输出(每批)
│ ├── test_resumes.json ← Step 2: 累计所有已下载简历
│ ├── _llm_scores_batch_N.json ← Step 3: LLM agent 评分(每批,可选)
│ ├── _llm_scores.json ← Step 3: 合并后的全量评分(喂给 score_resumes.py)
│ └── screening_results.json ← Step 3: score_resumes.py 输出
└── <job_name>_统一方案.html ← Step 4: generate_html_report.py 输出
上游
boss-job-detail/boss-recommend-downloader已自动写入此目录,下游脚本(score_resumes.py/generate_html_report.py)通过--input/--output读取此目录。
JobOutputManager提供的标准路径属性:jd_path/recommend_geek_ids_path/resumes_path/screening_results_path/report_path。
LLM 评分输入 schema
[
{
"name": "陈瀚",
"school": "辽宁工业大学/车辆工程/本科",
"work_years": "3 年",
"match_type": "山东浩信 · 汽车零部件三维设计",
"dims": {
"exp": 80,
"skill": 65,
"proj": 60,
"major": 100
},
"highlights": ["3 年 CATIA", "2 项发明专利"],
"concerns": ["做的是轮端非车架"],
"advice": "强烈建议电话沟通..."
}
]
字段说明:
| 字段 | 必填 | 说明 |
|---|---|---|
name | 是 | 候选人姓名 |
school | 是 | 校名(脚本自动拆出纯校名) |
work_years | 否 | 工作年限 |
match_type | 否 | 当前岗位 / 业务方向 |
dims.exp | 是 | LLM 评 0-100 最终分(工作经验:综合年限 + 对口度 + 实操深度) |
dims.skill | 是 | LLM 评 0-100 最终分(专业技能) |
dims.proj | 是 | LLM 评 0-100 最终分(项目经历) |
dims.major | 是 | LLM 评 0-100 最终分(专业匹配) |
dims.edu | 否 | 会被 validate_score 强制覆盖 |
school_name | 否 | 备选字段,优先级高于 school 拆分 |
highlights | 否 | 候选人亮点(推荐动作背景) |
concerns | 否 | 候选人顾虑(不推荐原因 / 待确认问题) |
advice | 否 | 个性化建议(推荐/待定动作方向) |
注意:
- 4 个 LLM 评分维度全部是最终分(0-100),脚本不会再做任何乘法 / 折扣
school字段允许任意格式,脚本智能拆出纯校名(支持/ · ( (等分隔符)- LLM 不要评
edu,会强制被school_tier覆盖
5 维度评分方法(理工类通用)
适用于一切工程/技术岗(机械、车辆、电子、材料、自动化、化工、土木、软件等)。LLM 评分时结合具体 JD 的核心技能清单与方向,按本表锚点给 0–100。所有维度给的都直接是最终分。
| 维度 | 权重 | 评分方 | 评分主体 |
|---|---|---|---|
| 学历 | 25% | school_tier 查表(校名→档次分);可选本/硕/博层次加成 | 脚本(强制) |
| 工作经验 | 25% | 综合考虑工作年限 + 与 JD 对口度 + 实操深度,给最终分 | LLM |
| 专业技能 | 25% | JD 核心技能覆盖度 × 实操深度 | LLM |
| 项目经历 | 15% | 项目与岗位的相关度 × 复杂度 × 角色 | LLM |
| 专业匹配 | 10% | 专业与 JD 的对口度(优先/相关/弱相关/无关) | LLM |
维度评分锚点
① 学历 edu(脚本查表,LLM 不评)
- 分数取
school_tier:C9=100 / 985=92 / 211=85 / 双一流=77 / 一本公办=71 / 二本公办=62 / 民办=53 - 表外学校:edu 显示"缺失",建议人工复核(可给默认 60 并标"需复核")
- (可选扩展)层次加成:硕士 +8、博士 +12,封顶 100——由脚本读
degree字段实现
② 工作经验 exp(LLM 评最终分 0–100)
LLM 在评 exp 时综合以下 3 个因素,给一个最终分:
- 工作年限(参考锚点):
- ≥8 年 = 95 / 5–7 年 = 85 / 3–4 年 = 75 / 1–2 年 = 60 / <1 年 = 45
- 与 JD 对口度(参考锚点,已并入最终分):
- 精准对口(与 JD 核心方向完全一致)= 不折扣
- 行业相关但非精准(测试/工艺/验证/零部件/相近子领域)= 视情况打 0.7×基础分附近
- 完全跨行业(纯销售/行政/文科背景)= 视情况打 0.4×基础分附近
- 实操深度(参考锚点):
- 能独立负责核心模块 + 有可验证产出 = 锚点 +5
- 仅参与执行 / 无量化成果 = 锚点 −5
以上三因素LLM 在打分时一次性综合考虑,直接给出最终分。脚本不参与任何乘法。
③ 专业技能 skill(LLM 评最终分 0–100)
- 按 JD 列出的核心技能清单评估"覆盖度 × 熟练度":
- 全覆盖且能独立负责核心模块 = 85–100
- 核心技能 70%+ 且较熟 = 70–84
- 覆盖 40–70% 或仅部分了解 = 55–69
- 覆盖 <40% 或仅字面提及 = 40–54
- 有 JD 硬性要求但不会的"硬伤":该档下限再 −10
④ 项目经历 proj(LLM 评最终分 0–100)
- 按"与 JD 岗位的相关度 + 复杂度 + 担任角色":
- 主导本岗核心项目(0–1 设计/量产落地)= 85–100
- 重要角色参与核心项目 = 70–84
- 边缘/支持角色、或项目仅部分相关 = 55–69
- 非相关但体现工程能力 = 40–54
- 无可验证项目 / 完全无关 = <40
⑤ 专业匹配 major(LLM 评最终分 0–100)
- 以 JD 要求的对口专业为"优先"基准,按专业大类映射(理工类通用):
- 优先=100:JD 直接点名的对口专业(随岗而定,如机械设计/车辆工程/材料成型/自动化/电子/化工等)
- 相关=80:同大类工科(机械类、车辆类、材料类、自动化/机电、土木、化工、计算机偏硬等相近领域)
- 弱相关=60:基础/交叉学科(力学、数学、物理、计算机偏软、工业工程等)
- 无关=40:文科、经管、艺术、生化医药等非工程背景
- 跨专业但有扎实对口课程 + 项目经历的,按"相关"档处理
评分公式
单维度加权分 = 原始分 (0-100) × 该维度权重
总分 = Σ(所有维度加权分)
示例 A(精准对口,3 年结构设计):
edu=62, exp=80, skill=65, proj=60, major=100
→ 62×0.25 + 80×0.25 + 65×0.25 + 60×0.15 + 100×0.10
→ 15.5 + 20.0 + 16.25 + 9.0 + 10.0 = 70.75 → "推荐"(≥70)
示例 B(行业相关非精准对口,3 年结构测试):
LLM 综合评估后直接给 exp 最终分 = 56(已包含"年限 75 × 对口度 0.7 ≈ 53" 的折扣判断)。
edu=62, exp=56, skill=65, proj=60, major=100
→ 62×0.25 + 56×0.25 + 65×0.25 + 60×0.15 + 100×0.10
→ 15.5 + 14.0 + 16.25 + 9.0 + 10.0 = 64.75 → "待定"(≥60)
Tier 判定
def calc_tier(total):
if total >= 70: return "推荐"
if total >= 60: return "待定"
return "不推荐"
学校分档表(脚本内置,500+ 学校)
| 档次 | 分数 | 示例学校 |
|---|---|---|
| C9 | 100 | 清华、北大、复旦、交大、浙大、中科大、南大、哈工大、西交 |
| 985 | 92 | 其他 30 所 985 高校 |
| 211 | 85 | 非 985 的 211 高校(如江南大学、苏州大学、华东理工) |
| 双一流 | 77 | 南方科技大学、上海科技大学、中国科学院大学 |
| 一本公办 | 71 | 深圳大学、广东工业大学、西安理工大学、杭州电子科技大学 |
| 二本公办 | 62 | 辽宁工业大学、信阳农林学院、太原工业学院、滁州学院、长江师范学院 |
| 民办/独立学院 | 53 | 燕京理工学院、黄河科技学院、郑州工商学院、四川工业科技学院 |
完整 500+ 学校列表见
scripts/school_tier.py。 不在表内的学校:返回score=None,edu 维度显示"缺失(XX 不在学校表)"。
LLM 评分调用示例
from score_resumes import validate_score
score = {
"name": "陈瀚",
"school": "辽宁工业大学/车辆工程/本科",
"work_years": "3 年",
"match_type": "山东浩信 · 汽车零部件三维设计",
"dims": {
"exp": 80, # LLM 评最终分
"skill": 65, # LLM 评最终分
"proj": 60, # LLM 评最终分
"major": 100 # LLM 评最终分
# edu 不需要填
},
"highlights": ["3 年 CATIA 三维设计", "2 项发明专利"],
"concerns": ["做的是轮端非车架本体", "无 CAE 仿真经验", "无焊接/工艺经验"],
"advice": "专业对口 + 设计经验真实,建议电话沟通是否有车架/底盘结构项目经验"
}
score = validate_score(score)
# → score["dims"]["edu"] = 62(二本公办,school_tier 查表)
# → score["total"] = 69.8
# → score["tier"] = "待定"
# → score["dims_edu_reason"] = "二本公办(school_tier 查询:辽宁工业大学)"
输出 schema(screening_results.json)
{
"job_name": "车架工程师",
"meta": {
"title": "车架工程师 · 简历筛选报告",
"subtitle": "LLM 主导评分 + school_tier 学历分档校准",
"job": {
"name": "...",
"company": "...",
"location": "...",
"salary": "...",
"experience_required": "...",
"degree_required": "..."
},
"type_judgment": {"type": "技术岗", "reason": "..."},
"core_requirements": ["..."]
},
"summary": {"total": 32, "recommend": 0, "pending": 2, "reject": 30},
"dimension_labels": ["学历", "工作经验", "专业技能", "项目经历", "专业匹配"],
"candidates": [
{
"rank": 1,
"name": "陈瀚",
"tier": "待定",
"total": 69.8,
"school": "辽宁工业大学/车辆工程/本科",
"work_years": "3年",
"current_role": "汽车零部件三维设计(轮端)",
"dimensions": [
{
"pct": 62,
"weighted": 15.5,
"weight": 25,
"reason": "二本公办(school_tier 查询:辽宁工业大学)"
}
],
"highlights": ["..."],
"concerns": ["..."]
}
],
"actions": {
"recommend": [{"name", "score", "background", "action"}],
"pending": [{"name", "score", "strengths", "action"}],
"reject": [{"name", "score", "concerns"}]
}
}
注意事项
- LLM 评 4 维度时务必读完完整简历再打分,避免"看一半就判断"
- 测试 / 设计 / 验证 / 仿真等职能差异要识别(如底盘电控功能测试 ≠ 车架结构设计)
- 学校档次 / tier 阈值 / 公式权重都由脚本控制,LLM 不要尝试覆盖
- exp 维度给的分数就是最终分,不要再额外标 industry_fit / 对口度系数,这些已经综合在 exp 分里了
- highlights / concerns / advice 是个性化建议的核心,必须基于候选人实际经历
What ships with it: 4 files
65.4 KB alongside SKILL.md, 4 of them executable
scripts/
- collect_llm_scores.pyruns8.1 KB
- prepare_scoring_inputs.pyruns13.8 KB
- school_tier.pyruns22.7 KB
- score_resumes.pyruns20.8 KB
Gives 0 of the 12 instructions most hr recruiting skills give in ~6.1k tokens
Counted across 356 of the 357 authors here whose files we hold, read 2026-08-07
- Quantify achievements with specific metricsin 14 of 356, across 6 files
- Keep the resume under two pagesin 14 of 356, across 6 files
- Request the full job description if not providedin 12 of 356, across 4 files
- Extract keywords and prioritize job requirementsin 12 of 356, across 4 files
- Stop and ask for clarification if required inputs are missingin 12 of 356, across 5 files
- Map candidate experience to job requirementsin 11 of 356, across 3 files
- Ask if the user wants adjustmentsin 11 of 356, across 3 files
- Provide strengths and gap analysis after the resumein 10 of 356, across 2 files
- Request candidate background details if not providedin 10 of 356, across 2 files
- Format experience bullets as action verb plus resultin 10 of 356, across 2 files
- Ask for missing inputs before startingin 10 of 356, across 9 files
- Use exact job description terminologyin 9 of 356, across 1 file
Said here and by no other author read
- Score resumes batch by batch in alignment with download batches
- Score four dimensions with LLM based on the full resume
- Run validate_score to override the education dimension via script lookup
- Calculate total score using fixed weights for five dimensions
- Assign tier based on total score thresholds
- Merge per-batch score files into a single combined file
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.