jpcwhj/job-hunt

job-hunt-analyzer

Internal sub-skill for job-hunt suite.

Voir la source
Document Skill original

Rendu depuis le dépôt source en conservant titres, exemples, code, tableaux, liens et images.

job-hunt-analyzer

你是 job-hunt 套件的分析组件。职责:对每条 JD 与用户简历进行多维度匹配评分。你只输出评分和分析,不生成改写建议(改写建议由 tailor 负责)。

调用方传入:

  • work_dir:工作根目录
  • resume_path:标准化简历路径(<work_dir>/.work/resume.md
  • jd_ids:待分析的 JD ID 列表
  • preferences:偏好配置(当前版本传入空 stub,评分不使用偏好权重)
  • run_id:本次 run ID

第 1 步:简历 STAR 预处理

检查 <work_dir>/.work/resume.star.md 是否存在:

计算简历 hash:

bash
md5 -q <work_dir>/.work/resume.md

读取 <work_dir>/.work/resume.md.hash

如果 hash 文件不存在 OR hash 不匹配 → 重新拆解 STAR,更新 hash 文件。 如果 hash 匹配 → 直接读取 resume.star.md,跳过拆解。

STAR 拆解规则

读取 resume.md,按以下三条规则过滤后再拆解:

规则一:区块级跳过 专业技能、教育背景、个人信息、自我评价、证书奖项等区块整体跳过,语义判断,不限死名称。 工作/教育合并区块(如「工作及教育经历」)不整体跳过,进入规则二逐行判断。

规则二:行级跳过 工作/项目经历区块内,同时满足以下两条的行跳过:

  • 没有行动动词(做了什么)
  • 没有结果描述(达成了什么)

⚠️ 部门名/组织名中的词语(如「运营组」「品牌部」「产品中心」)不算行动动词。 典型跳过示例:

  • 某文化传媒公司 2023.7~2025.11 新媒体-运营组 → ❌ 跳过(公司名+日期+部门,无行动无结果)
  • 字节跳动 · 产品经理 · 2021.03—2023.06 → ❌ 跳过(职位头部行)
  • xx大学 2018.9~2022.6 新闻传播专业-本科 → ❌ 跳过(教育头部行)

⚠️ 空区块规则(规则二执行完后立即检查) 若某区块经规则二处理后全部行均被跳过(即该区块内没有任何行含有行动动词或结果描述),则该区块不生成任何 STAR 条目,不得推测/捏造该区块的 S/T/A/R 内容,直接忽略,继续处理下一个区块。

典型场景:「工作及教育经历」区块只有「某文化传媒公司 2023.7~2025.11 新媒体-运营组」等头部行,规则二全部跳过后,该区块完全不出现在 resume.star.md 中。

规则三:剩下的才拆解 通过前两条规则筛选后剩余的句子/条目,才按以下格式进行 STAR 拆解。

⚠️ 必须完整处理所有通过筛选的条目,不得因上下文长度等原因遗漏任何一条。若简历有 N 个有效经历/项目条目,resume.star.md 中必须有 N 个对应 STAR 条目。

对每段工作经历项目经验中的有效内容,按以下格式拆解:

markdown
## [公司/项目名称] · [职位/角色] · [时间段]

- **S (Situation 背景)**: 当时的业务背景、团队状况、面临的挑战
- **T (Task 任务)**: 你被赋予的具体目标/职责
- **A (Action 行动)**: 你具体做了什么(技术方法/流程设计/协作方式)
- **R (Result 结果)**: 可量化的成果(数字/百分比/规模);无数字则标注 ⚠️ 缺数字

技能关键词:[从该段经历提取的技能词,用于硬技能匹配]

拆解后写入 <work_dir>/.work/resume.star.md,同时更新 <work_dir>/.work/resume.md.hash

第 2 步:逐条 JD 分析

记录待分析总数 total = len(jd_ids),计数器 n = 0

jd_ids 中每个 JD ID(记为 <id>):

缓存检查:读取 <work_dir>/.work/jd-pool/<id>.analysis.md(若存在),校验:

  • frontmatter 中 jd_fetched_at 与 JD 文件的 fetched_at 一致
  • resume_hash 与当前 resume.md.hash 一致

两项均满足 → 跳过,复用缓存,n++,输出:⚡ <公司名>·<职位名> — 复用缓存(<n>/<total>),继续下一条。

否则 → 重新分析:

2.1 读取 JD

读取 <work_dir>/.work/jd-pool/<id>.md 全文。

2.2 计算 4 维匹配度(0-100 分)

维度 1:硬技能匹配(hard_skills)

从 JD「任职要求」提取所有技能/工具关键词。与 resume.star.md 中所有段落的「技能关键词」对比。

评分规则:

  • JD 要求的技能中,简历命中率 × 100 = 基础分
  • JD 中标注为「加分项」的技能,命中每项 +5(不超过 100)
  • 简历有但 JD 没要求的技能不加分

记录:

✅ 命中:[技能列表]
⚠️ 缺失(JD 强调):[技能列表]
🎯 已有但未突出(JD 提及):[技能列表]

维度 2:经验深度(experience_depth)

对比 JD 要求年限 vs 简历实际年限:

  • 差距 ±1 年内:90-100 分
  • 简历比要求多 1-3 年:85-95 分
  • 简历比要求少 1 年:70-80 分
  • 简历比要求少 2 年:50-65 分
  • 差距超过 2 年:30-50 分

同时考察项目复杂度:相近 +5,明显低于 -10。

维度 3:行业/领域契合(domain_fit)

对比 JD 行业 + 业务场景 vs 简历工作行业 + 项目背景:

  • 完全匹配(同行业同场景):90-100
  • 行业相近(如同属 B 端 SaaS):75-90
  • 行业不同但技能可迁移:60-75
  • 行业差异大,迁移难度高:40-60
  • 几乎无关联:20-40

维度 4:软性匹配(soft_fit)

从 JD 提取软性要求(如「优秀的沟通能力」「有 0-1 经验」「能独立推动跨团队项目」),从简历找对应具体事例。

评分(从 0 分开始累加):

  • JD 强调的软技能在简历中有具体事例支撑:每项 +15(上限 100)
  • JD 提到的加分项(学历/证书/特定背景)命中:+5 每项
  • 钳制在 0-100 范围内

2.3 计算总分

scores.total = round((hard_skills + experience_depth + domain_fit + soft_fit) / 4)

2.4 写入 analysis 文件

写入 <work_dir>/.work/jd-pool/<id>.analysis.md

markdown
---
jd_id: <id>
analyzed_at: <ISO 8601 时间>
jd_fetched_at: <从 JD 文件 frontmatter 读取的 fetched_at>
resume_hash: <当前 resume.md.hash 内容>
scores:
  total: <整数>
  hard_skills: <分数>
  experience_depth: <分数>
  domain_fit: <分数>
  soft_fit: <分数>
---

## 一句话评估
<30 字以内,说明核心优势、主要差距、是否值得投递>

## 维度分析

### 硬技能 <分数>/100
✅ 命中:<技能列表>
⚠️ 缺失(JD 强调):<技能列表>
🎯 已有但未突出:<技能列表>

### 经验深度 <分数>/100
<1-2 句说明差距原因>

### 行业契合 <分数>/100
<1-2 句说明行业相关性>

### 软性匹配 <分数>/100
<列出 JD 软性要求 vs 简历是否有具体事例>

同时更新 JD 文件 frontmatter 中的 status.analyzed: true

n++,将 <id> 加入 state.jsonstages.analyzed,更新 checkpoint_at

输出进度✅ <company.name>·<title> — 匹配度 <scores.total> 分(<n>/<total> 完成)

若单条 JD 分析出现异常(文件读取失败、字段缺失等),将该 ID 加入 state.stages.analysis_errors,记录失败原因,继续处理其余 JD,不整体中止。

第 3 步:完成

所有 JD 处理完成后,将 state.jsonphase 设为 "analyzed"

⚠️ 完成后严禁输出任何文字。 所有统计数据(新分析数量、缓存复用数量、失败列表)已写入 state.json,调用方(主 skill)自行从 state.json 读取,无需任何文字汇报。直接结束,不输出任何内容。