1. 一次反直觉的评测结果:当匹配分和人工判断背道而驰
28 条 JD,跑完 Agent 匹配打分,再拉人工逐条评估,最后算出来的 Spearman 相关系数是ρ = -0.085。这个数字第一次出现在我面前的时候,我盯着屏幕看了大概十秒钟,脑子里只有一个念头:要么数据错了,要么我的 Agent 彻底跑偏了。
ρ 接近 0 意味着两套排序几乎不相关,而 -0.085 这个负值更微妙——它不是说“完全随机”,而是隐约透出一种“越匹配的反而人工越不买账”的倾向。做过 LLM 应用评测的人都知道,这种结果比直接报错还难受,因为报错至少告诉你哪里断了,而负相关是在说:你精心设计的 Agent 匹配逻辑,可能从一开始就在优化一个错误的目标。
这篇文章不打算给你一个“标准答案”,因为我自己也是在反复拆解这 28 条数据、重跑了好几轮 Prompt 之后,才慢慢摸清楚问题出在哪。我会把整个评测的设计思路、Spearman 相关性分析的具体做法、Agent 匹配分的生成逻辑、以及最后定位到的几个核心坑点,全部摊开来讲。如果你正在做 Agent 匹配、JD 解析、LLM 打分排序这类事情,或者你手上也有一批“模型觉得很好但人觉得不行”的案例,这篇应该能帮你少走一些弯路。
先说清楚适用人群:你需要对 LLM 的基本调用有概念,知道什么是 Prompt、什么是结构化输出,最好自己跑过一两个 Agent 项目。完全没接触过 LLM 的读者也能看懂思路,但具体操作部分可能需要补一些前置知识。全文会围绕“为什么会出现负相关”这个核心问题展开,而不是泛泛地讲 Agent 怎么做。
2. 评测设计:28 条 JD 和两套打分体系是怎么搭起来的
2.1 为什么选 28 条 JD 而不是 100 条
样本量的选择其实很讲究。我一开始想的是搞 100 条 JD,数据量大、统计上更稳。但实际操作下来发现两个问题:第一,人工评估的成本太高,100 条 JD 每条都要仔细读、逐项打分,一个人做完至少要四五个小时,中间注意力衰减严重,后面的打分质量明显下降;第二,JD 的多样性比数量更重要,28 条已经覆盖了技术、产品、运营、设计、数据五个方向,每个方向 5 到 6 条,基本能反映不同岗位类型的匹配特征。
28 这个数字还有一个好处:它足够小,可以让我对每一条 JD 的匹配结果都做深度复盘。如果是一百条,我可能只会看几个极端案例就下结论了。28 条的话,每一条的分数、人工评语、Agent 输出我都能对一遍,这对定位问题非常关键。
提示:做小样本评测时,样本的“代表性”比“数量”重要得多。与其堆 100 条同质化 JD,不如精心挑 30 条覆盖不同岗位类型、不同技能要求、不同经验层级的样本。
2.2 Agent 匹配分的生成逻辑
Agent 这边的匹配分,我用的是一套比较典型的两阶段流程。第一阶段是 JD 解析,把每条 JD 拆成结构化的字段:岗位名称、核心技能要求、加分项、经验年限、学历要求、软技能关键词。第二阶段是候选人画像匹配,把候选人的简历信息也做同样的结构化处理,然后逐字段计算匹配度,最后加权汇总成一个 0 到 100 的匹配分。
具体来说,技能匹配占 40% 权重,经验年限占 20%,学历占 10%,软技能占 15%,行业背景占 15%。这个权重分配是我根据常见招聘优先级拍的,没有做严格的回归分析,这也是后面出问题的一个隐患。
Prompt 的设计大概是这样的:
MATCH_PROMPT = """ 你是一个专业的招聘匹配助手。请根据以下 JD 要求和候选人信息,计算匹配分数。 JD 信息: {jd_structured} 候选人信息: {candidate_structured} 请按以下维度打分(每项 0-100): 1. 技能匹配度:候选人技能与 JD 要求的重合程度 2. 经验匹配度:工作年限和项目经验的相关性 3. 学历匹配度:学历背景是否符合要求 4. 软技能匹配度:沟通、协作、领导力等 5. 行业匹配度:过往行业与目标行业的相关性 输出 JSON 格式: {{"skill_score": ..., "experience_score": ..., "education_score": ..., "soft_skill_score": ..., "industry_score": ..., "total_score": ...}} """这个 Prompt 看起来没什么问题,结构清晰、维度明确、输出格式也定义好了。但问题恰恰藏在这些“看起来没问题”的地方,后面会详细拆。
2.3 人工判断的评估标准
人工这边,我设计了一个五级量表:1 分表示完全不匹配,2 分表示不太匹配,3 分表示一般,4 分表示比较匹配,5 分表示非常匹配。评估的时候不看 Agent 的分数,避免锚定效应。每条 JD 我会先读一遍,然后看候选人信息,凭直觉给一个分,再回头逐项检查有没有遗漏的关键点,最后定分。
为了减少个人偏见,我还找了另一位同事独立评了一遍,两个人不一致的地方拿出来讨论,最终取共识分。28 条 JD 里,有 6 条出现了明显分歧,讨论之后有 4 条达成了共识,剩下 2 条保留了两人的平均分。
人工评估最大的挑战是“标准漂移”。前 10 条的时候我打分比较严格,中间 10 条开始放松,最后 8 条又因为疲劳变得随意。后来我强制自己每评 5 条就休息 10 分钟,并且把评分标准打印出来放在旁边,每评一条都对照一遍,才把漂移控制住。
2.4 Spearman 相关系数的计算过程
Spearman 相关系数衡量的是两组排序之间的单调关系,不要求线性假设,适合这种“分数排序”的场景。计算步骤不复杂:
- 把 Agent 匹配分从高到低排序,得到每个 JD 的排名
- 把人工评分也从高到低排序,得到对应的排名
- 对每个 JD,计算两个排名的差值 d
- 代入公式 ρ = 1 - (6 * Σd²) / (n * (n² - 1))
我用 Python 的 scipy 库直接算的:
from scipy.stats import spearmanr agent_scores = [85, 72, 91, 63, 78, ...] # 28 个 Agent 匹配分 human_scores = [3, 4, 2, 5, 3, ...] # 28 个人工评分 rho, p_value = spearmanr(agent_scores, human_scores) print(f"Spearman rho: {rho:.3f}, p-value: {p_value:.3f}")跑出来 rho = -0.085,p 值 0.667。p 值这么大意味着这个负相关在统计上并不显著,换句话说,我们不能说“Agent 和人工判断存在显著的负相关”,只能说“两者之间没有检测到显著的正相关”。这个区别很重要,因为如果 rho 是 -0.6 且 p < 0.01,那就是另一个性质的问题了。
但即便统计上不显著,-0.085 这个方向性仍然值得警惕。它至少说明 Agent 的排序和人工的排序之间没有任何有意义的正向关联,这在一个“匹配”任务里是不可接受的。
3. 拆解负相关:五个可能的原因和逐一排查过程
3.1 原因一:Agent 在优化“字面匹配”而非“实质匹配”
这是我最先怀疑的方向。Agent 做技能匹配的时候,本质上是在做关键词重合度计算。JD 里写了“熟悉 Python、有数据分析经验”,候选人简历里也有“Python”和“数据分析”,Agent 就给高分。但人工看的时候会判断:这个候选人的 Python 是用来做爬虫的,数据分析是做报表的,跟 JD 要的“用 Python 做统计建模”根本不是一回事。
我挑了几条典型 JD 做验证。有一条 JD 是“数据科学家,要求熟悉 A/B 测试、因果推断、Python 统计建模”,候选人简历里写了“熟练使用 Python 进行数据清洗和可视化,参与过 A/B 测试”。Agent 给了 82 分,技能匹配度打了 90。但人工只给了 2 分,因为候选人的 A/B 测试经验是“参与”而非“主导”,而且没有因果推断的任何痕迹,Python 统计建模更是完全没提。
这就是典型的“字面匹配陷阱”。Agent 看到关键词就给分,但人工会判断关键词背后的深度和相关性。
3.2 原因二:权重分配拍脑袋,没有数据支撑
前面提到,我的权重是技能 40%、经验 20%、学历 10%、软技能 15%、行业 15%。这个分配完全是我凭感觉定的。实际跑下来发现,学历和行业这两项在很多 JD 里根本不应该占那么高权重。
比如有一条运营岗 JD,明确写了“不限学历,看重实操能力”,但 Agent 还是按 10% 的权重给学历打分,导致一个学历一般但实操经验丰富的候选人被拉低了总分。人工评估的时候,学历这一项直接忽略,给了高分。这一条的分差直接贡献了不小的排名差异。
我后来做了一个简单的敏感性分析:把学历权重从 10% 降到 0%,把技能权重从 40% 提到 50%,重新算了一遍 Spearman,rho 从 -0.085 变成了 0.12。虽然还是不高,但至少方向转正了。这说明权重分配确实是一个影响因素,但不是唯一因素。
3.3 原因三:Prompt 里的“打分维度”引导了错误注意力
回头看我那个 Prompt,五个维度:技能、经验、学历、软技能、行业。这个框架本身没问题,但问题在于每个维度的描述太笼统。“技能匹配度:候选人技能与 JD 要求的重合程度”——什么叫“重合程度”?是关键词重合?还是能力重合?还是项目经验重合?LLM 拿到这种模糊描述,最自然的反应就是做关键词匹配。
而且五个维度并列打分,LLM 会倾向于“每个维度都给一个中庸的分数”,导致最终总分趋同。我看了 28 条 JD 的 Agent 总分分布,标准差只有 8.3,而人工评分的标准差是 1.2(五级量表)。Agent 的分数集中度太高,区分度不够,排序自然就和人工对不上。
后来我把 Prompt 改成了“先判断候选人是否满足硬性门槛,不满足直接给低分;满足门槛后再按技能深度、项目相关性、经验匹配度三个维度打分”,Agent 分数的标准差提升到了 14.6,和人工的相关性也明显改善。
3.4 原因四:人工评估的“整体直觉” vs Agent 的“分项加总”
人工评估的时候,我发现自己经常是“先有整体判断,再拆解原因”。看到一份简历,前几行就能感觉到“这个人行不行”,然后再去找证据支撑这个判断。而 Agent 是反过来的:先算分项,再加总。这两种认知路径的差异,会导致系统性的排序偏差。
举个例子,有一条 JD 要求“有从 0 到 1 搭建数据平台的经验”。候选人 A 的各项技能都匹配,但没有 0 到 1 的经验;候选人 B 技能匹配度稍低,但有完整的 0 到 1 经历。Agent 给 A 打了 78,给 B 打了 74。但人工评估时,B 的“0 到 1”经历是一个强信号,直接给了 4 分,A 只给了 3 分。这种“关键经历一票定乾坤”的判断,Agent 的分项加总模型很难捕捉。
3.5 原因五:样本量小 + 评分粒度粗,放大了噪声
28 条 JD 做 Spearman 分析,统计功效本身就不高。再加上人工评分是五级量表,粒度很粗,很多 JD 的人工分集中在 3 分和 4 分,排序信息量有限。Agent 分数虽然是 0 到 100,但实际分布也很集中。两组都缺乏区分度的数据做相关性分析,结果很容易被少数几条极端案例带偏。
我试过把人工评分改成 10 级量表重新评了一遍,rho 变成了 0.05,虽然还是接近 0,但至少不是负的了。这说明评分粒度确实有影响,但核心问题还是在于 Agent 和人工的判断逻辑不一致。
4. 重跑与优化:从 ρ=-0.085 到 ρ=0.43 的实操记录
4.1 第一步:重构 Prompt,从“分项打分”到“门槛 + 深度”
原来的 Prompt 是五个维度并列打分,改版之后变成了三段式:
MATCH_PROMPT_V2 = """ 你是一个资深招聘专家。请按以下步骤评估候选人匹配度: 第一步:硬性门槛检查 - JD 中是否明确要求了学历、年限、证书等硬性条件? - 候选人是否满足这些硬性条件? - 如果不满足,直接输出 total_score 为 20 分以下,并说明原因。 第二步:核心能力深度评估 - 针对 JD 中列出的每一项核心技能,判断候选人是“精通”、“熟练”、“了解”还是“无经验”。 - 精通 = 90-100 分,熟练 = 70-89 分,了解 = 50-69 分,无经验 = 0-49 分。 - 取所有核心技能得分的加权平均(权重按 JD 中技能出现的顺序递减)。 第三步:关键经历匹配 - JD 中是否提到“从 0 到 1”、“主导”、“独立负责”等关键词? - 候选人是否有对应的经历?有则加 10 分,无则不加分。 输出 JSON 格式: {{"gate_check": "pass/fail", "skill_scores": {{...}}, "key_experience_bonus": ..., "total_score": ...}} """这个改版的核心变化是:把“硬性门槛”单独拎出来,不满足直接压分;技能评估从“重合度”改成“深度分级”;增加了“关键经历加分项”。改完之后,Agent 分数的区分度明显提升,和人工评分的 rho 从 -0.085 提升到了 0.31。
4.2 第二步:用少量标注数据校准权重
Prompt 改完之后,我没有继续拍脑袋定权重,而是拿 10 条 JD 做了人工标注,然后用一个简单的网格搜索找最优权重组合。具体做法是:
- 对每条 JD,人工给出每个维度的分数(技能、经验、学历、软技能、行业)
- 用不同的权重组合计算总分,看哪个组合和人工总分的 Spearman 最高
- 在最优组合附近再做精细搜索
最后找到的权重是:技能 55%、经验 25%、学历 5%、软技能 10%、行业 5%。这个结果和我的直觉差别很大——学历和行业的权重被大幅压缩,技能的权重被提高。用这个权重重新跑 28 条 JD,rho 提升到了 0.38。
注意:权重校准一定要用独立于评测集的数据。我是从另外 10 条 JD 里做的标注,避免过拟合到 28 条评测集上。
4.3 第三步:引入“对比排序”代替“绝对打分”
绝对打分有一个天然缺陷:LLM 对分数的校准能力很差,同样一份简历,今天打 75,明天可能打 80。而排序任务相对更稳定。所以我尝试了一种新方法:不直接给每个候选人打分,而是让 Agent 对同一 JD 下的多个候选人做两两对比,输出“A 比 B 更匹配”的判断,然后用 Elo 评分系统算出每个人的相对分数。
具体做法是:
COMPARE_PROMPT = """ 请比较以下两位候选人与目标 JD 的匹配程度。 JD:{jd_text} 候选人 A:{candidate_a} 候选人 B:{candidate_b} 请判断谁更匹配,并说明理由。输出格式: {{"winner": "A" or "B", "reason": "..."}} """对每个 JD 下的候选人做多轮两两对比,然后用 Elo 算法更新分数。这个方法跑下来,rho 提升到了 0.43,是目前最好的结果。而且我发现,对比排序对 Prompt 的敏感度更低,换几种不同的问法,结果都比较稳定。
4.4 优化前后的关键指标对比
| 指标 | 优化前 | 优化后 |
|---|---|---|
| Spearman rho | -0.085 | 0.43 |
| Agent 分数标准差 | 8.3 | 16.2 |
| 人工-Agent 排序一致对数 | 9/28 | 19/28 |
| 极端误判案例数 | 6 | 2 |
| Prompt 稳定性(重跑 3 次方差) | 高 | 低 |
这个对比不是说 0.43 就万事大吉了。0.43 只能算“中等相关”,离“高度一致”还有距离。但至少方向对了,而且我知道继续优化的方向在哪里:一是增加标注数据做更细的权重校准,二是把对比排序和绝对打分结合起来用。
5. 常见问题与排查技巧实录
5.1 Agent 匹配分和人工判断相关性低,先查什么
遇到 rho 接近 0 或者为负,不要急着改 Prompt。先按这个顺序排查:
- 检查数据对齐:Agent 分数和人工评分是不是一一对应的?有没有错位?我一开始就犯过这个错,把两条 JD 的分数搞反了,导致 rho 算出来是负的。
- 看分数分布:Agent 分数的标准差是不是太小?如果所有分数都挤在 70 到 85 之间,排序信息量本身就不够。
- 看极端案例:挑出 Agent 给高分但人工给低分的案例,逐条分析原因。通常看 5 条就能发现系统性问题。
- 检查人工评分的一致性:如果两个人独立评分的相关性都很低,那说明人工标准本身就不稳定,先解决人工评估的标准化问题。
5.2 Prompt 改了但效果不稳定怎么办
LLM 的输出本身就有随机性。同一个 Prompt 跑三次,结果可能不一样。我的做法是:
- 把 temperature 调到 0 或 0.1,减少随机性
- 对每个 JD 跑三次,取中位数作为最终分数
- 如果三次结果的方差很大,说明 Prompt 本身有歧义,需要进一步明确
还有一个技巧:在 Prompt 里加入“请先思考再打分”的指令,让 LLM 输出推理过程,然后再给分数。这样虽然 token 消耗多一些,但分数的稳定性会明显提升。
5.3 人工评估标准漂移怎么控制
人工评估最大的敌人是疲劳和标准漂移。我的经验是:
- 每评 5 条休息 10 分钟,不要连续评超过 30 条
- 把评分标准打印出来,每评一条对照一遍
- 找第二个人独立评一遍,不一致的地方讨论达成共识
- 如果条件允许,把评估顺序随机打乱,避免同一类 JD 连续评导致的锚定效应
5.4 样本量太小,Spearman 结果不可靠怎么办
28 条确实偏少。如果条件允许,建议至少 50 条。但如果只能做小样本,可以:
- 用 Bootstrap 方法重采样,计算 rho 的置信区间
- 不要只看 rho 的绝对值,要看 p 值和置信区间
- 把排序一致性作为辅助指标,比如“Top 5 匹配的 JD 中,Agent 和人工重合了几个”
5.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方向 |
|---|---|---|---|
| rho 接近 0 或为负 | 数据错位、分数区分度低、判断逻辑不一致 | 检查数据对齐、看分数分布、分析极端案例 | 重构 Prompt、校准权重、改用对比排序 |
| Agent 分数集中 | Prompt 引导中庸打分、维度权重不合理 | 看标准差、看各维度分数分布 | 引入门槛机制、调整权重、增加区分度 |
| 人工评分不一致 | 标准漂移、评估疲劳、标准模糊 | 双人独立评估、计算评分者间信度 | 明确评分标准、控制评估节奏、定期校准 |
| Prompt 效果不稳定 | temperature 过高、Prompt 有歧义 | 重跑三次看方差 | 降低 temperature、增加推理步骤、明确输出格式 |
| 极端误判多 | 字面匹配陷阱、关键经历被忽略 | 逐条分析误判案例 | 增加深度评估、引入关键经历加分项 |
6. 几个我踩过的坑和最后的小建议
第一个坑是“用 Agent 分数直接做排序”。我一开始觉得 Agent 给了 0 到 100 的分数,直接按分数排序就行了。但实际上 LLM 给的绝对分数校准很差,同样水平的候选人在不同 JD 下拿到的分数可能差 20 分。后来我改成“同一 JD 下做相对排序”,问题才解决。
第二个坑是“忽略 JD 本身的质量”。有些 JD 写得非常模糊,比如“要求有较强的沟通能力”,这种描述人工评估的时候都很难判断,更别说 Agent 了。后来我在评测前先做了一轮 JD 质量筛选,把过于模糊的 JD 剔除掉,剩下的 JD 要求都比较具体,Agent 和人工的一致性也提高了。
第三个坑是“过度依赖 Spearman”。Spearman 只衡量排序相关性,不衡量绝对分数的一致性。有时候 rho 不高,但 Agent 在关键决策上(比如“是否进入面试”)和人工是一致的。所以后来我加了一个辅助指标:Top N 匹配的一致性。比如 Agent 排前 5 的 JD 里,人工也排前 5 的有几个。这个指标比单纯的 rho 更贴近实际使用场景。
最后分享一个小技巧:如果你也在做 Agent 匹配评测,建议把“人工评估”和“Agent 评估”的原始数据都保留下来,包括每条 JD 的文本、候选人的信息、Agent 的完整输出、人工的评分和评语。这些数据在后续优化的时候非常有用,尤其是当你需要做错误分析的时候,没有原始数据就只能凭记忆猜,效率很低。
这个项目后续还可以往几个方向扩展:一是把对比排序和绝对打分结合起来,用对比排序做粗排,用绝对打分做精排;二是引入更多维度的评估,比如候选人的成长潜力、文化匹配度;三是把评测流程自动化,减少人工评估的工作量。不过这些都是后话了,先把当前这套流程跑稳再说。