# Job Hunt Analyzer

> Internal sub-skill for job-hunt suite. Performs STAR decomposition of resume and scores JD-resume match across 4 dimensions. Does NOT generate tailoring suggestions (handled by tailor). Do NOT invoke directly — use the job-hunt main skill instead.

- Skill: `jpcwhj/job-hunt-analyzer` (Agent Skill)
- Install (CLI): `npx skillmds@latest add jpcwhj/job-hunt-analyzer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jpcwhj/job-hunt-analyzer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: jpcwhj (https://skillmd.com/u/jpcwhj)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/jpcwhj/job-hunt-analyzer

---


# 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.json` 的 `stages.analyzed`，更新 `checkpoint_at`。

**输出进度**：`✅ <company.name>·<title> — 匹配度 <scores.total> 分（<n>/<total> 完成）`

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

## 第 3 步：完成

所有 JD 处理完成后，将 `state.json` 的 `phase` 设为 `"analyzed"`。

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

