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) 固定:1720 条 JD(2019-2026,26 个岗位,15 城市,7 行业,8% 抄袭、噪声植入)、
# 179 项技能词表(含 AIOps/微前端/ROS/SLAM/联邦学习/零信任等新技能)、176 条测试集+标准答案、
# 52 对人岗匹配标注、
# 7 份简历样例(txt,另附 resume_full.docx / resume_full.pdf 演示上传解析)、3 份行业报告样例、7 条审核留痕种子记录

岗位清单(26 个,对齐人工智能/大数据/智能系统/物联网等新一代信息技术领域):

  • 后端与前端:Java开发工程师、Python开发工程师、Go开发工程师、前端工程师
  • 大数据:数据工程师、大数据开发工程师、数据治理工程师
  • AI 与算法:算法工程师、机器学习工程师、NLP工程师、CV工程师、智能机器人算法工程师、隐私计算工程师
  • 智能系统与云原生:云原生工程师、智能系统架构师、边缘计算工程师
  • 物联网与嵌入式:嵌入式工程师、物联网工程师、物联网安全工程师
  • 测试/运维/分析/产品:测试开发工程师、运维工程师(SRE)、数据分析师、AI产品经理
  • 新岗位发现入库(2023 年后出现):大模型应用工程师、RAG工程师、提示词工程师

简历上传支持 .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% (176 条) ≥90%
简历提取准确率 100% (7 份简历) ≥90%
人岗匹配准确率 100% (52 对标注) ≥90%
真实 JD(AutoWeakS)技能 F1 99.80% (200 条) / 99.82% (500 条分层) ≥80%
真实简历(AIStudio)姓名/电话命中 100% / 100% (200 份) 100%
真实简历(AIStudio)技能 F1 100% (200 份) —

测试

python -m pytest tests/ --cov=app --cov-report=term-missing
# 74 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,均为纯前端持久化。

S
Description
CareerNexus 职联
Readme
4.2 MiB
Languages
Python 49.5%
JavaScript 33.4%
CSS 10.1%
HTML 5.8%
Shell 0.5%
Other 0.7%