第一阶段:批量筛选简历(通用版)
核心定位
通用岗位简历批量筛选工具。输入任意岗位JD和候选人简历文件夹,自动解析JD提取评估维度,对多候选人进行统一打分排序,输出标准化筛选报告。
功能说明
批量解析多个候选人的简历,对照岗位JD进行多维度打分,输出:
- 简历筛选报告.xlsx(所有候选人分数、关键信息、排序)
- 面试邀请名单.xlsx(进入面试名单及邀请状态)
输入要求
必要信息
- 岗位JD文件(docx/pdf/md/txt)— 支持任意行业/职能岗位
- 简历文件夹(多份简历,支持docx/pdf/jpg/png)
可选信息
- 筛选标准(如:综合得分≥60分进入面试)
- 面试官安排
- 面试时间安排
核心流程
┌─────────────────────────────────────────────────────────────┐
│ 步骤1:解析JD │
│ ↓ │
│ • 提取硬性要求(学历/年限/专业/证书等) │
│ • 提取评估维度(3-5个核心能力项) │
│ • 提取加分项(专利/证书/特定经验等) │
│ ↓ │
│ 步骤2:解析简历 │
│ ↓ │
│ • 提取基本信息(姓名/学历/工作年限) │
│ • 提取工作经历(公司/职位/时间/业绩) │
│ • 提取技能/项目/证书等信息 │
│ ↓ │
│ 步骤3:多维度打分 │
│ ↓ │
│ • 基础维度打分(6项通用维度) │
│ • JD专项维度打分(根据JD自动生成) │
│ ↓ │
│ 步骤4:排序输出 │
│ ↓ │
│ • 生成筛选报告.xlsx │
│ • 生成面试邀请名单.xlsx │
└─────────────────────────────────────────────────────────────┘
评估维度体系
总分:100分制 - 所有候选人按同一标准评分,确保跨岗位可比性。
统一评分维度(所有岗位适用)
| 维度 | 分值 | 评分标准 |
|---|
| 学历 | 15分 | 博士15/硕士12/本科8/大专4 |
| 工作年限 | 10分 | 8年+满分10/5年+8分/3年+6分/1年+4分 |
| 技能匹配 | 25分 | 与岗位核心技能关键词匹配度,按匹配数量计算 |
| 项目/经验质量 | 25分 | 目标岗位相关项目经验质量,分4个等级 |
| 职业稳定性 | 15分 | 8年+15分/5年+12分/3年+8分/1年+5分 |
| 软性能力 | 10分 | 沟通协作、团队配合等,默认8分 |
技能匹配评分计算方法
def calc_skill_match(skills, job_type):
"""计算技能匹配得分"""
all_text = " ".join(skills).lower()
if job_type == "tech":
# 技术岗核心技能
tech_skills = ["CUDA", "OpenCL", "SIMT", "SIMD", "GPGPU", "GPU", "NPU", "RISC-V",
"Verilog", "VHDL", "UVM", "RTL", "Gem5", "GPGPU-Sim", "SystemC",
"SoC", "FPGA", "芯片架构", "微架构", "指令集", "AI", "深度学习", "流片", "量产"]
matched = [s for s in tech_skills if s.lower() in all_text]
return min(25, len(matched) * 3 + (5 if len(matched) >= 5 else 0))
elif job_type == "market":
# 市场岗核心技能
market_skills = ["市场开拓", "客户关系", "项目管理", "PMP", "AEC-Q", "ISO26262", "车规", "上车", "Tier1", "整车"]
matched = [s for s in market_skills if s.lower() in all_text]
return min(25, len(matched) * 4 + (5 if len(matched) >= 4 else 0))
return 15 # 默认
项目经验评分标准
| 等级 | 技术岗分值 | 市场岗分值 | 条件 |
|---|
| 卓越级 | 22-25分 | 22-25分 | 有目标岗位同类产品主导经验,成果可量化 |
| 良好级 | 16-21分 | 16-21分 | 有目标岗位同类项目完整参与经验 |
| 中等级 | 10-15分 | 10-15分 | 有相近岗位项目经验 |
| 基础级 | 5-9分 | 5-9分 | 有相关基础经验,无直接项目经历 |
筛选标准
| 分数区间 | 建议 |
|---|
| ≥85分 | ✅ 强烈推荐 |
| 70-84分 | ✅ 推荐 |
| 60-69分 | ⚠️ 备选 |
| <60分 | ❌ 不推荐 |
硬性门槛检测(先于打分)
| 门槛项 | 要求 | 不满足处理 |
|---|
| 学历 | JD要求的最低学历 | 直接淘汰或总分上限60分 |
| 工作年限 | JD要求的最少年限 | 明显不足者直接淘汰 |
| 必备技能 | JD要求的核心技能 | 无必备技能者直接淘汰 |
| 行业经验 | JD要求的特定行业 | 无行业经验者降一档 |
JD解析方法
自动提取流程
def parse_jd(jd_content):
"""从JD内容中自动提取评估维度"""
# 1. 提取硬性要求
hard_requirements = {
'学历': extract_education(jd_content), # 如:硕士及以上
'年限': extract_experience(jd_content), # 如:5年+
'专业': extract_major(jd_content), # 如:计算机相关
}
# 2. 提取评估维度(3-5个核心能力)
evaluation_dimensions = extract_core_abilities(jd_content)
# 如:[架构设计, 算法开发, 团队管理, 客户对接]
# 3. 提取加分项
bonus_items = extract_bonus_items(jd_content)
# 如:[PMP认证, CPA, 行业排名前十公司经验]
return hard_requirements, evaluation_dimensions, bonus_items
JD关键词识别
| 类别 | 识别关键词 |
|---|
| 学历要求 | "硕士及以上"、"本科985/211"、"全日制" |
| 年限要求 | "5年+"、"8年+"、"10年以上" |
| 硬性技能 | "熟练掌握"、"精通"、"必须具备" |
| 加分技能 | "加分"、"优先"、"更佳" |
| 行业经验 | "医疗行业"、"金融行业"、"汽车电子" |
| 证书资质 | "CFA"、"CPA"、"PMP"、"司法考试" |
不同岗位类型的权重策略
| 岗位类型 | 权重调整策略 |
|---|
| 技术/研发类 | 技能匹配度25-30分,项目经验质量25-30分 |
| 算法/AI类 | 技能匹配度30-40分,学历权重提高(15-18分) |
| 管理类 | 软性能力15-20分,工作年限权重提高 |
| 市场/销售类 | 行业经验权重提高,技能匹配度权重降低 |
| 运营/产品类 | 项目经验权重提高,学历权重降低至8-10分 |
| 职能/支持类 | 稳定性权重提高,技能匹配度权重降低 |
专业经验详细评分规则(20分)
根据JD提取的核心能力进行评估:
| 等级 | 分值 | 条件 |
|---|
| 极强 | 18-20分 | 同时满足岗位JD要求的全部核心能力项 |
| 强 | 14-17分 | 满足岗位JD要求的3项以上核心能力 |
| 中 | 9-13分 | 满足岗位JD要求的2项核心能力 |
| 弱 | 4-8分 | 满足岗位JD要求的1项核心能力 |
| 极弱 | 0-3分 | 无相关经验 → 淘汰或降级 |
项目经验质量详细评分规则(25分)
| 等级 | 分值 | 条件 |
|---|
| 卓越级 | 23-25分 | 有目标岗位同类产品/项目主导经验,成果可量化 |
| 良好级 | 18-22分 | 有目标岗位同类项目完整参与经验 |
| 中等级 | 12-17分 | 有相近岗位项目经验 |
| 基础级 | 6-11分 | 有相关基础经验,但无直接项目经历 |
| 无关级 | 0-5分 | 无目标岗位直接经验 → 降级处理 |
注:卓越级指主导并产生明确成果的项目,良好级指完整参与但非主导,中等级指行业相近但岗位不同
筛选标准
| 建议等级 | 分数区间 | 建议动作 |
|---|
| 强烈推荐 | ≥80分 | 优先安排面试(核心岗位/稀缺人才) |
| 推荐 | 70-79分 | 安排面试(匹配度良好) |
| 备选 | 60-69分 | 根据招聘数量决定(基本匹配) |
| 不推荐 | <60分 | 不进入面试(存在明显短板) |
注:分数区间可根据岗位紧急程度调整,如急招岗位可将"备选"区间提升至55-59分
中文简历解析实现要点
依赖库
import pdfplumber # PDF文本提取
from docx import Document # Word文档解析
import re # 正则表达式
from pathlib import Path
PDF文本提取
def read_pdf(path):
text = ""
with pdfplumber.open(path) as pdf:
for page in pdf.pages:
text += page.extract_text() or ""
return text
Word文档解析
def read_docx(path):
doc = Document(path)
return "\n".join([p.text for p in doc.paragraphs])
姓名提取(重要:多种格式兼容)
def extract_name(content, filename):
"""提取简历姓名,兼容多种格式"""
# 1. 优先匹配 "姓 名:冯亮" 格式(中间有空格/制表符)
name_match = re.search(r'姓\s*名[::]\s*([\u4e00-\u9fa5]{2,4})', content)
if name_match:
return name_match.group(1)
# 2. 备用:从文件名获取(当简历正文无标准姓名格式时)
return filename.replace('.docx', '').replace('.pdf', '').strip()
工作年限提取
def extract_work_years(content):
"""提取工作年限"""
# 优先匹配 "工作年限:9年" 格式
year_match = re.search(r"工作年限[::]\s*(\d+)", content)
if year_match:
return int(year_match.group(1))
# 备用:从工作经历时间范围推算(取最早年份)
dates = re.findall(r"(\d{4})[.\-/~]", content)
if dates:
try:
years = [int(d) for d in dates if len(d) == 4]
if years:
return 2026 - min(years)
except:
pass
return 5 # 默认值
学历提取
def extract_education(content):
"""提取学历层次"""
if "博士" in content:
return "博士"
elif "硕士" in content or "研究生" in content:
return "硕士"
elif "本科" in content:
return "本科"
else:
return "大专"
核心技能提取(大小写不敏感)
def extract_skills(content):
"""提取核心技能关键词"""
skills = []
content_lower = content.lower()
skill_pool = [
"CUDA", "OpenCL", "ROCm", "SIMT", "SIMD", "GPGPU", "GPU", "NPU", "TPU", "RISC-V",
"Verilog", "VHDL", "SystemVerilog", "UVM", "RTL",
"Gem5", "GPGPU-Sim", "SystemC",
"SoC", "FPGA", "ASIC",
"Linux", "KVM", "虚拟化",
"AEC-Q", "ISO26262", "车规",
"芯片架构", "微架构", "指令集", "ISA",
"AI", "人工智能", "深度学习", "机器学习",
"市场开拓", "客户关系", "渠道管理", "项目管理", "PMP",
"流片", "量产", "EDA",
"物理", "电路", "半导体", "器件",
]
for skill in skill_pool:
if skill.lower() in content_lower:
skills.append(skill)
return list(set(skills))
公司提取
def extract_companies(content):
"""提取工作单位"""
companies = re.findall(r'([\u4e00-\u9fa5]{2,15}(?:公司|集团|科技|技术|有限|股份|研究所))', content)
return list(set(companies))[:5]
输出文件
简历筛选报告.xlsx
Sheet1: 筛选结果汇总(全部候选人)
| 序号 | 姓名 | 应聘岗位 | 综合得分 | 排名 | 学历 | 工作年限 | 技能匹配 | 项目经验 | 稳定性 | 软性 | 邀请状态 | 核心技能 |
|---|
数据要求:
- 按综合得分降序排序
- 得分保留整数
- 邀请状态:✅强烈推荐/✅推荐/⚠️备选/❌不推荐
Sheet2-N: 各岗位筛选结果(含评分依据)
每个岗位一个Sheet,Sheet命名=岗位名称(最长20字符)
包含两部分内容:
第一部分:候选人得分汇总表
| 序号 | 姓名 | 综合得分 | 排名 | 学历 | 工作年限 | 技能匹配 | 项目经验 | 稳定性 | 软性 | 邀请状态 |
|:---:|:---|:---:|:---:|:---|:---:|:---:|:---:|:---:|:---:|:---:|:---|
第二部分:候选人详细评分依据(每人占用约15行)
每位候选人包含以下评分明细:
【候选人:XXX】
■ 学历评分(满分15分,得X分)
评价依据:[学历层次],[院校背景](如适用)
结论:满足/不满足JD学历要求
■ 工作年限评分(满分10分,得X分)
评价依据:工作年限X年,对应档位[X年+],得X分
结论:满足/不满足JD年限要求
■ 技能匹配评分(满分25分,得X分)
匹配技能:[列出所有匹配的技能关键词,用"/"分隔]
计算方法:匹配X个技能 × 3分 = X分(上限25分)
结论:技能匹配度[X/高/中/低]
■ 项目经验评分(满分25分,得X分)
评价依据:[简要描述项目经验质量]
等级认定:[卓越/良好/中等/基础级]
结论:项目经验与岗位要求[匹配度高/中/低]
■ 职业稳定性评分(满分15分,得X分)
评价依据:工作年限X年,平均每段工作时间约X年
结论:职业稳定性[高/中/低]
■ 软性能力评分(满分10分,得X分)
评价依据:[从简历中提取的软性能力描述]
结论:软性能力[强/中/弱](默认8分)
■ 综合评价
总分:X分(学历X+年限X+技能X+项目X+稳定X+软性X)
建议:✅强烈推荐/✅推荐/⚠️备选/❌不推荐
■ 核心优势
1. [优势1]
2. [优势2]
■ 风险点
1. [风险点1]
2. [风险点2]
■ 面试关注要点
1. [关注点1]
2. [关注点2]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
面试邀请名单.xlsx
Sheet1: 邀请名单
| 序号 | 姓名 | 综合得分 | 学历 | 工作年限 | 核心优势 | 邀请状态 | 面试时间 | 面试形式 | 主面试官 | 备注 |
|---|
Sheet2: 候选人关键信息
每个候选人一个区块:
【候选人:姓名】
综合得分:XX分 排名:第X名
关键经历:━━━━━━━━━━━━━━━━━━━━
核心技能:━━━━━━━━━━━━━━━━━━━━
风险提示:━━━━━━━━━━━━━━━━━━━━
面试关注点:━━━━━━━━━━━━━━━━━━
评分标准模板.xlsx
Sheet1: 评分维度总览
| 维度 | 最高分 | 评分说明 |
|---|
| 学历 | 15分 | 按院校层次打分 |
| 工作年限 | 10分 | 按年限档位打分 |
| 技能匹配度 | 20分 | 按与JD要求匹配度打分 |
| 项目经验质量 | 25分 | 按项目规模/成果分级 |
| 职业稳定性 | 10分 | 按平均每段工作时间打分 |
| 软性能力 | 10分 | 按管理/协作/沟通打分 |
| JD专项加分 | 10分 | 根据具体岗位JD提取 |
Sheet2: 筛选标准
| 分数区间 | 建议 |
|---|
| ≥80分 | ✅ 强烈推荐 |
| 70-79分 | ✅ 推荐 |
| 60-69分 | ⚠️ 备选 |
| <60分 | ❌ 不推荐 |
Sheet3: 学历评分细则
| 学历层次 | 分值 |
|---|
| 博士(985/211) | 15分 |
| 硕士(985/211) | 13分 |
| 硕士(普通院校) | 11分 |
| 本科(985/211) | 8分 |
| 本科(普通院校) | 6分 |
| 大专 | 3分 |
Sheet4: 各项评分细则
详细列出其他维度的评分标准
候选人详细评分依据.xlsx
Sheet1: 全部候选人汇总
| 候选人 | 学历 | 年限 | 技能匹配 | 项目质量 | 稳定性 | 软性 | JD专项 | 总分 | 排名 | 建议 |
|---|
Sheet2-N: 各候选人详细评分说明
| 维度 | 得分 | 评分依据 |
|---|
| (每行一个维度的详细评分说明) | | |
| 核心优势:xxx | | |
| 风险点:xxx | | |
排版格式
Excel格式要求:
- 表头:加粗,背景色#E0E0E0,黑色边框
- 数据行:白底,黑色细线边框
- 综合得分列:黄色背景#FFFF00(可编辑),居中对齐
- 强烈推荐/推荐:绿色背景#C6EFCE
- 备选:橙色背景#FFEB9C
- 不推荐:红色背景#FFC7CE
- 列宽:自动适应(建议width=14)
文件命名:{岗位名称}-筛选报告-{日期}.xlsx
文件写入注意事项(WSL环境)
权限问题处理:WSL环境下直接写入/mnt/d/路径可能遇到PermissionError
# 解决方案:先写入/tmp,再复制到目标目录
import shutil
output_path = '/tmp/简历筛选报告.xlsx'
wb.save(output_path)
# 复制到Downloads目录
shutil.copy(output_path, '/mnt/c/Users/{用户名}/Downloads/')
注意事项
- 通用性优先:本Skill适用于任何行业/职能岗位,不预设任何特定行业词汇
- 批量处理时保持每个候选人评估标准一致
- 关键信息(核心技能、量化指标)需在备注中标注
- 对不确定的信息在备注中标注"待核实"
- 排序必须按综合得分降序
- 中文文件名可能有空格(如"周光迪 .pdf"),解析时需注意strip处理
- PDF文件必须使用pdfplumber库提取文本,不要用PyPDF2(中文支持差)
- JD解析时优先提取JD中的专有词汇作为评估维度,确保评分与岗位需求精准匹配
重要:重新生成文件时的处理流程
当用户要求重新生成筛选报告时,必须遵循以下步骤避免数据不一致:
步骤1:删除旧文件
# 删除该目录下所有之前生成的筛选报告文件
rm -f /目标目录/简历筛选报告*.xlsx
rm -f /目标目录/面试邀请名单*.xlsx
rm -f /目标目录/候选人详细评分依据*.xlsx
步骤2:使用验证过的评分数据
- 不要重新解析简历(解析结果可能因算法微调而变化)
- 使用已验证的、用户确认过的正确评分数据
- 如无验证数据,需先与用户确认评分标准
步骤3:生成后一致性检查
- 验证"筛选结果汇总"和"面试邀请名单"中的候选人数据一致
- 确保总分、排名、建议在所有sheet中保持一致
错误示例(避免)
❌ 先生成文件A发现问题后修改评分再生成文件B
❌ 筛选结果汇总和面试邀请名单使用不同的评分结果
❌ 保留旧的Excel文件只覆盖部分sheet
正确示例
✅ 确认评分标准 → 删除旧文件 → 生成新文件 → 验证一致性