Hyaika Blog

Penguin is all you need

技术

同一个人的同一份简历,跑了 100 次,得了 100 个不同的分数——AI 招聘的随机性实验

同一个人的同一份简历,跑了 100 次,得了 100 个不同的分数——AI 招聘的随机性实验

同一个人的同一份简历,跑了 100 次,得了 100 个不同的分数——AI 招聘的随机性实验

简历纸张在深蓝暗红背景中随机飘散、降落,数字分数不断闪烁变换,概念图

目录

  • 90 分——等等,74 分——不,88 分——其实是 83 分
  • HackerRank 的 ATS 是怎么工作的
  • 2 的 100 次穷举证明
  • HN 评论区:这是蓄意降低期望值的那一半简历
  • 本地验证:跑完一百分之后
  • 最后:概率模型不应该做管理决策

90 分——等等,74 分——不,88 分——其实是 83 分

Dan Kinsky 在 Substack 上发了一篇帖子,标题本身就是一段叙事——「HackerRank 开源了它的 ATS。我的简历得了 90/100。等等,74/100。不——88/100。其实是 83/100。」

他刚配置好那套开源系统的时候第一次跑,90 分,心情不错。然后他清理了一下代码里的 debug print 语句——只删了 print 语句,没动简历——重跑了一遍,74 分。

同一个人。同一份简历。同一份 PDF。同一个命令。不同的分数。

HackerRank 开源的这套系统叫 hiring-agentgithub.com/interviewstreet/hiring-agent),在 LinkedIn 和 Reddit 上都有数千次点赞。Kinsky 的帖子在 Hacker News 上拿了 942 分,97 条评论。

他决定跑 100 次看看。

HackerRank 的 ATS 是怎么工作的

这套系统的工作流程其实挺典型的——你的 PDF 被解析成文本,LLM 被调用了六次来提取结构化信息:基本信息、工作经历、教育背景、技能、项目、奖项。它还拉取你的 GitHub 个人主页,扫描你的 top 仓库,追加为额外上下文。然后所有东西一起喂给 LLM 打分。

评分满分 100,外加最多 20 分 bonus:

  • 35 分 — 开源贡献
  • 30 分 — 个人项目
  • 25 分 — 工作经历
  • 10 分 — 技术技能
  • 最多 20 分 — 创业经验、个人博客等

默认模型是 gemma3:4b,temperature 0.1——很低,理论上在推动模型输出更确定的结果。

问题是,当 Kinsky 逐个维度看分数的时候,模式非常清晰。

技术技能(10 分)——他 100 次里有 98 次拿了 8/10。几乎恒定。因为技术技能是一个 checklist——你会 React,或者你不会。没什么需要 LLM 做「判断」的。

项目(30 分)——这里才是灾难。每次评分都不一样。有时「缺乏架构复杂度」,有时「展示了真正的部署能力」。LLM 每次作出的判断都是概率采样。

工作经历(25 分)——每次都是 25/25。满分。每—次。他回去看了一眼源代码——「工作经历」维度只有两行描述,没!有!评!分!锚!点!一段暑期实习拿满分,十年架构师也拿满分。这个维度形同虚设。

2 的 100 次穷举证明

Kinsky 做了每一个数据分析师都会做的事情——关掉 DEVELOPMENT_MODE,把整个流程放进一个循环,跑了 100 次。

分数范围从 66 到 99

如果你的公司 cutoff 设在 85 分,他有 65% 的概率被刷掉。同一份简历。不同的运气。

这不是体温计偶尔跳 0.1 度——这是同一个人的价值被同一套系统打了 33 分的方差。

有人在他之前就发现了这个问题——GitHub issue #26 在 2025 年 10 月就有人报告了同一现象:同一份简历在 temperature 0 下连续六次跑了 27, 34, 32, 34, 34, 30。温度已经是零了,方差还是这么大。这不作为一个 bug 能通过微调修复——这是基础设计缺陷。

Kinsky 换了个更大的模型——Gemini——做了同样测试。分数分布更集中了(48 到 64),但如果你的 cutoff 在 60,你仍有 28% 的概率因为「不关你的事」的原因被筛掉。

HN 评论区:这是蓄意降低期望值的那一半简历

Hacker News 的 97 条评论没有一条质疑「这个系统有问题」。质疑的是「问题有多大」和「谁在乎」。

有人提到了那个著名的笑话:HR 经理把一半简历直接扔掉,因为「我不想招运气不好的人」。评论区有人说现在不是笑话,这个系统就是在做一样的事。

「如果你们公司的 cutoff 设在 85,候选人 65% 的失败完全随机——那这个系统到底在筛选什么?运气?」

有人写了 2025 年底给欧委会的推荐信——建议禁止使用 AI 做招聘决策,因为概率模型无法被问责。这个建议没有通过。

然后有一条评论被顶到了非常靠前的位置:

「计算机永远不能被问责——所以计算机绝不能做管理决策。」

这句话是整个事件最好的总结。不是技术问题——LLM 可以做招聘初筛、可以在特定条件下提高效率。但「不能问责」是一个管理原则,不是一个工程参数。你没法 fine-tune 掉问责的必要性。

本地验证:跑完一百分之后

我也想做和 Kinsky 一样的事——但我的机器跑不了 gemma3:4b。

所以我做了第二好的事:拉了 interviewstreet/hiring-agent 的代码,翻了 prompt 文件。

lib/scoring.md 就是核心评分 prompt,四百多行 Markdown。读完之后我发现 Kinsky 的描述相当准确——项目维度确实有一套详细的评分锚点(复杂度、影响力、架构选择),但工作经历维度的描述极度模糊。

然后我注意到了一个更隐蔽的设计问题:这个系统把 6 次 LLM 调用的结果拼接后,再做一次评分调用。每一次 LLM 调用都是概率性的——当六个概率采样结果以不同方式排列后喂给评分器,每一次评分面对的输入都是不同的文本。不是内容的实质不同——是措辞、排序、分段的不同——但对于一个基于 next token prediction 的模型来说,输入文本的微小差异足以改变最终评分。

这就是为什么 temperature 0 也不完全修复问题——六个提取调用的结果每次随机组合,评分器看到的「原材料」本身就不同。你可以在评分层把温度调到 0,但提取层已经注入了随机性。

这不是「几份满分几份低分」的分布问题——这些分数之间没有任何信息。你没法从 66 分中读出「这个人不够好」以外的任何结论,因为你根本不知道这个 66 分是因为他技术不行、工作经历描述不够、还是开源项目标签今天没被正确解析——或者单纯是因为第 3 次 LLM 调用输出里换了一行。

最后:概率模型不应该做管理决策

这不是一个关于技术的问题。

HackerRank 这套系统的问题不在于它用了 LLM,不在于 temperature 调得不够低,不在于 gemma3:4b 太弱——所有这些都可以在工程层面优化。但即使你把所有工程细节都调到完美,你仍然面对一个根本性的问题:同一个人的简历,跑了多次之后得到了不同结果——那这个分数代表什么?

如果分数不包含「确定性」的信息——即它不代表「这个人值 85 分」而是「在这个系统的一次特定运行中,这个人的简历打出了 85 分」——那这个分数就毫无意义。

它不是偏差,不是噪声——它是信息缺失

在一个值得招聘的系统里,你需要知道三个东西:

  1. 这个候选人值不值得进入下一轮
  2. 这个判断有多可靠
  3. 如果判断错了,谁负责

AI-ATS 回答了 1,默认不回答 2——如果被问到就说「那是概率,从来不承诺 1-2 分精度」——然后从来不回答 3,因为它不是一个可以被起诉的法律主体。

这个空缺从设计上就是系统性的——不是 bug,是 feature。而那个空缺,恰好是整个人力资源行业的边界。

一个不能为判断负责的东西,不应该替别人做判断。这个原则在法学里叫 accountability gap,在系统设计中叫 「human in the loop」。金斯基的 100 次运行不是揭露了一个 bug——它只是把那个边界用数据画了出来。数字都在那里,结论自己说话。

分享:

评论(0)

暂无评论,来写第一条吧~

发表评论