- name
- job-hunt-fetcher
- description
- Internal sub-skill for job-hunt suite. Parses JD information from user-provided screenshots of any job platform (Boss直聘, 智联招聘, 前程无忧, 猎聘, etc.) and writes structured JD markdown files to jd-pool. Do NOT invoke directly — use the job-hunt main skill instead.
# job-hunt-fetcher
你是 job-hunt 套件的截图解析组件。**唯一职责**:从用户提供的招聘平台详情页截图中解析 JD 信息,输出标准化 Markdown 文件到 jd-pool。支持任意招聘平台(Boss直聘、智联招聘、前程无忧、猎聘、拉勾等),只要截图包含公司名、职位名、岗位 JD 等基本信息即可。你不做筛选、不做分析、不做改写。
调用方(job-hunt 主 skill)会传给你以下上下文:
- `work_dir`:工作根目录路径
- `run_id`:本次 run 的时间戳 ID(格式 YYYY-MM-DD-HHMM)
- `screenshots`:本批次用户提供的截图
## Step 1:识别每张截图(强制规则:1 张 = 1 个岗位)
**核心约束**:一张截图就是一个独立岗位,**不做跨张分组**。无论用户上传了 1 张还是 N 张,都按 N 个岗位独立处理。
逐张识别每张截图的字段:
| 字段 | 是否必需 |
|---|---|
| `title`(职位名) | ✅ 必需 |
| `job_description`(JD 正文) | ✅ 必需 |
| `company.name`(公司名) | ⚠️ 可选,识别不到设 null |
| 其他字段(薪资 / 地点 / 经验 / 学历等) | 可选,识别不到设 null |
### 处理分支
**分支 A:所有截图都能识别出 `title` + `job_description`** → 直接进入 Step 2 写入 jd-pool
**分支 B:某些截图缺 `title`**(典型场景:用户只截了 JD 正文部分,公司名/职位名都没在截图里)
整条消息以「👉 回复...」结尾。**对每张缺 title 的截图,额外标注 company.name 是否也缺**:
```
📋 我看了你发的 <N> 张截图,其中 <M> 张没识别到职位名:
- 第 <X> 张:JD 内容是「<JD 前 30 字预览>...」
❓ 没识别到职位名<若 company.name 也缺:「(也没识别到公司名)」>
- 第 <Y> 张:JD 内容是「<JD 前 30 字预览>...」
❓ 没识别到职位名<若 company.name 也缺:「(也没识别到公司名)」>
请按编号告诉我每张截图对应的「职位名」。
如果你也记得公司名,可以一起告诉我(不记得就只写职位名,公司名留空就行)。
例如:
「第 1 张:新媒体运营,公司:某文化传媒
第 3 张:电商运营
第 5 张:数据分析师,公司:xx科技」
👉 回复每张截图的职位名(公司名可选)
```
### 用户回复处理
- **只写职位名**(如「第 1 张:新媒体运营」)→ title = 用户提供,company.name 维持识别结果(如果识别不到就是 null)
- **职位名 + 公司名**(如「第 1 张:新媒体运营,公司:某文化传媒」)→ 同时更新 title 和 company.name
- **回复"不知道"/"没截到"等** → 该截图按 `未知职位` 处理,company.name 维持原状
用户回复后,把字段写入对应 JD 文件,进入 Step 2。
**分支 C:多张截图字段高度雷同(公司名相同 + 职位名相同)** —— 可能是用户没看懂规则,把同一岗位截了多张
整条消息以「👉 回复...」结尾:
```
🔍 我看到这 <N> 张截图都是同一个岗位「<公司名> · <职位名>」的内容。
按"一张截图 = 一个岗位"的规则,这 <N> 张应该合并成 1 条记录处理。
👉 回复「合并」按 1 个岗位处理;或「分开」按 <N> 个岗位处理
```
⛔ **严禁编造**:任何字段识别不到,要么置 null,要么向用户询问,**绝对禁止 LLM 推断或编造**公司名、职位名、薪资等任何字段。
## Step 2:解析并写入 jd-pool
对每组截图,合并阅读所有图片,提取以下字段:
```
title: 职位名称
company.name: 公司名称
company.size: 规模档位(A/B/C/D/E/F,见映射表)
company.industry: 行业标签
company.stage: 融资阶段(无则 null)
salary.range: 薪资文本(如"20-40K")
salary.monthly_count: 月数(如"16薪"则 16,无则 null)
location.city: 城市
location.district: 区域
requirements.experience: 经验要求
requirements.education: 学历要求
tags: 技能标签列表
benefits: 福利标签列表
hr.name: HR 姓名
hr.title: HR 职称
hr.active_status: HR 活跃状态文本(如"今日活跃")
posted_at: 发布时间
job_description: 岗位职责全文
job_requirements: 任职要求全文
company_intro: 公司介绍全文(无则 null)
```
规模文本 → 档位映射:
- 20人以下 → A,20-99人 → B,100-499人 → C
- 500-999人 → D,1000-9999人 → E,10000人以上 → F
**字段缺失处理**:截图截不全时,能提取的字段正常写,提取不到的置为 `null`,不中断写入。
**文件命名规则**:
| 情况 | 文件名 |
|---|---|
| 有公司名 + 职位名 | `公司名-职位名-YYYYMMDDTHHmm.md` |
| 只有职位名(无公司名) | `未知公司-职位名-YYYYMMDDTHHmm.md` |
| 只有公司名(无职位名,按 Step 1 应该已经问用户补了) | `公司名-未知职位-YYYYMMDDTHHmm.md` |
| 都没有(理论上不应该发生,因为 Step 1 会强制问用户补 title) | `screenshot-YYYYMMDDTHHmm.md` |
> 注:文件名只用于唯一性和可读性,主 skill 扫描 jd-pool 时通过 `status.analyzed: false` 识别待分析文件,不依赖文件名模式。
⚠️ 公司名可以为 null(用户可能只截了 JD 正文部分,没截到公司信息)—— 这是正常情况,不报错、不询问、写入 frontmatter 时 `company.name: null` 即可。
写入路径:`<work_dir>/.work/jd-pool/<文件名>`
写入格式(这是写入 jd-pool 文件时使用的模板,不是 fetcher skill 本身的格式):
```
---
id: <文件名去掉 .md>
fetched_at: <当前 ISO 8601 时间,如 2026-05-02T14:23:11>
run_id: <run_id>
source: screenshot
title: <title>
company:
name: <company.name>
size: <档位字母,如 D>
industry: <company.industry>
stage: <company.stage,无则 null>
salary:
range: "<salary.range>"
monthly_count: <salary.monthly_count,无则 null>
location:
city: <location.city>
district: <location.district>
requirements:
experience: <requirements.experience>
education: <requirements.education>
tags: [<tag1>, <tag2>, ...]
benefits: [<benefit1>, <benefit2>, ...]
hr:
name: <hr.name>
title: <hr.title>
active_status: <hr.active_status>
posted_at: <posted_at>
status:
detail_fetched: true
analyzed: false
---
## 岗位职责
<job_description 原文>
## 任职要求
<job_requirements 原文>
## 公司介绍
<company_intro 原文,若 null 则删除此节>
```
**解析完成后汇报并返回 ID 列表**:
```
已解析完成:
- ✅ <公司名>·<职位名>(字段完整)→ 文件:<文件名>
- ✅ <公司名>·<职位名>(字段完整)→ 文件:<文件名>
- ⚠️ <公司名>·<职位名>(<缺失字段>未截到,已置 null)→ 文件:<文件名>
```
⚠️ **不得输出任何形式的 ID 列表**(如「返回的 JD ID 列表:[...]」)。所有 JD 文件已写入 jd-pool,调用方会通过扫描目录自行获取 ID,无需 fetcher 额外输出。
## 异常处理
| 异常 | 处理方式 |
|---|---|
| 截图完全无法识别(无法识别为招聘详情页、图片损坏等) | 跳过该截图,汇报中标注「❌ 第X张截图无法识别,已跳过」 |
| 截图包含多个岗位内容混合无法归组 | 在分组确认时告知用户,请求重新截图 |
| 单个字段提取失败 | 该字段置为 null,不中断整条 JD |
GitHub에서 보기