起因:关键词匹配根本不懂我
像很多人一样,我在 LinkedIn、各种招聘网站上设过岗位提醒。结果就是每天收到一堆噪音——它们只会匹配关键词。
我搜 “backend”,它给我推一堆我根本不会去的岗位;我做 web3,它分不清”区块链工程师”和”区块链销售”;同一个岗位在三个城市发了三遍,它推我三次。
问题的根源很简单:这些提醒系统没读过我的简历,它们只是在做字符串匹配。
而 2026 年,让一个 LLM 读完我的简历、再读完一份 JD、然后判断”这俩到底配不配、为什么”——这件事已经便宜到可以每天跑几百次。
于是我用业余时间写了个自用的小工具:job-radar。
一句话:自己跑的找工作引擎。抓取公开岗位 → 硬过滤 → 让读过你简历的 LLM 打分 → 去重 → 每天邮件推送一份干净的清单。
这篇记录一下它的设计思路和踩坑,给想做类似自用工具的人参考。先说清楚:它还很糙,主要是给我自己用的,后面会持续迭代。
整体流水线
核心就是一条管道:
collect (15+ 来源) → hard filter → LLM 打分(带上你的简历)→ dedup → email digest
每一步都可以单独跑、单独调。设计上我刻意让它像 Unix 管道一样可组合,而不是一个大黑盒。
job_radar/
├── sources/ # 每个招聘源一个适配器
├── pipeline/ # hard_filter → embed_recall → llm_scorer → dedupe
├── channels/ # email(resend / smtp)、digest 渲染
├── eval/ # 打标 + 准确率统计
├── cli.py # typer CLI
└── config.py # .env + profile.yaml 加载
几个我觉得值得说的设计取舍
1. 为什么用 LLM 打分,而不是关键词
这是整个工具存在的理由。
关键词匹配的天花板就是”字面命中”。但找工作的真实判断是模糊的——一个写着 “Platform Engineer” 的岗位可能比 “Backend Engineer” 更适合我,光看标题永远判断不出来。
job-radar 的做法是:把 JD 全文 + 我的简历一起喂给 LLM,让它从 4 个维度打分,并给出理由和风险,还是中英双语的。这样我看到的不是”匹配度 85%“这种没意义的数字,而是”为什么这个岗位值得你花时间、以及它可能有什么坑”。
判断力外包给模型,但判断的依据(我的简历、我的偏好)始终是我自己的。
2. 为什么本地优先
简历、个人配置、抓来的数据、各种 key——全部留在本地(~/.job-radar/ 下,都 gitignore 了)。
工具除了访问招聘源、你自己选的 LLM 端点、你的邮件服务商,不做任何其他外联。
原因很直接:简历是很私密的东西,我不想把它传给任何一个我不能控制的第三方服务。自己跑的工具,数据就该待在自己机器上。这也是我倾向于”自用工具”而不是”注册一个 SaaS”的核心理由。
3. 预算感知的 LLM 花费
LLM 打分是要花钱的。15+ 个来源每天抓下来几百个岗位,如果无脑全打分,账单会很难看。
所以加了:
- 每日花费上限——超了就停
- 优雅降级——预算用完后自动 fallback 到免费的启发式打分(基于规则,质量差点但不要钱)
- 打分前先用硬过滤(关键词、级别、地点、remote-only)砍掉大部分明显不合适的,只把”可能合适”的送去过 LLM
这套组合让日常成本压在可以忽略的水平。
4. 跨来源去重
同一个岗位经常在多个来源、多个城市重复出现。job-radar 会把它们折叠成一条,避免一份清单里同一个岗位出现五次。
5. 可以当 Claude Skill 用
这点是我自己用得最爽的。job-radar 带了一个 SKILL.md,可以装进 Claude Code / Claude Desktop / openclaw,让 AI agent 直接替我操作:
- “刷新一下我的求职雷达”
- “这个岗位为什么打分这么高?”
- “别再给我推 QA 的岗位了”
./install.sh # 软链进 ~/.claude/skills 和 ~/.openclaw/skills
从”我去跑一个 CLI”变成”我跟 agent 说句话”,这种体验上的差别比想象的大。
数据源
开箱带了 15+ 个来源,大致分几类:
- 官方 ATS API:Lever、Greenhouse、Ashby、Workable(预置了 80+ 家公司)
- 远程招聘板:RemoteOK、Remotive、WeWorkRemotely、Jobicy
- Crypto/Web3:dejob.ai、decentrajobs
- 其他:HN “Who is hiring?”、JSON-LD career 页面、LinkedIn(走 Gmail API)
加新来源的成本很低——写一个 fetch() -> Iterable[RawJob] 的适配器,在 registry 里注册一下就行。这是我刻意保留的扩展点,以后看到好的源随手就能接。
踩的坑
坑 1:招聘源的接口五花八门
官方 ATS(Lever、Greenhouse 这些)有规范的 JSON API,好接。但很多公司的招聘页是自己渲染的,只能退而求其次去解析页面里的 JSON-LD 结构化数据,命中率参差不齐。
教训:先把”好接的源”接满,覆盖度先上去,再去啃那些难啃的。不要一开始就跟最难的源死磕。
坑 2:LLM 打分的稳定性
同一个 JD,模型偶尔会给出波动的分数。解决办法是把打分维度拆细(4 个维度分别打),并要求它输出结构化理由——让模型”解释”会比让它直接”打分”稳定得多。
坑 3:邮件送达
一开始用 SMTP,在云服务器上经常被防火墙挡。后来主推 Resend(走 HTTPS),在云环境里稳定多了。SMTP 作为备选保留。
坑 4:怎么知道它到底准不准
这是最容易被忽略的一点。一个推荐系统,你得能衡量它好不好,否则调参就是瞎调。
所以加了 label 和 eval 两个命令:我可以交互式地给推荐结果打标(want / applied / maybe / reject / noise),然后 eval 会算出准确率和噪音率。有了这个反馈闭环,“调 prompt / 调过滤规则” 才有依据,而不是凭感觉。
现在的状态 & 接下来
老实说,它还很简单,很多地方糙。但已经在每天给我跑了,这就够了——自用工具的标准是”它解决了我的问题”,不是”它有多完备”。
接下来想做的:
- 把打标数据攒起来,做更个性化的打分(学习我的真实偏好)
- 加更多 web3 / 远程的优质源
- 可能把 digest 从邮件扩展到 Telegram
如果你也受够了招聘网站的噪音,仓库在这:github.com/survivorff/job-radar,MIT 协议,欢迎拿去改成你自己的。加数据源的 PR 尤其欢迎。
一点题外话
这个工具从想法到能用,大概花了我几个晚上——大部分代码是和 AI 协作写的。
这又一次印证了我之前那篇《AI 是工程师的杠杆》里的观点:以前”给自己写个趁手的小工具”这件事,启动成本高到很多想法最后都烂在脑子里;现在一个周末就能把想法跑通。
会用 AI 的工程师,最大的红利不是写大项目快了,而是那些”本来不值得做”的小工具,现在都值得做了。