返回技能市场
企业经营 安全

简历筛选

@user_3t0fj/resume-screening-agent

简历筛选智能体(v2·新规则版,防幻觉确定性内核)。当用户给来「岗位要求明细表 + 一批简历」,要做初筛/人岗匹配/通过与否判定,或强调「结果要稳定、可追溯、避免 AI 幻觉、需要人工复核」时使用。判定全部由标准库确定性代码完成,同一输入逐字节可复现;大模型只负责读文件与组织话术,绝不产出「通过/不通过」。适用场景:招聘初筛、资格条件核验、履历评分,以及同类的「批量数据 × 既定规则 → 通过/不通过判定」需求。产出:三态结论(通过/不通过/异常)+ 逐条要求证据链 + 人工确认界面 HTML + 可追溯报告 HTML。

user_3t0fj 热度 50v0.0.1

简历筛选智能体 v2(新规则版)

一句话

判定全部交给标准库代码,大模型一行判定都不许写。

同一份输入,跑一万次结果逐字节相同;每条结论都能追回到「简历哪个单元格 / 岗位哪句原文 / 知识库哪一行」;判不出来的当场报「异常」交人工,不许猜、不许兜底、不许"应该差不多"

---

红线(任何步骤都不得违反)

| # | 红线 | 违反后果 | |---|---|---| | 1 | 大模型不产出三态结论。所有「通过 / 不通过 / 异常」只由 screening_core.py 产出 | 结论漂移、无法复现、无法审计 | | 2 | 抽取值必须能在原文里逐字找到。归一化只能走受控词表(标准术语),不做同义发挥 | 幻觉:编出一个原文没有的条件或经历 | | 3 | 两侧用同一套标准术语terms.py)。岗位侧与简历侧写法不一致就自动比不了 | 静默漏判:字符串不等 → 判成"不满足" | | 4 | 判不出来 → 异常,不猜。缺哪一列要指名道姓 | 把"信息不全"伪装成"通过" | | 5 | 不调用任何模型 / 不联网。纯标准库,可在云端离线跑 | 结果不可复现 | | 6 | 渲染端只读判定结果,绝不重跑判定 | 界面口径与报告口径各漂各的 | | 7 | 基准日写错必须报错,不静默兜底 | 年龄/年限类判定整体偏移 |

---

六步流程(人机协同)

给用户的每一句话都要短。少解释、多给结果,让用户点「确认」或「改」。

① 智能体:开场 + 发模板

话术(直接照抄):

我可以帮你做简历初筛。请按模板准备两个 Excel:
1. 岗位要求明细表(含「资格条件」列)
2. 简历表
两个模板见 templates/岗位信息表-模板.xlsx简历表-模板.xlsx
每份只保留 1 行示例,照着列填、删掉示例行即可。
  • 附上 templates/岗位信息表-模板.xlsxtemplates/简历表-模板.xlsx
  • 不发模板就别让对方猜列名——列名对不上,后面全白干。

② 用户:导入两个 xlsx

收到文件后只做一件事:确认这是「岗位表 + 简历表」,不是别的。然后进 ③。

③ 智能体:解析岗位要求 → 给用户确认

调用:

python scripts/parse_position.py --positions 岗位信息表.xlsx --out positions.json

必须遵守(规则原文:《简历筛选数据清洗及规则(确认后的)》,见 references/01-规则与口径.md):

  • 逐条切分「资格条件」正文,一条要求一个维度,条数要覆盖全部编号条款(脚本自带 _条款覆盖 校验)
  • 每个取值都给 原文片段(逐字),归一化只允许词表内取值
  • 认不出的条款不许硬套,标成「定性/制度类要求 → 需人工」

话术:

岗位要求已解析:16 个岗位 / 175 条要求(可自动判定 138 条、转人工 37 条)。
条款覆盖 103/103,无遗漏。
请确认:① 岗位数对不对?② 有没有该判却没识别的条款?
用户确认后再进下一步。没确认不许往下跑——后面所有判定都长在这份解析上。

④ 智能体:解析简历 → 给用户确认

调用:

python scripts/parse_resume.py --resume 简历表.xlsx --kb references/知识库-简历筛选.xlsx \
    --as-of today --out resumes.json
  • 每个事实带 出处(源列 + 单元格原值)与 推导
  • 查知识库(院校层次/办学性质、专业类、单位白名单/发供电、职称、荣誉、政治面貌),命中要记行号
  • 归一化到与 ③ 同一套标准术语(否则 ⑤ 比不了)
  • 空值 ≠ 无:算不出来写 null,不填默认值

话术:

简历已解析:114 份,55 个字段全部归一化到与岗位侧同一套术语。
⚠️ 有 8 份「专业」为空、1 份「毕业院校」为空 —— 属源表缺项,会按「异常①信息不全」显影,不会猜。
请确认后继续。

⑤ 智能体:逐条匹配 → 出「人工确认界面」

调用:

python scripts/run_screening.py --positions 岗位信息表.xlsx --resume 简历表.xlsx \
    --kb references/知识库-简历筛选.xlsx --as-of today --out ./out

产出 成果1-筛选结果-人工确认界面.html + 筛选结果-full.json

硬要求:

  1. 每个岗位要求都判一遍,一条不落(覆盖校验 会机检条数;脚本里 units_of() 负责把
  2. 同一判定的多个分支合并成一个单元,并把岗位表没写、但公司通用口径要求必判的维度补进来 —— 漏了这一步会白送"通过",副总监岗就踩过这个坑)

  3. 三态:通过 / 不通过 / 异常;不通过的写清 淘汰原因,异常的写清 异常原因
  4. 异常四类要分开标:
  • ① 信息项不全,无法判断(要指名缺哪一列)
  • ② 未找到匹配的岗位
  • ③ 岗位名称与岗位表非精确一致
  • ④ 其他无法计算出结论的情况
  1. 表格列(11 列<thead>th 个数、JS 里的 var NCOL = 11;
  2. 展开行的 colspan 三处必须同步,否则展开行右侧会短一列露出底色断层): 勾选 / 序号 / 姓名 / 应聘岗位 / AI筛选结果 / AI筛选详情 / 需人工关注确认 / 淘汰原因·异常原因 / 确认结果 / 简历详情 / 操作

  3. 展开区必须跨全表铺开(渲染上是挂在 colspan=NCOL 详情行里,不是塞进单元格):
  • 「AI筛选详情」展开后 = 横向 6 列:判定维度 / 结果 / 岗位要求(概要) / 简历实际 / 说明 / 出处(可核对)
  • 「需人工关注确认」展开后 = 独立面板,逐条两行:
  • [来源列] 标签 + 该条条款摘要(长条款去括号枚举后断句,虚线下划线可悬停看全文) ② 为什么需要人看(如「属定性或制度类要求,需人工关注」) ⚠️ 这一条容易被做废:只写原因不写「是哪一条」的话,同一岗位下几十条一模一样的 文案,人根本对不上号(本批 341 条里 141 条同款)→ 已进 selftest.py 守门

  • 「简历详情」展开后 = 字段原值按分组横向多列排(基本信息 / 学历 / 工作经历 / 职称与荣誉 / 绩效与表现)
  • ⚠️ 别把展开内容放回单元格:290px 的列宽会把每句话压成竖条(这条已进 selftest.py 守门)
  1. 「确认结果」三态:确认通过 / 待确认(初值)/ 确认不通过;「操作」= 通过 / 淘汰,
  2. 支持勾选后批量确认,可导出确认结果(JSON + CSV)

界面交互(都进 selftest.py 守门,别退化):

| 交互 | 要求 | |---|---| | 顶部副标题 | 固定为「共 N 份简历 | 判定引擎:确定性内核,无大模型参与 | 每条判定都可回溯到简历原值、岗位条件原文或知识库行号」;不出现「口径:…」那一行(口径仍完整留在 筛选结果-full.jsonmeta.口径 里) | | 指标卡(第一行·系统结论) | 通过 / 不通过 / 异常 / 异常率 / 通过率 五张卡可点击:通过·通过率→筛「通过」,异常·异常率→筛「异常」,再点一次取消。卡面常显「点击筛选」,激活时变「已筛选 · 再点取消」 | | 指标卡(第二行·人工确认) | 人工确认 · 通过 / 人工确认 · 淘汰 / 人工确认 · 待确认 三张卡:全部简历初始为「待确认」;点下方「通过 / 淘汰」(含批量)后数字实时更新;点卡片筛出该类人群,再点一次取消。数值为 0 时数字置浅灰(.zero) | | 两组筛选可叠加 | 第一行(系统结论)× 第二行(人工确认)是两组独立筛选,同时生效。例:点「通过率」再点「人工确认 · 待确认」= 系统判通过、但还没人工拍板的那批。留空即「全部」 | | 人工确认计数取全量 | confirmCounts() 必须遍历 RESULTS,不能遍历当前筛选结果 —— 否则数字会随筛选自己缩水(已进 selftest.py 守门) | | 展开 / 收起 | 按钮带明显三角图标(收起 ▶ / 展开 ▼,靠 aria-expanded 驱动 transform:rotate(90deg));展开态文案用「收起 N 条要求的判定」(不追加「(收起)」,否则按钮会折成两行) | | 手风琴互斥 | 同一个人同时只展开一个面板:AI筛选详情 / 需人工关注确认 / 简历详情 三者互斥。展开 AI筛选详情后再点简历详情,前者必须自动收起 | | 表头吸顶(两层) | 主表:thead th{position:sticky;top:var(--headtop)};展开后的明细表.wk table.wide thead th{position:sticky;top:var(--dheadtop)}。两个偏移都由 syncHeadTop() 实测写入 —— --headtop = .toolbar 实际高度(工具条本身也 sticky 在 0),--dheadtop = 工具条高度 + 主表头高度。两层必须错开且无缝(实测主表头 48–84、明细表头 84–114);明细表头 z-index:5 低于主表头 6,万一窗口变窄导致行高变化,也让主表头压在上面。窗口 resize 会重算两个偏移。成果 2 的每张长表同样吸顶 | | 岗位要求列 | 只放概要brief() 去序号 → 去「X要求:」标签 → 截到首个句号/分号 → 超长加「…」),全文挂 title 供悬停查看 |

话术:

初筛完成:通过 38 / 不通过 75 / 异常 1(共 114 份,通过率 33.3%)。
界面里可展开每一条要求的依据;请点「通过 / 淘汰」,支持批量。
「异常」的人都写清了是哪一类、缺哪一列 —— 这几位必须你拍板。

⑥ 用户:批量确认 → 智能体出报告

用户点完(或直接说"这批我确认完了 / 全部按系统结论")后,产出 成果2-筛选报告-过程与依据.html

  • 方法与红线、口径条
  • 汇总 + 异常类别分布 + 各维度判定分布 + 主因归集
  • 逐人完整证据链:每条要求 = 判定 → 岗位条件原文 → 依据(简历原值 / 知识库行号 / 规则原文)
  • 知识库清单、解析统计、覆盖校验
  • 人工确认结果回填(人工确认不覆盖系统结论,两者并列留痕)

话术:

报告已出:成果2-筛选报告-过程与依据.html(含 114 人的逐条证据链)。
人工确认结果已导出,可回写业务系统。

---

一键跑通(步骤 ⑤⑥ 合体)

python scripts/run_screening.py \
  --positions 岗位信息表.xlsx \
  --resume 简历表.xlsx \
  --kb references/知识库-简历筛选.xlsx \
  --as-of today \
  --out ./out

| 参数 | 说明 | |---|---| | --as-of | 基准日 = 招聘公告截止日。写 today 取本机今天;也可写 2026-09-23。写错直接报错 | | --out | 输出目录,落 筛选结果-full.json + 两份 HTML | | --limit | 只跑前 N 份(调试) | | --岗位名匹配 | normalized(默认)/ exact,见下 | | --数据源不承载的维度 | manual(默认)/ abnormal | | --不还原术语 | 跳过「专业/职称文字还原」(展示层回写仍会执行) | | --术语还原表 | 自定义还原词表路径,默认 references/术语还原表.tsv |

渲染端也能单独跑(改了界面样式时不必重跑判定):

python scripts/render_html.py --full out/筛选结果-full.json --out out

---

口径开关:两组数字,请用户拍板

同样的数据、同样的规则,岗位名口径会让通过率从 33.3% 掉到 20.2%,必须让用户明确选:

| 口径 | 岗位名匹配 | 通过 | 不通过 | 异常 | 通过率 | |---|---|---|---|---|---| | A(默认,推荐) | 允许「岗位表部门」列前缀 | 38 | 75 | 1 | 33.3% | | C | 要求字面精确一致 | 23 | 75 | 16 | 20.2% |

(同一批 114 份简历、同一份知识库、基准日 2026-09-24 实测)

A 为什么合理(有证据,不是拍脑袋):

  • 全表 114 份里 45 份按「部门 + 岗位」写法填 应聘岗位(如「某某业务部某某业务及安全管理专责」),
  • 其前缀 100% 逐字等于岗位表『部门』列的取值 → 属可机械核验的规范化写法,不是随手写错

  • 这 45 份对应 4 个岗位,同名岗位的资格条件逐条一致(脚本 _check_same_name() 机检)
  • → 「四级单位无法唯一确定」这件事不改变任何结论

  • 即便如此,A 仍把这 45 人全部列入需人工关注(提示确认四级单位),不静默放过

取舍建议:对外交付用 A;若审核方坚持字面口径,用 C(异常 16 人,人工能清完)。

⚠ 反例留档:规则字面曾经「跑不出结果」

在简历表补齐「三级及以上单位正式工作经历时长(年)」列之前,把两条最严口径叠在一起:

| 口径(补齐该列之前) | 岗位名匹配 | 数据源不承载 | 通过 | 不通过 | 异常 | 通过率 | |---|---|---|---|---|---|---| | D | exact(字面精确一致) | abnormal(信息项不全即异常) | 0 | 69 | 45 | 0.0% |

「岗位名必须字面精确一致」+「信息项不全即异常」同时严格执行 → 无人通过。 不是代码 bug,是规则字面不自洽 —— 这也是为什么必须补齐那条数据、并显式选一条口径放宽。 补列之后同样是 exact + abnormal,通过率回到 20.2%,工具才可用。

--数据源不承载的维度 开关在本批数据上已不影响结论(源表已补该列)。
只有当源表缺该列时它才生效:manual = 该条转人工、不影响三态;
abnormal = 判异常①信息项不全。

---

已知数据缺口(会显影为异常/需人工,不是 bug)

| 缺口 | 影响到谁 | 现状 | |---|---|---| | 岗位表 16 个岗位中只有「副总监」正文没写基层一线条款 | 副总监岗候选人 | 已按公司通用口径补判(通用规则注入=all);改成 text-only 则整维度不判 | | ~~「须至少含 1 年三级及以上单位正式工作经历」无数据~~ | ~~69 人~~ | ✅ 已解决:简历表补齐「三级及以上单位正式工作经历时长(年)」列,该条改为自动判定 | | 简历表无「四级单位」字段 | 同名多岗位的 45 人 | 已核验同名岗位条件一致 → 不影响结论,仍提示人工确认 | | 8 份「专业」为空、1 份「毕业院校」为空 | 9 人 | 源表缺项(已核对脱敏前后一致),报异常/需人工 | | 回避原则为定性条款 | 全体 | 列人工确认,不参与自动三态 | | 3 人「校招入职单位」填 广西某某有限责任公司,知识库条目写作 广西某某有限责任公司(本部及职能部门) | 3 人 | 已加去括号后精确匹配_unit_key)→ 命中白名单=是 → 直接符合第一步。刻意不做前缀匹配:否则所有「某某局」都会撞上本部条目,基层一线维度集体放水 |

---

新增字段:「三级及以上单位正式工作经历时长(年)」

规则「须至少含 1 年三级及以上单位正式工作经历」在 16 个岗位都写了,但原导出表没有这个量, 原先只能判「需人工」。现已补进简历表(第 56 列,工作经历信息 组),该条可自动判定≥ 1 年 → 通过;< 1 年 → 不通过;该列缺失/为空 → 异常①(指名缺列)

补数口径(可复现,不是臆造)

三级及以上单位正式工作经历时长
  = max(0, 系统内工作时长 − 基层一线工作时长 − 班站所长工作时长 − 党支部书记工作时长)

即「系统内时长里扣掉在基层一线/班组层级的经历」,剩下的视为在三级及以上单位 (地市局本部及以上)的正式工作经历。

本批 114 人实测:≥1 年 103 人、=0 的 11 人、均值 7.49 年

  • 有该列时,取值直接来自源表,出处写明具体列名
  • 没有该列(旧版简历表)时,parse_resume.py 自动按上式推导,并在推导链里写清
  • 「该值为推导值,不是客户原始数据;正式使用请由业务系统导出该列」

  • 生产环境应要求业务系统直接导出该列,推导式只作过渡
补齐该列后,--数据源不承载的维度 开关不再影响本批结论;
通过率由 38.6% 变为 33.3%(新增该条判定使 6 人由「通过」转「不通过」——
他们的三级及以上单位经历为 0 年,按规则本就不满足)。

---

脱敏口径(v2):只打码企业名称(2026-09-24 收窄)

交付前的输入表做过脱敏。口径经过一次收窄,务必分清:

| 版本 | 口径 | 后果 | |---|---|---| | v1(旧,已弃) | 凡含「电」的字眼一律 某某 | 院校 桂林电子科技大学桂林某某科技大学、专业 电气工程及其自动化某某工程及其自动化、术语 发供电企业名单某某企业名单。业务方在院校库里根本检索不到(旧库共 150 种院校名被打码),核对无从下手 | | v2(现行) | 只打码企业 / 单位名称 | 上面那些全部保留原文;只有企业名仍打码(广西电网有限责任公司广西某某有限责任公司桂林供电局桂林某某局) |

实测对照(用户反馈的 5 所院校):

| 院校 | 旧库(v1) | 新库(v2) | |---|---|---| | 桂林电子科技大学 | ❌ 检索不到 | ✅ 命中 | | 上海电力大学 | ❌ 检索不到 | ✅ 命中 | | 华北科技学院 | ✅ 命中(不含「电」字) | ✅ 命中 | | 华北水利水电大学 | ❌ 检索不到 | ✅ 命中 | | 广西电力职业技术学院 | ❌ 检索不到 | ✅ 命中 |

判定逻辑:靠「企业名形态」圈定范围,不靠字符

mask 只在电语素 + 右侧紧跟企业后缀处生效,三条约束缺一不可:

| 约束 | 内容 | 排掉的误伤 | |---|---|---| | 语素表 | 电网 / 供电 / 电力 / 送变电 / 配售电 / 水电 / 新电力 / 电科院 … | —— | | 后缀表 | 有限责任公司 / 有限公司 / 集团 / 公司局 / 分局 / 所 只允许跟在 供电 / 电业 | 输电管理所变电管理二所(内部机构,不是单位名) | | 左侧判据 | 左侧不得是分隔符(/ \ 、 ,)或层级词(地市 / 三级 / 所属) | 班员/副班长/供电所/供电分局(岗位类别枚举)、地市供电局三级供电公司 |

⭐ 三条约束必须放在 Python 侧判断,不能写进正则:写进正则会让引擎从语素内部重试 ——
/配售电公司 被切成 + 售电,得 配某某公司。正解是匹配后判断、并吃掉这次匹配。
⚠️ 单字层级词表里不能放「县」「等」:真实单位名 天等供电局藤县供电有限公司
会被误挡(实测漏网 2 类)。层级说法交给两字表(县级/四级)或左邻「级」处理。

因此天然落在范围外(保留原文)的:院校名(…大学 / 学院 / 研究院)、专业、职称、荣誉名、 法条(《电力法》)、行业术语(发供电企业)、部门名(电力调度控制中心)。

展示层(unmask.py,只动展示、不动判定)

判定全部完成之后才执行,所以不可能改变「通过 / 不通过 / 异常」。 v2 口径下术语不再打码,两个方向都空转,但机制保留可配:

| 机制 | v2 状态 | 说明 | |---|---|---| | 还原(术语还原表.tsv) | 空表 | 专业/职称已是原文,无需还原 | | 回写(DISPLAY_MASK) | 空元组 | 数据里就是 发供电企业名单,与内核写法一致,无需反向打码 |

# 词表与回写都是可配的:将来若对术语重新打码,把词表与 DISPLAY_MASK 加回来即可
python scripts/run_screening.py ... --术语还原表 references/术语还原表.tsv
⚠️ 生成还原表时必须剔除「差异仅来自企业名打码」的条款,否则会把 南方某某公司
还原成 南方电网公司、把企业名重新漏出来。本批整格 diff 15 条全是这类,
已按判据 mask_orgs(原文) == 脱敏写法 ⇒ 属企业名差异 ⇒ 不还原 剔除。

---

与上一版(v1,09-22)的差异

| 项 | v1 | v2(本版) | |---|---|---| | 规则依据 | V4.0 旧规则 | 《简历筛选数据清洗及规则(确认后的)》09-23 版 | | 数据 | 未脱敏(含「电网」字样) | 只脱敏企业名称(院校 / 专业 / 职称保留原文) | | 岗位名称非精确 | 未单列 | 记入需人工关注 + 可切 exact 置异常③ | | 通用规则注入 | 无 | 有(_GENERIC),修掉「副总监岗整维度被跳过 → 白送通过」 | | 单位白名单匹配 | 仅精确 | 精确 + 去括号精确 | | 覆盖校验 | 无 | 有(coverage_check,机检每个候选人的判定条数) | | 三级及以上单位经历 | 无数据 → 需人工/异常 | 简历表补齐该列 → 自动判定;缺列时按推导式兜底 | | 院校 / 专业文字 | 保持脱敏(院校库里检索不到) | 保留原文(院校名、专业、职称都不打码) | | 行业术语 | 被打码(发供电企业名单某某企业名单) | 保留原文;还原表与回写均空转 | | 主表列数 | 10 列 | 11 列(新增「需人工关注确认」) | | 指标卡 | 静态数字 | 两组均可点击筛选(第一行:系统结论 5 张卡;第二行:人工确认 3 张卡),两组可叠加 | | 人工确认进度 | 只有表格里的「确认结果」列 | 指标区第二行实时显示通过 / 淘汰 / 待确认计数,标记后立即刷新 | | 展开区互斥 | 可同时展开多个 | 同一人只展开一个面板(AI筛选详情 / 需人工关注 / 简历详情 互斥) | | 展开图标 | 文字按钮 | 三角图标 ▶/▼aria-expanded 驱动旋转) | | 表头吸顶 | 无 | :主表头 + 展开区明细表头,两层错开(--headtop / --dheadtop 按实际高度自适应) | | 岗位要求列 | 整段铺开 | 只放概要,全文挂 title | | 内部措辞 | 出现「阶段一」「需人工确认」 | 全部去除阶段/需人工确认/口径: 命中 0 处) |

---

目录结构

resume-screening-agent/
├── SKILL.md
├── scripts/
│   ├── xlsx_reader.py      纯标准库 OPC/xlsx 读取(不依赖 openpyxl)
│   ├── terms.py            标准术语层(两侧共用,自动可比的前提)
│   ├── knowledge.py        知识库精准查询(每次取值记「表/行/列/原值」)
│   ├── parse_position.py   资格条件 → 结构化约束(带逐字出处)
│   ├── parse_resume.py     简历表 → 事实 + 出处 + 推导链
│   ├── screening_core.py   ⭐ 唯一产出「通过/不通过」的确定性内核
│   ├── unmask.py           展示层术语映射(v2 口径下术语不打码 → 空转,机制保留)
│   ├── run_screening.py    批处理入口(解析 → 判定 → 展示层映射 → 落盘 → 渲染)
│   ├── render_html.py      只读 JSON 渲染两份 HTML
│   ├── style_assets.py     界面样式(沿用已交付版本,逐字保留)
│   └── selftest.py         交付前自检(可复现性 / 条款覆盖 / 界面与文案守门)
├── templates/
│   ├── 岗位信息表-模板.xlsx  表头 + 1 行示例
│   └── 简历表-模板.xlsx      分组表头 + 1 行示例
├── references/
│   ├── 知识库-简历筛选.xlsx  默认知识库,随包可用
│   ├── 术语还原表.tsv        术语还原词表(v2 口径下为空;机制保留,可替换)
│   ├── 01-规则与口径.md
│   └── 02-输入输出说明.md
└── 样例输出/
    ├── 成果1-筛选结果-人工确认界面.html
    ├── 成果2-筛选报告-过程与依据.html
    └── 筛选结果-full.json

---

交付前自检(改完规则/代码必跑)

python scripts/selftest.py

二十四项全绿才算交付通过:

| 检查 | 在查什么 | |---|---| | 端到端可跑通 | 随包模板 + 随包知识库能出结果、出 HTML | | 同输入可复现(逐字节一致) | 连跑两次,判定结果指纹相同 → 证明没有隐藏的随机性 | | 岗位条款 100% 被识别 | 不允许有条款被静默丢弃 | | 每份简历判定条数完整 | 判定条数 = 岗位判定单元 + 岗位名称行 + 单独列示行 | | 两份 HTML 均生成 | 渲染链路通 | | 展开区跨全表独立成行 | 详情的 colspanNCOL 一致,不塞进单元格 | | 主表 11 列 | 含「需人工关注确认」列,且 NCOL = 11 同步 | | 展开/收起有明显三角图标 | .caret + aria-expanded="true"] .caret{rotate(90deg)} 规则在位 | | 表头滚动吸顶 | 主表 --headtop + position:sticky + syncHeadTop();明细表 --dheadtop 同样由 syncHeadTop() 实测主表头高度后写入 | | 展开区明细表头也吸顶 | .wk table.wide thead thsticky;top:var(--dheadtop),与主表头错开不重叠 | | 指标卡可点击筛选 | 5 张卡带 data-conclpickConcl() 在位 | | 人工确认指标卡三态 | class="cards cards2" + 3 个 data-confirm 属性值 + cuOk/cuNo/cuPend 三个计数锚点 | | 人工确认计数取全量 | confirmCounts() 体内必须是 RESULTS.forEach不得出现 rows() | | 两组筛选叠加生效 | curConfirmstate[r.姓名] 同时参与 rows() 过滤 | | 岗位要求列只放概要 | brief() + title 全文都在 | | 需人工关注逐条标明出处 | 人工关注明细人工关注事项 条数一致,且每项都有「来源/该条/说明」 | | 需人工关注面板结构化 | ol.why.mlist + manHtml()m.该条 / m.该条全文 | | 对外文案不含内部机制措辞 | 全文(去 <script>)不得出现「阶段」「需人工确认」「口径:」「该条来自」 | | 术语还原表为空 | references/术语还原表.tsv 无词条 —— 术语不再打码,无需还原 | | 展示层回写已废除 | DISPLAY_MASK 为恒等(数据即原名) | | 企业名称仍打码 | 结果 JSON 里 某某有限责任公司 / 某某局 命中数 > 0 | | 院校名不被误打码 | 结果 JSON 里 某某大学 / 某某学院 / 某某职业技术 命中 0 处 | | 口径开关可切换 | 命令行开关真的接上了 |

---

环境

  • Python 3.8+,只用标准库json / csv / re / datetime / zipfile / xml / html
  • 不联网、不装包、不调模型 → 可直接在云端/隔离网跑
  • 14 万行级别的知识库(院校库 4014 行、专业库 1028 行)读取约 1 秒;114 份简历全流程约 5 秒
qianwen skills install @user_3t0fj/resume-screening-agent