| name | pxb-liepin |
| description | Pixboom 招聘搜人筛人作业流程(猎聘 liepin-cli),为任一岗位搜候选人、筛简历、提报、 维护候选人池/去重台账/JD 记录。当用户说"搜人""下一轮""继续搜""筛简历""提报候选人" "开简历给我看""出 PDF""更新候选人池",或要为某岗找人/筛人时使用。岗位标准看该岗 JD,本流程岗位中立。 |
Pixboom 搜人筛人作业流程
⚠️ 改本 Skill 前先想:这里只放泛用作业流程(所有岗通用、可复用)。单一案例/某轮/某岗的标准经验 → 进该岗 JD.md,不进这里。
每岗:JD.md(对外JD + 内部备注表,判断只看它)· 去重台账.csv(resume_id,status,仅去重)· 候选人池.md(确认候选人)· 待定/(简历 PDF 中转)。
路径:命令里 <岗位>\… 等相对路径相对工作区根目录(本 CLAUDE.md 所在);脚本统一在 .claude/skills/pxb-liepin/scripts/(下文简写 SC)。机械活全在脚本里、跨 Win/mac;判断在本文+agent。
全流程:两层循环(主 agent 直接串行跑,不派 subagent)
- 主 agent 串行自跑、不派 subagent:单账号单锁串行,subagent 无并行收益、反而启动慢易卡死。
- 小循环(步骤 1-3,主 agent 自跑、不打扰用户):搜一页 → 粗筛挑 ~10 → 精筛 → 合适标
待提报 → 没攒够回步骤 1 再搜,连轮跑到攒够 ~5 个 待提报。绝不跑一轮就停等用户。
🔴 边跑边报,别闷头静默:每跑完一轮,先输出一行进度再继续下一轮,别一口气跑到底让用户 10-20 分钟看不到动静。"不打扰用户"指没攒够时别停下问用户拍板,不是全程不吭声;进度是单向心跳,不算打扰。
每轮播报格式:第N轮(词:X):搜A/精筛B/新增待提报C,累计待提报 D/目标 E,继续…(熔断/出批时另行说明)。带上本轮关键词,方便步骤 6 复盘哪个词有效。
- 大循环(步骤 4-6,用户校准 JD):一批出 PDF → 用户复核 → 入池 → 迭代回写 JD(重点是进化下一轮关键词)→ 下一批。JD 越调越准、小循环越搜越准。
- 上下文:脚本只输出窄表(非原始 JSON)。看完窄表做完判断后,记住结论即可(待提报的
id=标签、方向感、哪个词有效),不必把整页窄表一直留在上下文;轮数多了丢掉旧轮明细。
P. 确认/补全 JD(搜之前最先做) → 0. 排队抢锁 → 0.5 登录(自己探,没登才引导扫码) → 1. 粗筛 → 2. 精筛 → 3. 够一批没(没够回 1)→ 4. 出 PDF 提醒 → 5. 入池 → 6. 迭代回 0。
全程红线:① 单账号串行,绝不并发调 liepin ② 反爬宁慢勿封:脚本非零退出即停、别密集连跑(脚本内已带抖动)③ 原始 JSON 不进上下文(脚本只输出窄表)④ 隐私:简历只存本地、不外发、不传外部服务 ⑤ 只 search/resume,不 greet(沟通归 HR)⑥ 无头硬执行 + 脚本独占:所有 liepin 访问只走脚本(search.mjs/fetch.mjs/pdf.mjs,已内置强制无头)——除用户手动 liepin login 外,绝不直接敲 liepin search/resume。裸调用在 npm 发布版默认有头会弹窗(new CdpBrowser() 不传参,只看 config 默认)。过程中绝不该弹出任何浏览器窗口;一旦看到浏览器弹窗又关闭=有人裸调了 liepin、或没先登录,立即停手排查,别继续刷(可选:在该机器跑一次 patch-headless.mjs 把发布版默认也改成无头,当安全网)。
所有脚本无参运行会打印用法;任一脚本退出码 ≠ 0 = 停手,按其报错处置(多半反爬/被踢/未登录)。
P. 开搜前:把 JD + 人员画像聊全(搜之前最先做,主 agent+用户,不碰 liepin、不抢锁)
搜任何人之前,先把该岗的 JD + 人员画像补到能搜的状态——判断全程只看它,补不全 = 瞎搜、多轮返工(本流程返工几乎全因开搜前没聊清就动手)。在对话里完成,不动 liepin、不抢锁。
🟢 怎么聊(最重要):像个懂行的猎头跟用人方对齐需求,用人话把"要什么样的人、这种人在哪、什么样的看着像其实不是"聊明白。 下面的"硬约束 / 三锚 / 锚一二三"全是给你对照的内部清单,不是台词——别把这些词报给客户,别"锚一锚二锚三""硬约束剩余项"这样列条目念给他听。自然地问、一次一两点;你拿到的每样东西,本质都只是在补 JD 和人员画像这两件事。
① 补齐事实(填进 JD 硬约束行):预算 / 城市 / 经验 / 学历 / 年龄 / 目标人数。用户给了就填,缺的顺嘴问一句即可,别追问"预算够不够"——按预算搜,真枯竭(步骤 3)再谈预算。
② 聊出人员画像(别问"最看重什么能力/不要哪类人"这种抽象话——客户答不出、也喂不进搜索):
- 这种人在哪、叫什么 — JD 不写目标公司,得你来配:读
_共享\公司档案.md(行业/竞对/业务特点)× 这个岗的性质,网络检索 + 判断出"对标 / 竞品 / 上下游 / 相邻行业藏这类人的公司"分类清单,带职位名变体 + 锚点词,交用户勾选 / 砍(同公司不同岗清单不同)。落 JD「开搜前三锚」块 + 喂第一轮强搜索词。
- 标杆长什么样 — 用户心里有样板简历,就请他放
<岗位>\参考简历\(没有就建该文件夹),我真读这几份(不读=没意义),抽出正向画像 / 出身公司 / 技能锚点 → 落 JD 正向建议首行 + 补搜索词。没样板就靠上一条兜。
- 什么看着像、其实不是 — JD 只说谁合适、从不说谁不合适;自然问一句"有没有哪些行业 / 公司 / 岗位,乍看像这份 JD、其实不对路?"(走量客服像客服、器件方向像硬件、纯塑胶件像结构、Shopify 电商像独立站前端)→ 落 JD 负向建议首行 + 排除词。
用户当下答不全很正常(真实录取线常要看到拒绝才说清)→ 别硬逼,有样板就靠样板三角定位,答不出的那块标"第一轮校准时确认",照样能开搜。
intake 完成判据(逐项勾齐才回写 JD、进步骤 0 抢锁;别用"感觉够了"代替勾选):① 硬约束行填满 ② 目标公司清单已交用户确认 ③ 样板简历已读、或已标"无/欠" ④ 反向锚已问、或已标"欠" ⑤ 用户说"就按这个搜"。
- 快速通道:用户明说"立刻搜、先欠着" → 放行,但记一笔欠了哪块;欠 = 池子大概率搜歪、多花轮次,第一轮当校准用(出批后按反馈补,别假装第一轮就交终选)。
- 已有成熟 JD + 画像齐 + 用户明说直接搜 → 快速过一眼即可,别为流程而流程。
0. 排队 + 抢锁
搜人先往 _共享/搜索队列.md 追一行 待办。当 worker:抢锁 → 挑最早 待办 → 跑 → 标完成 → 解锁。
node SC/lock.mjs acquire <岗位>
node SC/lock.mjs renew <岗位>
node SC/lock.mjs release
- 单账号单锁:同一时刻只一个对话/进程持锁跑 liepin,多岗/多线只能排队(账号物理唯一,与是否用 subagent 无关)。
- 锁的生命周期 = 一"批" = 一次持锁:
acquire(本批第一轮前)→ 每轮 renew → 步骤 4 出 PDF 交用户复核时 release(复核是纯等待、不碰 liepin,把账号让给别的岗)→ 用户复核完、回来搜下一批时再 acquire。别一把锁从头持到尾(会把同时在招的别的岗饿死整段复核时间),也别每轮 acquire/release(和排队逻辑打架)。
- 多岗位同招:各岗在
_共享/搜索队列.md 排队;靠"批次边界释放锁"自然交错——A 岗出批给用户复核时让出账号,B 岗就能搜它那批。
0.5 登录:自己探,别问用户登没登
开搜不问用户"这台机器登录过吗"——直接拿第一轮 search 当探针:search.mjs 强制无头、不弹窗,跑得通=已登录,直接连着往下跑;只有脚本报未登录才去登录。
开搜前一次性告诉用户预期:「开始搜了,每轮大概 10–20 分钟,慢是为了悠着点别被网站封,我每轮报你一句,凑够一批叫你看。」别让用户干等以为卡死。
1. 粗筛(脚本自动登 CSV)
node SC/search.mjs "<岗位>\去重台账.csv" "关键词" --city 深圳 --limit 40
脚本一步做完:search → 去掉台账已召回的 → 新人登记 未精筛 → 打印窄表(id/姓名/现职/公司/年限/薪资/学历)。登 CSV 是查重命根,脚本已强制做。
- 卡住保护:search 内置 6 分钟硬超时(resume 2.5 分钟),liepin 卡死(撞反爬/滑块/未登录/Chrome 卡住)会强杀并报错,不会静默挂死。一旦报超时:告诉用户"搜索卡住已中断",关掉残留 Chrome、确认已登录、过几分钟再试或把
--limit 临时调小,别立刻重刷(越刷越被反爬盯上)。
卡片有 现职/公司/年限/期望薪资/学历/年龄/期望职位,判不了能力(实做/真伪/方向细节要精筛),粗筛只做三件:① 卡面就能判死的(硬约束出局:城市/期望薪资/年限/学历/年龄;期望职位明显转行、偏离本岗方向;+ 卡面可见的通用排除,见步骤 2)→ 标 粗筛不合适;② 按 JD 正/负向挑 ~10 个最对口进精筛(别只挑 5、也别宽到 20+);③ 其余卡面过得去 / 拿不准的留 未精筛——这是干净库存:召回变稀时直接挑 未精筛 再拉精筛,不重搜。
粗筛不合适 只给卡片一眼就否的;拿不准 = 留 未精筛,别误标(库存要保干净,误标会把好货埋了)。卡面否的落库:
node SC/dedup.mjs set "<岗位>\去重台账.csv" 粗筛不合适 <卡面否的id...>
--limit 40 起步(自动翻页,别 --page):漏斗要宽,召回 ~40-50 里才挑得出 ~10(约 4-5:1)。别为了快降到 20——那样挑 10 几乎没筛。只有反复卡死时才临时调小排查,排查完放回。健康比 未精筛:精筛 ≈ 4:1,随时 node SC/dedup.mjs stats "<岗位>\去重台账.csv" 自查。
2. 精筛(批量取、按 JD 下判决)
拉这页挑出的 ~10 份,一个循环拉完 = 1 个回合,别开一份判一份:
node SC/fetch.mjs <id1> <id2> ...
每份过三关(对照该岗 JD):
- 硬约束 & 去向:硬约束(城市/期望薪资/年限/学历/年龄/期望职位)粗筛卡片已初筛;精筛复核
want_city——期望城市不在本岗城市 = 想迁走,慎留。(want_salary 仍带回,供关 3 判薪资-成色错配。)
- 正/负向建议:命中正向画像几条?命中负向排除信号 → 砍。
- 真伪:实做主看
work_history 每段的职责(已补丁,每段时间线下带 duty=那家公司实际做了啥)——这是判成色/方向的主料;self_descr(自述)作补充,详略不一、空泛堆形容词/技能名词的警惕注水。再叠:薪资-成色错配(带队多年要地板价=注水)、方向偏离 → 砍。work_history 段头(时长/公司)同时看稳定性(跳槽/空窗)。
通用排除(岗位中立,叠加在 JD 上,命中即砍):① 简历空洞、看不出实际职责产出(是空洞、不是写得短);② 频繁跳槽——多段 <1 年且无任何 ≥2 年稳定段;③ 在职 + 暂无跳槽打算(work_status 为"在职-暂不考虑/暂无跳槽打算"等)——统一砍:约不动、即便约到也议价难,性价比低;"离职找工作""在职-看机会"保留;④ 近一年无工作经历(最近一段 work_history 结束已超 1 年 / 空窗 >1 年)——直接砍。①卡片看不出留精筛、②卡片能初判的粗筛先排、③看 work_status(精筛见;卡片若显示在职状态可粗筛先排)、④看 work_history 末段结束时间(精筛见;卡片若显示离职已久可粗筛先排)。
归档:过三关、对口 → 待提报;真·边界且方向稀缺才 候补;其余 精筛不合适("够得着但不对"直接砍)。判完升级状态:
node SC/dedup.mjs set "<岗位>\去重台账.csv" 待提报 <过关id...>
node SC/dedup.mjs set "<岗位>\去重台账.csv" 候补 <边界id...>
node SC/dedup.mjs set "<岗位>\去重台账.csv" 精筛不合适 <淘汰id...>
3. 够一批没?
攒够 ~5 个 待提报(或到目标人数)没?
- 没够 → 回步骤 1 再搜下一页(别停问用户)。
- 够了 → 步骤 4。
- 方向熔断:本次循环已粗筛 ~100 人(≈2 页)却 0 个进
待提报 → 停循环、反馈用户:搜了 N 人 0 命中,把卡住的共性(都倒在哪关 / 哪类问题)说清楚,多半方向或 JD 标准有偏,等校准再搜。别闷头继续刷。
- 路径枯竭(召回越来越稀)→ 先扫
未精筛 库存(dedup.mjs seen 比对);仍无 → 停,报情况 + 换路径建议。
4. 出 PDF + 一次性提醒(不开网页)
这批 待提报 一次性出 PDF 到 待定/,对话提醒用户复核。默认不开 Chrome(占 profile 挡并行搜索)。
LIEPIN_PDF_DIR="<岗位>\待定" node SC/pdf.mjs "<id1>=张三-大疆" "<id2>=李四-影石"
node SC/lock.mjs release
告诉用户,并把每份 PDF 直接列成可点链接发在对话里——pdf.mjs 打印的「已存 …」就是各份路径,逐个做成 markdown 链接 [姓名·标签](<岗位>/待定/简历_<标签>.pdf)(href 用正斜杠),用户点一下就开,不必回文件夹翻;再问出"为什么"(合适/不合适各带理由——下一轮 JD 收敛的唯一燃料,不能只收"行/不行"):
「这批 N 份出好了,直接点开看:
- [张三 · 大疆](<岗位>/待定/简历_张三-大疆.pdf)
- [李四 · 影石](<岗位>/待定/简历_李四-影石.pdf)
逐个看完跟我说哪些合适、哪些不合适,各自为什么:对的对在哪(背景/公司/作品/某段经历)、不对的差在哪(方向偏/成色虚/硬约束)。说得越细,我下一轮越能搜对路。」
- 用户只甩"这个行那个不行"没给理由时,追问为什么——步骤 6 的正/负向建议全靠它,缺了就是瞎搜。
- 只存本地、不外发;别只贴文字不出 PDF;仅用户要"在线看原页"才临时开 Chrome(看完关掉再跑 liepin)。
待定/ 留删:入选的 PDF 留下(候选人池直链,是成品);落选/候补的拍板后删;下批出新 PDF 前清掉上批未入选的。
5. 入池
用户复核拍板后:
- 合适 →
候选人池.md 加一行(姓名·现职·经验·薪资·学历·一句判断 + 两列链接 [PDF](待定/简历_<标签>.pdf)、[猎聘](https://lpt.liepin.com/cvview/showresumedetail?resIdEncode=<id>)),dedup.mjs set ... 入选,PDF 留 待定/。
- 不合适 →
dedup.mjs set ... 精筛不合适、删 PDF;留候补标 候补。
6. 迭代:进化下一轮的搜索关键词(本流程成败在此)
核心认知:每轮真正改变候选池的只有"搜索关键词"。 关键词决定"捞来谁"(池子),正/负向建议只决定"怎么筛"(过滤)。池子捞错了,再严的筛也救不回来。 所以别"随便换个词、再用更严的标准卡一轮"——要让上一轮的结果告诉你下一轮搜什么:把搜索词当假设、把结果当数据来修正。
A. 关键词进化的发动机:扒「入选」简历,反推下一轮的词。 逐个打开本批入选简历(必须真读、不能拍脑袋),从他们身上抽出真实可搜的词:
- 职位名变体 ← 他们简历上自称什么?同一岗常有多种叫法(动效设计 / 交互动效 / motion designer / UI动效 / H5动效)——都拿来当下一轮的并列(OR)词。
- 出身公司 + 当时岗位 ← 入选的人来自哪些公司、在那家做的什么?某段经历特别对口,往往是那家公司 + 当时那个岗位做的事正好契合 → 开一条「目标公司」轴,先顺藤摸瓜搜同公司、同岗位的其他人(最快找到类似合适的),再扩到其对标 / 竞品 / 上下游。
- 技术/工具/项目名词 ← 反复出现的工具(AE / Lottie / Figma…)、项目或产品词,都是锚点词。
B. 诊断本轮每个关键词,决定怎么调(一次只动一个轴,才看得出是哪步起效):
| 本轮表现 | 诊断 | 怎么调 |
|---|
| 召回多但大多不对口 | 太宽/有歧义 | 收紧:加硬约束、换更具体职位变体、加排除词 |
| 召回太少 / 快枯竭 | 太窄 | 放宽:同义词/近义词、职位变体(品牌↔市场、外贸↔贸易),或扩邻近行业(医美→生物科技/个护) |
| 连 ≥2 轮净入池 = 0 | 该词判死 | 移进弱搜索词弃用,换锚点 |
- 关键词轴轮换:① 职位名+变体/同义词 ② 目标公司(对标/竞品/上下游)③ 技术/工具名词 ④ 项目/产品名词 ⑤ 邻近行业(本行枯竭时)。
C. 追加一行到 JD 内部备注表(别改旧行,一轮一行):
- 强搜索词 ← 本轮有效词 + A 步从入选简历新抽出的词(职位变体/目标公司/锚点词)。
- 弱搜索词 ← 本轮无效/太宽/枯竭的词,写清为什么废,别下轮再踩。
- 正向建议 ← 用户说的"为什么合适" + 你真读入选简历的交叉印证(画像/背景/公司/技能锚点),落成下批筛人要找的信号。
- 负向建议 ← 用户说的"为什么不合适",归纳成排除信号(方向偏/成色虚/某类背景)。
- 每格要点即可,别散文、别重抄硬约束。
⚠️ 锁:步骤 4 已 release。下面 D(复判)和 E(新搜)要再调 liepin——动手前先 node SC/lock.mjs acquire <岗位> 重新占锁(占不到=别的岗在搜,排队)。
D. 回扫错杀(本轮标准/方向有调整时必做——否则越搜越少): 标准是动态的,上几轮按旧标准砍掉的人,换新标准可能是错杀。回去新搜之前,先按新正/负向建议复判已召回的库存,别只顾往前找新词:
node SC/dedup.mjs list "<岗位>\去重台账.csv" 候补 → 先复判候补(本就是边界,最易翻案)。
node SC/dedup.mjs list "<岗位>\去重台账.csv" 未精筛 → 库存里没细看过的,直接精筛(本就是该挖的库存)。
- 标准明显变向时(某硬约束放宽 / 新增了正向信号)→
node SC/dedup.mjs list "<岗位>\去重台账.csv" 精筛不合适 取近几轮的,挑可能受这次变化影响的重新 fetch.mjs + 复判。注意这要重拉简历、耗 liepin 调用,只挑相关的、别全表重刷。
- 复判翻案的 →
dedup.mjs set ... 待提报,并入本批。
错杀回收常比新搜更快补人,尤其方向一调。"越搜越少"多半就是只往前搜、不回头捡。
E. 用进化后的关键词回步骤 0 继续,到满额收尾。
收尾自检:召回全员登 CSV 了(脚本已保证)?待提报 都归档了?未精筛:精筛 还 ~4:1(dedup.mjs stats)?入选进候选人池了?JD 表追加本批行了(强搜索词含从入选简历新抽的词、正向建议含真读印证)?lock.mjs release 了?
脚本清单(SC = .claude/skills/pxb-liepin/scripts/)
| 脚本 | 用法 | 干什么 |
|---|
lock.mjs | acquire|renew|release <岗位> | 单账号搜索锁,30 分钟过期,退出码表态 |
search.mjs | <csv> "<词>" [--city --limit --experience --salary --degree] | 搜+去重+登记未精筛+打窄表 |
fetch.mjs | <id...> | 批量拉简历窄字段,内置反爬抖动 |
dedup.mjs | seen|add|set|list|stats <csv> [状态] [id...] | 台账查重/改状态/按状态列 id(回扫错杀)/比例自查 |
pdf.mjs | <id=标签...>(配 LIEPIN_PDF_DIR) | 整页存 PDF;npm root -g 动态定位 liepin-cli |
patch-headless.mjs | (装完跑一次,可选) | 把发布版 liepin-cli 默认改无头,免疫裸调用弹窗;幂等 |
patch-resume.mjs | (装完跑一次,需要) | 让 resume 把每段 duty(逐段职责)吐进 work_history——精筛主料,不打就只剩时间线;幂等。上游修复发布后可弃用 |
liepin 命令本身细节见同目录 liepin-cli skill。环境/安装见仓库根 README.md。