Skip to content
survivorff's blog
Go back

我用 AI 给自己写了个找工作雷达 job-radar

7 min read

起因:关键词匹配根本不懂我

像很多人一样,我在 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+ 个来源每天抓下来几百个岗位,如果无脑全打分,账单会很难看。

所以加了:

这套组合让日常成本压在可以忽略的水平。

4. 跨来源去重

同一个岗位经常在多个来源、多个城市重复出现。job-radar 会把它们折叠成一条,避免一份清单里同一个岗位出现五次。

5. 可以当 Claude Skill 用

这点是我自己用得最爽的。job-radar 带了一个 SKILL.md,可以装进 Claude Code / Claude Desktop / openclaw,让 AI agent 直接替我操作:

./install.sh   # 软链进 ~/.claude/skills 和 ~/.openclaw/skills

从”我去跑一个 CLI”变成”我跟 agent 说句话”,这种体验上的差别比想象的大。

数据源

开箱带了 15+ 个来源,大致分几类:

加新来源的成本很低——写一个 fetch() -> Iterable[RawJob] 的适配器,在 registry 里注册一下就行。这是我刻意保留的扩展点,以后看到好的源随手就能接。

踩的坑

坑 1:招聘源的接口五花八门

官方 ATS(Lever、Greenhouse 这些)有规范的 JSON API,好接。但很多公司的招聘页是自己渲染的,只能退而求其次去解析页面里的 JSON-LD 结构化数据,命中率参差不齐。

教训:先把”好接的源”接满,覆盖度先上去,再去啃那些难啃的。不要一开始就跟最难的源死磕。

坑 2:LLM 打分的稳定性

同一个 JD,模型偶尔会给出波动的分数。解决办法是把打分维度拆细(4 个维度分别打),并要求它输出结构化理由——让模型”解释”会比让它直接”打分”稳定得多

坑 3:邮件送达

一开始用 SMTP,在云服务器上经常被防火墙挡。后来主推 Resend(走 HTTPS),在云环境里稳定多了。SMTP 作为备选保留。

坑 4:怎么知道它到底准不准

这是最容易被忽略的一点。一个推荐系统,你得能衡量它好不好,否则调参就是瞎调。

所以加了 labeleval 两个命令:我可以交互式地给推荐结果打标(want / applied / maybe / reject / noise),然后 eval 会算出准确率和噪音率。有了这个反馈闭环,“调 prompt / 调过滤规则” 才有依据,而不是凭感觉。

现在的状态 & 接下来

老实说,它还很简单,很多地方糙。但已经在每天给我跑了,这就够了——自用工具的标准是”它解决了我的问题”,不是”它有多完备”

接下来想做的:

如果你也受够了招聘网站的噪音,仓库在这:github.com/survivorff/job-radar,MIT 协议,欢迎拿去改成你自己的。加数据源的 PR 尤其欢迎。


一点题外话

这个工具从想法到能用,大概花了我几个晚上——大部分代码是和 AI 协作写的。

这又一次印证了我之前那篇《AI 是工程师的杠杆》里的观点:以前”给自己写个趁手的小工具”这件事,启动成本高到很多想法最后都烂在脑子里;现在一个周末就能把想法跑通。

会用 AI 的工程师,最大的红利不是写大项目快了,而是那些”本来不值得做”的小工具,现在都值得做了。


更多 AI + 工程的实战,订阅 RSS关注 X


Share this post on:

Next Post
为什么 Hyperliquid 赢了链上 perp:一个交易所工程师的架构拆解

继续阅读

如果觉得有用

订阅更新,每次发新文章第一时间收到。不发广告、不搞推销。