- scripts/expand_real_dataset.py:AutoWeakS 全量 2215 条 + 500 条分层评测集 + 简历扩量(seed=2026 可复现) - pipeline 被动语料机制(passive_sources):真实无日期 JD 参与接入/清洗/抽取验证(2915 条命中率 99.8%),不进图谱/演化/发现 - 新岗位发现第四指标'差异度'与双年窗口增长率口径 - 评测新增 real_jd_500 维度(99.91%);测试会话隔离 jd_extra_dirs 防止本机配置拖慢套件
CareerNexus 职联
多源异构数据驱动的岗位与能力图谱构建与动态演化分析平台 —— 挑战杯“揭榜挂帅”赛题 XH-202621 参赛作品。
核心链路:多源 JD 接入 → 清洗交叉验证(时滞/噪声/抄袭)→ 结构化抽取(离线规则 / 星火大模型双通道,JSON Schema 强校验)→ 时序知识图谱(Temporal KG)→ 新岗位发现与能力演化分析 → 简历解析、人岗匹配、差距分析与学习路径。
环境准备
python -m venv .venv
# Windows: .venv\Scripts\activate Linux: source .venv/bin/activate
pip install -r requirements.txt
一键启动
python main.py # 自动构建/加载图谱,启动服务并打开浏览器
# 浏览器访问 http://127.0.0.1:9008
系统设置(WebUI 右上角 ⚙)
设置保存在 config.json(优先级高于 config.yaml),包含:
- 服务监听:
127.0.0.1(仅本机)或0.0.0.0(对外开放)+ 端口,修改后需重启(面板提供"保存并重启"); - 访问令牌:设置后
/api/*需携带X-Access-Token头(health 与只读 GET /api/config 豁免); - LLM API:星火/OpenAI 兼容的 base_url、api_key、model,保存即热生效——配置后抽取走大模型通道,未配置时显式回退离线确定性抽取,前端有醒目的"离线回退模式"横幅提示。
数据生成(已随工程提交,可复现重建)
python scripts/generate_dataset.py
# random.seed(2026) 固定:1375 条 JD(2019-2026,18 个岗位,15 城市,7 行业,8% 抄袭、噪声植入)、
# 161 项技能词表(含 AIOps/微前端等新技能)、144 条测试集+标准答案、36 对人岗匹配标注、
# 7 份简历样例(txt,另附 resume_full.docx / resume_full.pdf 演示上传解析)、3 份行业报告样例、7 条审核留痕种子记录
简历上传支持 .txt / .docx / .pdf(POST /api/resume/parse/file,≤5MB,解析即脱敏,临时文件自动清理)。
真实数据集(data/real/,与合成集分开报告)
python scripts/build_real_dataset.py
# random.seed(2026) 固定,从 datasets/XH-202621/data/(只读)加工:
# autoweaks_jd/ 200 条 AutoWeakS 真实 JD(腾讯160/京东40,去分词+技术岗过滤)+ silver gold(初标+抽检30条)
# aistudio_resumes/ 50 份 AIStudio CC0 简历(保留 PII 验证脱敏链路)+ 字段级 gold(抽检10条)
# batch_demo_resumes/ 12 份 chinese_resume 渲染后经 mask_text 脱敏的批量演示素材(原始 PII 不落盘)
# esco_reference/ ISCO/ESCO 职业分类锚点(4 个关键 labels 文件)
来源/授权/处理口径/抽检一致率详见 data/real/README.md。
指标复现
python scripts/evaluate.py
# 输出 reports/metrics.json 与控制台报告
实测(从文本重新抽取再与 gold 比对,非硬编码):
| 指标 | 实测 | 目标 |
|---|---|---|
| JD 解析准确率 | 100% | ≥90% |
| 简历提取准确率 | 100% (7 份简历) | ≥90% |
| 人岗匹配准确率 | 100% (36 对标注) | ≥90% |
| 真实 JD(AutoWeakS)技能 F1 | 99.94% (200 条) | ≥80% |
| 真实简历(AIStudio)姓名/电话命中 | 100% / 100% (50 份) | 100% |
| 真实简历(AIStudio)技能 F1 | 100% (50 份) | — |
测试
python -m pytest tests/ --cov=app --cov-report=term-missing
# 71 passed
端到端冒烟(不启动服务):
python scripts/run_demo.py
Docker
docker build -t careernexus .
docker run -p 9008:9008 careernexus
# 或 docker compose up(可选 Neo4j 增强见下节,默认不启动)
可选高级组件
SQLite 应用状态库(默认启用,零配置)
审核留痕、待审核候选、异步任务状态统一存储在 SQLite(data/careernexus.db,
配置键 state_db_path),仅用标准库 sqlite3、零新依赖:WAL 模式、幂等建表,
服务启动时自动把旧的 data/review/audit.jsonl / data/review/pending.json
一次性迁移入库(原文件保留不删除)。表结构:audit_log(留痕)、
review_candidates(待审核候选)、tasks(异步任务,重启后可恢复查询)、
job_overrides(人工状态覆写层,见下节)。
人工状态持久化(跨图谱重建)
job_overrides 表保存两类人工操作:审核通过的岗位定义(含支撑 JD 来源与时间窗)、
图谱节点编辑。审核 accept 时用候选簇的真实统计入库——REQUIRES 边的 intervals
自首个支持窗口起、sources 为真实支撑 JD 的 source_id 列表,并补
(Job)-[:APPLIES_TO]->(Scenario) / (Job)-[:BELONGS_TO]->(Industry) 边与
"新增"演化事件;节点编辑同步 kg.jobs 的 JobDefinition(title/category/级别,
级别编辑同步回期望年限)。pipeline 全量重建图谱后自动重放覆写层:人工入库岗位
强制纳入正式图谱(不受"2023 年前出现"规则限制),节点编辑一并恢复;
候选被驳回时相应覆写记录自动清理。
JD 手动导入
POST /api/jd/import 支持三种用法(均触发异步 pipeline 重建,任务 ID + 轮询):
- 文件上传:multipart 表单
file字段,支持.jsonl/.csv/.txt(UTF-8,≤10MB;CSV 需含jid,job_title,company,publish_date,text表头); - 文本粘贴:JSON 请求体
{"text": "..."},每行一条 JSON 记录; - 空请求:仅触发全量重建(旧行为)。
逐行校验:合格记录写入 data/jd_raw/import_YYYYmmdd_HHMMSS.jsonl
(source_id 按 文件名#行号 重新分配,保留来源标记);坏行进入响应的
bad_lines 清单并写入 logs/import_bad_时间戳.jsonl。响应含
imported / skipped / bad_lines / file / task_id。WebUI 驾驶舱"导入 JD 数据"
按钮提供上传/粘贴对话框。
Neo4j 图数据库(profile: advanced)
平台默认使用内置 TemporalKG + JSON 快照即可完整运行;需要企业级图库时可选启用:
pip install neo4j # 官方驱动为可选依赖
NEO4J_PASSWORD=你的密码 docker compose --profile advanced up -d neo4j
python scripts/sync_neo4j.py # MERGE 幂等同步 data/graph.json
python scripts/sync_neo4j.py --dry-run # 只打印节点/边统计,不连接
# 浏览器打开 http://localhost:7474 查看(Bolt 端口 7687)
为什么 BGE-M3 / FAISS / reranker / GLiNER / PaddleOCR 不做进容器
这些组件定位为生产部署的可选增强,而非竞赛交付:
- 模型权重 GB 级(BGE-M3、reranker、GLiNER、PaddleOCR 均为深度模型), 镜像体积膨胀到数 GB,构建与分发成本高;
- 评审环境离线,容器内无法下载模型权重,打进镜像又会进一步放大体积;
- 与赛题要求的**“普通笔记本 2 分钟启动”**目标直接冲突——默认链路用纯 Python TF-IDF / 规则抽取即可达到实测指标(见上表),深度模型只在生产侧追求 长尾召回/版式鲁棒性时才有增量价值。
因此交付物默认链路保持轻量确定性实现,上述模型以接口预留方式作为生产增强路线。
大模型抽取通道(可选)
默认 mode: demo 全程离线,使用离线确定性抽取器。配置密钥并改 mode: live 即启用星火/OpenAI 兼容通道(JSON 模式、Schema 校验、失败重试 2 次、超时自动降级离线):
cp .env.example .env # 填入 SPARK_API_KEY(密钥只从环境变量读取)
目录结构
├── main.py # 唯一入口:加载配置→构建/加载图谱→启动服务→自动开浏览器
├── config.yaml # 端口/数据路径/运行模式 demo|live/匹配权重等
├── app/
│ ├── models.py # pydantic v2 全链路模型
│ ├── ingest/loader.py # jsonl 接入,source_id=文件#行号,坏行错误清单
│ ├── cleaning/ # MinHash(128哈希,5-gram)+LSH 近重复、噪声过滤、exp(-λ·age) 时间衰减
│ ├── extract/ # Extractor 协议+多源投票(base) / 离线规则(offline) / 大模型(llm) / 提示词(prompts)
│ ├── graph/tkg.py # TemporalKG:时间区间 + 事件追加不覆盖 + snapshot 切片 + JSON 持久化
│ ├── discover/cluster.py # TF-IDF+凝聚聚类新岗位发现 + 待审核分区 + 审核留痕
│ ├── storage/db.py # SQLite 应用状态库:audit_log/review_candidates/tasks/job_overrides + 旧文件一次性迁移
│ ├── evolution/analyzer.py# 季度窗口聚合,新增/增强/减弱/退出事件 + 中文说明
│ ├── match/ # 简历解析脱敏(resume) / 四维加权匹配+学习路径(engine)
│ ├── services/ # pipeline 端到端编排 / overrides 人工状态覆写层(跨重建重放)
│ └── api/routes.py # FastAPI:统一响应{code,message,data,request_id},任务ID+轮询
├── webui/ # 原生 HTML/JS 单页应用(无构建、完全离线):驾驶舱/图谱工作台/演化/匹配/学习路径
│ ├── index.html # 侧栏+顶栏外壳与五视图结构
│ ├── style.css # 设计系统(token/按钮/卡片/弹窗/表格等)
│ ├── app.js # 公共库 + 驾驶舱/演化/匹配/学习路径
│ └── graph.js # 图谱工作台:力导向画布/小地图/详情面板/编辑/备注/审核
├── scripts/ # 数据生成、真实数据集构建(build_real_dataset)、指标复现、端到端冒烟、sync_neo4j(可选 Neo4j 同步)
├── tests/ # pytest:cleaning/extract/tkg/evolution/match/api/real_data
└── data/ # 词表、JD 原始数据、测试集+gold、简历、报告、图谱快照、real/(真实公开数据集,见其 README)
人机协同审核(防“幻觉”)
新岗位簇与低置信抽取不直接入库:先进入“待审核”分区(SQLite 状态库 review_candidates 表),
人工 accept / modify / reject 后才写入正式图谱,全程留痕(操作人/时间/before/after/理由,
audit_log 表)。抽取结果每个字段附原文证据片段供核对。
WebUI 图谱工作台与节点编辑
全景图谱页为“岗位能力图谱工作台”:canvas 力导向(缩放/平移/拖拽节点/小地图/筛选/关系标签开关), 节点类型覆盖 岗位/技能/行业/场景((Job)-[:BELONGS_TO]->(Industry) 行业归属边,可按类型筛选), 点击节点打开右侧详情面板(基础信息/关联跳转/证据来源/演化 sparkline/备注/审核留痕), 待审核候选以虚线节点并入画布,可直接确认/驳回。
配套接口(统一响应格式,全部留痕):
| 接口 | 说明 |
|---|---|
POST /api/graph/node/update |
编辑节点展示属性(title/level/importance/weight 白名单字段),写图谱并在状态库 audit_log 表追加 kind=node_update 留痕;Job 节点同步 JobDefinition,编辑写入 job_overrides 覆写层(重建后自动重放);只改属性不动结构 |
GET /api/jd?sid=<文件#行号> |
按 source_id 回查 JD 原文(证据来源弹窗),文件名/行号强校验防路径穿越 |
GET /api/audit?node_id=&limit= |
查询审核/编辑留痕(新→旧),可按节点过滤 |
GET /api/graph |
追加返回 events(演化事件列表),供前端趋势图与智能建议 |
节点备注保存在浏览器 localStorage(cn_notes),图谱视图布局保存在 cn_graph_view,均为纯前端持久化。