# CareerNexus 职联 多源异构数据驱动的**岗位与能力图谱构建与动态演化分析**平台 —— 挑战杯“揭榜挂帅”赛题 XH-202621 参赛作品。 核心链路:多源 JD 接入 → 清洗交叉验证(时滞/噪声/抄袭)→ 结构化抽取(离线规则 / 星火大模型双通道,JSON Schema 强校验)→ 时序知识图谱(Temporal KG)→ 新岗位发现与能力演化分析 → 简历解析、人岗匹配、差距分析与学习路径。 ## 环境准备 ```bash python -m venv .venv # Windows: .venv\Scripts\activate Linux: source .venv/bin/activate pip install -r requirements.txt ``` ## 一键启动 ```bash 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,保存即热生效——配置后抽取走大模型通道,未配置时显式回退离线确定性抽取,前端有醒目的"离线回退模式"横幅提示。 ## 数据生成(已随工程提交,可复现重建) ```bash 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/,与合成集分开报告) ```bash 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`。 ## 指标复现 ```bash 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 份) | — | ## 测试 ```bash python -m pytest tests/ --cov=app --cov-report=term-missing # 74 passed ``` 端到端冒烟(不启动服务): ```bash python scripts/run_demo.py ``` ## Docker ```bash 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 快照即可完整运行;需要企业级图库时可选启用: ```bash 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 次、超时自动降级离线): ```bash 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`,均为纯前端持久化。