一个基于大语言模型的人岗匹配系统,包含学生端和管理后台两个客户端。
学生端支持简历上传、能力画像构建、技能标签管理,以及智能岗位匹配推荐。管理后台负责岗位数据的录入、JD 结构化提取、标签归一化治理,以及匹配引擎的管理。
系统的核心思路是:先把学生和岗位的能力分别拆解为结构化标签(技术栈、技术能力、开发工具、软素质、成长潜力五个维度),再通过逐标签对齐、等级差计算和加权打分完成匹配,最终输出可解释的匹配结果和差距分析。
| 登录页 | 画像编辑 |
|---|---|
![]() |
![]() |
| 岗位探索 | 匹配详情 |
|---|---|
![]() |
![]() |
| 采摘篮 | 收割分析 |
|---|---|
![]() |
![]() |
| 行动计划 | 职业报告 |
|---|---|
![]() |
![]() |
系统分为两个独立的前后端应用,共享岗位数据、标签体系和智能服务:
- 学生端后端调用管理后台的匹配接口获取推荐结果
- 管理后台以 SQLite 作为在线岗位主库,通过 FTS5、预计算检索字段和 Qdrant 完成文本与语义召回
- 岗位完整载荷按请求边界读取,
career.json仅作为首次迁移或离线重建输入 - LLM、OCR 和向量调用统一采用 OpenAI 兼容接口,可按任务连接不同模型供应商
| 层次 | 技术 | 说明 |
|---|---|---|
| 前端 | React 19 + Vite + Tailwind CSS | 两个独立的单页应用 |
| 后端 | FastAPI + Uvicorn | 学生端 :8001,管理后台 :8000 |
| 数据库 | SQLite(学生端与岗位主库)+ FTS5 | 事务化存储,岗位载荷按需读取 |
| AI 模型 | OpenAI 兼容 API(旗舰 + 快速 + 向量三层) | 支持 GPT / Claude / DeepSeek 等 |
| 向量服务 | Qdrant + OpenAI 兼容 Embedding API | 持久化语义召回、标签搜索和归一化 |
| 数据处理 | NumPy + Pandas + Scikit-learn | 匹配打分和向量计算 |
- Python 3.10+
- Node.js 18+
pip install -r requirements.txt
cd career-planner/frontend && npm install && cd ../..
cd job-admin/frontend && npm install && cd ../..复制 .env.example 为 .env,填入模型 API 密钥:
# 旗舰模型(简历解析、报告生成、岗位画像提取)
JOB_SYSTEM_FLAGSHIP_LLM_BASE_URL=https://api.example.com/v1
JOB_SYSTEM_FLAGSHIP_LLM_API_KEY=your-key
JOB_SYSTEM_FLAGSHIP_LLM_MODEL=gpt-5.4
# 快速模型(分类、判断等轻量任务)
JOB_SYSTEM_FAST_LLM_BASE_URL=https://api.example.com/v1
JOB_SYSTEM_FAST_LLM_API_KEY=your-key
JOB_SYSTEM_FAST_LLM_MODEL=gpt-5.4-mini
# 向量模型(语义搜索、标签归一化)
JOB_SYSTEM_EMBEDDING_BASE_URL=https://open.bigmodel.cn/api/paas/v4
JOB_SYSTEM_EMBEDDING_API_KEY=your-key
JOB_SYSTEM_EMBEDDING_MODEL=embedding-3
# OCR 模型(图片简历转写,走 OpenAI 兼容 Chat Completions)
JOB_SYSTEM_OCR_BASE_URL=https://api.example.com/v1
JOB_SYSTEM_OCR_API_KEY=your-ocr-key
JOB_SYSTEM_OCR_MODEL=your-image-aware-ocr-model
JOB_SYSTEM_OCR_TIMEOUT_SECONDS=180
# JWT 密钥(学生端登录用)
CAREER_PLANNER_JWT_SECRET=your-random-string以上为必填项。完整配置(端口、超时、并发、温度等)见 .env.example。
OCR 不是绑定某个厂商的专用 SDK:上游只需兼容 /v1/chat/completions,接受 image_url.url 中的 Base64 Data URL,并在 choices[0].message.content 返回文字。返回内容可以是纯文本、Markdown、HTML 或 LaTeX,系统会把这份文字底稿再交给旗舰文本模型,统一抽取为学生画像 JSON。这样可以用较小的专用 OCR 模型完成识字与版面恢复,减少主模型直接处理图片时的视觉 token 噪音;OCR 失败或返回空内容时,当前实现会回退到直接视觉抽取。详见 简历 OCR 流水线与接入协议。
python start_all.py启动后访问:
- 学生端:http://localhost:3000
- 管理后台:http://localhost:5173
- 学生端 API 文档:http://localhost:8001/docs
- 管理后台 API 文档:http://localhost:8000/docs
首次迁移完整岗位库时会执行一次 SQLite/索引构建;数据未变化时,管理后台通常约 3.5 秒即可完成健康启动。
学生端内置了一个预填充画像的演示账号:
| 用户名 | 密码 |
|---|---|
| admin | 123456 |
仓库自带的 dataset/career.json 包含约 100 条岗位画像样本数据(覆盖 21 个技术方向),仅供演示和功能验证。这些数据由模拟生成,不代表真实岗位信息。如需接入实际岗位数据,通过管理后台上传 JD 即可自动生成结构化画像。
如需完整数据集(10,800+ 岗位画像 + 标签关系 + 向量缓存)用于复现标签归一化和匹配效果,可从 Release 下载:
解压后将文件覆盖到项目对应目录即可:
unzip dataset-full.zip -d .系统将学生和岗位的能力拆解为五个维度:
- 技术栈(编程语言、框架)
- 技术能力(算法、架构设计等抽象能力)
- 开发工具(IDE、CI/CD、云服务等)
- 软素质(沟通、协作、领导力)
- 成长潜力(学习能力、项目经验深度)
每个标签带有 1-5 的能力等级。匹配时逐标签对齐,计算等级差,加权求和得到总分。根据总分和核心技能覆盖情况,将岗位分为三档:
- 保底岗:学生能力完全覆盖且等级达标
- 精准岗:核心能力匹配,等级在合理区间
- 挑战岗:存在技能缺口,适合作为成长目标
匹配结果附带具体的命中标签、缺失标签和等级差分析,支持一键生成 AI 深度分析报告。
详细算法文档见 docs/matching_algorithm.md。
Rolefit/
├── career-planner/ # 学生端
│ ├── backend/ # FastAPI 后端(:8001)
│ └── frontend/ # React 前端(:3000)
├── job-admin/ # 管理后台
│ ├── backend/ # FastAPI 后端(:8000)
│ └── frontend/ # React 前端(:5173)
├── dataset/ # 共享数据与迁移输入
│ ├── career.json # 岗位库迁移/离线重建输入
│ └── db/ # SQLite 主库、标签词典和索引资产
├── shared/ # 公共工具模块
├── docs/ # 设计文档
├── docs_assets/ # README 与文档使用的视觉素材
├── start_all.py # 一键启动脚本
└── requirements.txt # Python 依赖
| 文档 | 内容 |
|---|---|
| 岗位画像字段定义 | 岗位数据结构和字段说明 |
| JD 提取流水线 | 从原始 JD 到结构化画像的提取流程 |
| 标签归一化机制 | 标签去重、聚类和标准化 |
| 匹配算法详解 | 打分公式和分档逻辑 |
| API 接口文档 | 全部 REST API 说明 |
| LLM 配置说明 | 模型选择和环境变量 |
| 简历 OCR 流水线 | OpenAI 兼容 OCR 协议、Base64 图片请求与降级策略 |
- 调研国内外招聘平台提供的官方 API 与 OAuth 授权能力,在遵守平台条款、用户授权和限流要求的前提下,接入真实职位导入、同步与投递状态;优先评估具有正式开发者平台的海外服务,同时持续关注国内招聘平台是否开放合规接口。
![]() connectedGraph |
![]() sedsej |
![]() zzZ |
MIT
2026-08-24 完成了两阶段管理后台内存优化。优化过程保持了现有公开 API、响应结构、匹配公式和 Qdrant collection,不以删功能换指标。完整执行记录、测量口径和后续条件见 管理后台内存优化交接文档。
在加载 10,822 条岗位数据的场景中,管理后台存在多份完整岗位对象、标签快照和向量缓存同时驻留的问题:
| 指标 | 优化前 |
|---|---|
| 仅导入后台模块 | 约 146 MB RSS |
| 完整运行时加载后 | 约 410 MB RSS |
| 进程启动内存高水位 | 约 604 MB |
| systemd cgroup 启动峰值 | 约 684 MB |
| 启动耗时 | 约 11 秒 |
| 最终交换到 Swap | 约 312 MB |
实现提交:b8b46e8(Reduce Zhitu admin startup memory)
- SQLite 岗位数据改为逐行读取、解码和归一化,不再同时保留“原始行 + 解码对象 + 归一化对象”三份完整副本。
- Pandas、LangChain 和 OpenAI 相关依赖改为惰性导入,普通启动不再提前承担 CSV/Excel 或 LLM 工作流的内存成本。
- 标签快照增加源数据库签名清单;数据未变化时直接复用约 100 MB 的标签/领域资产,不再每次启动重建。
- 196.8 MB 的 embedding JSON 缓存改为流式读取,并对缓存状态查询结果进行记忆化。
实测结果:
| 指标 | 优化前 | Phase 1 后 |
|---|---|---|
| 仅导入后台模块 | 约 146 MB | 约 63 MB |
| 导入并加载完整运行时 | 约 407 MB | 约 182 MB |
| 启动耗时 | 约 11 秒 | 约 3.7 秒 |
| 稳定 RSS | — | 约 234 MB |
| 进程内存高水位 | 约 604 MB | 约 235 MB |
| Swap | 约 312 MB | 0 |
| 归一化缓存状态接口 | 约 1.7 秒 | 约 2 毫秒 |
针对性测试结果:9 passed。
实现提交:bb972a2(Reduce Zhitu admin resident job memory)
Phase 2 把 SQLite 提升为在线岗位数据的唯一事实来源,并加入 schema v2:job_search、job_search_fts、job_tags 和 job_repository_meta。
- 3 个及以上字符的查询使用 FTS5 trigram;短中文查询走标量字段和预计算搜索文本。
- 运行时不再持有完整的
state.jobs_metadata,只保留紧凑 ID、位置映射、倒排 posting 和频次。 - 岗位列表与详情接口只加载本次请求需要的载荷;匹配流程先召回 ID,再批量读取一个有上限的候选集合。
- 导出每批流式读取 200 行,避免再次把完整岗位库装入 Web 进程。
- 新增、修改、删除岗位时,主载荷、搜索字段、FTS 索引和标签关系在同一事务内更新。
career.json降为迁移输入,不再承担在线主库职责。
实测结果:
| 指标 | Phase 2 结果 |
|---|---|
| 紧凑状态导入/运行时最大 RSS | 71,432 kB |
| 代表性请求后的温态 RSS | 131,320 kB |
| Swap | 0 |
| systemd cgroup current / peak | 109,858,816 / 111,419,392 bytes |
| 启动到健康检查通过 | 3.537 秒 |
| 应用初始化区间 | 2.317 秒 |
/api/jobs?limit=20 |
9.3–11.1 毫秒(此前约 20–25 毫秒) |
/api/admin/summary |
14.8 毫秒 |
| 固定匹配样例 | 0.818 秒(此前 2.022 秒) |
匹配结果、分档与顺序保持等价,针对性测试结果为 14 passed。
首次迁移 10,822 条数据时会生成约 204 MB 的 SQLite 数据库,其中包含 10,822 组主载荷/搜索/FTS 记录与 46,792 条标签关系。首次迁移和快照重建耗时 20.512 秒,进程高水位约 475 MB、cgroup 峰值约 683 MB;这是一次性迁移成本,不代表数据未变化时的正常启动表现。
Phase 2 已经解决实际运行中的内存问题:管理后台温态 RSS 约 131.9 MB、VmSwap: 0,决策时主机仍有约 1.9 GiB 可用内存。继续移除本地在线向量会改变 Qdrant 故障时的回退语义,使 Qdrant 成为更强的硬依赖;把重任务拆为独立 worker,也缺少“生产环境反复出现内存压力”的证据。因此 Phase 3 不应仅因为写在交接文档中就启动。
只有在测量到以下任一条件后才重新评估:
- 温态 RSS 多次超过 160 MB,或正常流量开始产生 Swap。
- 主机持续内存紧张,或多个 Admin Web worker 重复持有向量内存。
- 导入、归一化、画像构建、标签审核或快照重建反复使 Web PID 长时间高于基线。
- 产品明确接受 Qdrant 作为匹配硬依赖,并接受向量服务故障时确定性的结构化
503。 - 标签/向量规模增长,使当前向量缓存或 posting list 再次成为可测量的瓶颈。











