用 Jev 做简历初筛:快速且可复核

更新于 适用版本 Jev 1.13

TL;DR: 一份 JD(职位描述)本质是穿着段落外衣的检查清单。把每条硬性条件转成一道 judgment 判断题,整体匹配度用一次 scoring 打 1-10 分,边界情况连同 rationale 交给招聘人员。你得到的是一轮快速、一致、而且可审计的初筛——这正是公平性审查和合规团队要看的东西。

从 JD 到问题清单

筛选决策必须可解释,所以先改写 JD:

{"answer":"yes","confidence":0.97,"rationale":"工作经历部分显示其带过后端团队 7 年。"}
{"answer":8,"scale":[1,10],"confidence":0.86,"rationale":"技术栈与级别匹配;缺少要求的金融科技背景。"}

初筛流程图

简历 + JD 问题清单
   |
   v
逐条硬性条件调用 judgment(yes / no / unclear)
   |
   +--> 某条真实硬性条件为 no --> 淘汰,保留 rationale
   |
   +--> 出现 unclear 或低置信度 --> 招聘人员队列
   |
   +--> 全部条件通过
            |
            v
        Jev scoring 调用(匹配度,1-10 分制)
            |
            +--> 分数 >= 8 且置信度高 --> 推进到面试
            |
            +--> 分数 6-7 或置信度低 --> 招聘人员队列
            |
            +--> 分数 < 6 --> 淘汰,保留 rationale

每次淘汰和每次推进都存 answer、confidence、rationale。招聘人员看得到原因,候选人问得到原因,审计方能回放原因。

最小实现

import os, json, requests

URL = "https://openrouter.ai/api/v1/chat/completions"
# Confirm the exact model slug on the OpenRouter model page.
MODEL = "typesafe/jev-1.13"

def ask(question: str, resume: str) -> dict:
    resp = requests.post(
        URL,
        headers={"Authorization": f"Bearer {os.environ['OPENROUTER_API_KEY']}"},
        json={"model": MODEL, "temperature": 0, "messages": [
            {"role": "system", "content":
             "Answer strictly from the resume. yes, no, or unclear. "
             "If the resume does not state it, answer unclear."},
            {"role": "user", "content": f"Requirement: {question}\n\n{resume[:6000]}"}]},
        timeout=30,
    )
    resp.raise_for_status()
    # 示例数据(example fixture):
    # {"answer":"yes","confidence":0.97,"rationale":"..."}
    return json.loads(resp.json()["choices"][0]["message"]["content"])

def screen(resume: str, requirements: list[str], low=0.85):
    for req in requirements:
        r = ask(req, resume)
        if r["answer"] == "no":
            return {"stage": "rejected", "requirement": req, **r}
        if r["answer"] == "unclear" or r["confidence"] < low:
            return {"stage": "recruiter-queue", "requirement": req, **r}
    return {"stage": "checklist-pass", **ask("Overall fit 1-10.", resume)}

注意系统提示里的”简历没写就答 unclear”——正是这句话阻止模型对缺失信息瞎猜。官方 API 的端点与字段以 typesafe.ai 官方文档为准。

公平与合规注意事项

关注点做法
问题范围只问书面、与岗位相关的要求;不碰受保护特征
信息缺失模型必须答 unclear,不允许从空白推断
记录留存每次决策存问题、answer、confidence、rationale、模型版本
人工环节所有 unclear、所有低置信度、所有最终决定
偏差检查定期抽样对比不同群体的通过率

为什么固定格式的问题比让聊天模型”评价一下这份简历”更可靠,见 Jev 与 LLM-as-a-judge 对比指南;简历匹配度打分案例展示了完整流水线;阈值调优见置信度与兜底指南。

本文适用版本:Jev 1.13。

FAQ

常见问题

为什么把 JD 拆成多个是/否问题,而不是一个大提示词?

每条硬性条件变成独立的 judgment 调用(如'是否有 5 年以上后端经验?'),小而固定的问题才能返回置信度和 rationale,每次筛选决策都可复核。

怎么保证自动初筛公平合规?

只对与岗位相关的书面要求提问,绝不涉及受保护特征;每次决策都记录 answer、confidence、rationale;低置信度和最终决定一律保留人工环节。

人工复核阈值放在哪里?

实用默认:仅当所有硬性条件都以高置信度通过时自动推进,其余情况——包括任何 unclear 或低置信度结果——全部进招聘人员队列。

继续阅读