一个在本机运行的简历批量评估 Web 应用。输入岗位 JD 和最多 20 份 PDF 简历,系统会先整理岗位职责与必备技能,等待用户确认后,再完成简历解析、 经历评估、岗位匹配、独立复核、排名和报告生成。
项目采用:
- 后端:Python、FastAPI、SQLite
- 前端:React、Vite
- PDF:PyMuPDF
- OCR:Tesseract
- Workflow Agent:StepFun
- Evaluation Agent:StepFun
- Review Agent:DeepSeek
上传 JD 和 PDF 简历
↓
Workflow Agent 整理岗位职责与必备技能
↓
用户编辑、确认并冻结本批次 JD
↓
PDF 文本提取,扫描件自动回退 OCR
↓
Workflow Agent 提取结构化简历信息
↓
移除姓名、邮箱、电话后进入评分
↓
Evaluation Agent 联合完成经历评估和 JD 匹配
↓
Review Agent 使用 DeepSeek 独立复核
↓
Python 计算最终分和学历加分
↓
Workflow Agent 生成报告
↓
网页排名、单人详情和 Excel 导出
系统只提供招聘决策辅助,不自动录用或淘汰候选人。
代码位于 app/agents/workflow.py,Skill 位于
agent_skills/workflow-agent/。
该 Agent 根据任务类型执行三类工作:
- 整理或补全 JD 中的岗位职责与必备技能。
- 从 PDF/OCR 文本中提取结构化简历信息。
- 根据最终评分生成中文筛选报告。
代码位于 app/agents/evaluation.py,Skill 位于
agent_skills/evaluation-agent/。
该 Agent 在一次模型调用中同时完成:
- 经历可信度评估
- 经历含金量评估
- 与已确认 JD 的语义匹配评估
合并评估可以让经历评分和岗位匹配使用相同的简历上下文及证据标准。
代码位于 app/agents/review.py,Skill 位于
agent_skills/review-agent/。
该 Agent 使用 DeepSeek 独立复核 StepFun 给出的结果:
- 检查评分是否有简历原文证据。
- 检查分数范围和分项是否合理。
- 必要时修正三个总分,并记录改分理由。
- 证据仍不足时标记“建议人工复核”。
- 只复核一次,不进行无限循环。
建议环境:
- macOS 或 Linux
- Python 3.11 或更高版本
- Node.js 20 或更高版本
- npm
- Tesseract 5
检查本机环境:
python3 --version
node --version
npm --version
tesseract --version以下命令都默认从项目根目录执行。
python3 -m venv .venv
.venv/bin/pip install -r requirements.txtcd frontend
npm install
cd ..cp .env.example .env.env 已被 .gitignore 忽略,不会被正常提交到 Git。
macOS 使用 Homebrew:
brew install tesseract
brew install tesseract-lang检查中文和英文语言包:
tesseract --list-langs输出中建议至少包含:
chi_sim
eng
没有中文语言包时,系统仍会尝试英文 OCR,但中文扫描版简历的识别效果会明显 下降。
初始页面的“Agent 模型 API”区域提供三种运行方式:
| 方式 | 行为 |
|---|---|
| 环境配置 | 使用项目根目录 .env 中的 StepFun 与 DeepSeek 配置 |
| 自定义 API | 本批次输入请求地址和 API Key,验证后从接口读取模型列表 |
| 演示模式 | 不调用外部模型,直接使用本地规则完成全流程 |
自定义 API 分为两组:
- Workflow Agent 与 Evaluation Agent 共用一组 OpenAI 兼容接口和模型。
- Review Agent 使用另一组 OpenAI 兼容接口,建议选择 DeepSeek 推理模型。
填写请求地址与 API Key 后,点击“验证并读取模型”。验证通过后页面会显示模型 选择框。创建批次时后端会再次验证配置,并为该批次冻结模型选择。
右上角会持续显示:
- 当前是“正式模式”还是“演示模式”。
- Workflow Agent 使用的模型。
- Evaluation Agent 使用的模型。
- Review Agent 使用的模型。
自定义 API Key 会通过本机 /api 请求发送给后端,只保存在当前应用进程的
内存中,不会写入 SQLite、Excel、任务结果或日志。后端服务重启后无法恢复
自定义 Key;尚未完成的自定义 API 批次会自动改用演示模式。
如果模型列表接口无效、Key 无效、所选模型不存在,或实际模型调用连续失败, 系统不会中断整批任务,而会切换到演示模式,并在右上角显示本地规则模型。
项目默认使用 Mock 模式,可以在没有任何模型 API Key 的情况下运行。
确认 .env 包含:
STEP_API_KEY=
DEEPSEEK_API_KEY=
APP_MOCK_LLM=trueMock 模式中:
- PDF 文本提取和 OCR 会真实执行。
- SQLite 保存、并发处理、最终公式和 Excel 导出会真实执行。
- 简历结构化使用本地正则和关键词规则。
- 经历评分使用动作词、技术链条和量化指标等启发式规则。
- JD 匹配使用关键词及文本命中规则。
- Review 使用本地一致性检查。
Mock 模式用于验证上传、流程、页面和报告格式,不代表真实 LLM 的评估质量。 页面右上角会显示“演示模式”。
真实模式需要同时配置 StepFun 和 DeepSeek。
编辑项目根目录的 .env:
STEP_API_KEY=你的_STEPFUN_API_KEY
STEP_BASE_URL=https://api.stepfun.com/v1
STEP_MODEL=step-3.7-flash
DEEPSEEK_API_KEY=你的_DEEPSEEK_API_KEY
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_MODEL=deepseek-v4-pro
APP_MOCK_LLM=false
APP_MAX_CONCURRENCY=3
APP_RETRY_COUNT=3
APP_DATA_DIR=./data模型分工:
| Agent | 模型 |
|---|---|
| Workflow Agent | step-3.7-flash |
| Evaluation Agent | step-3.7-flash |
| Review Agent | deepseek-v4-pro |
Review Agent 会使用:
reasoning_effort="high"
extra_body={"thinking": {"type": "enabled"}}当 APP_MOCK_LLM=false 且任一 API Key 缺失时,后端会拒绝启动并说明缺少的
环境变量。
修改 .env 后必须停止并重新启动服务。启动后在首页选择“环境配置”即可使用。
后端创建批次时会通过模型列表接口验证这两组配置;验证失败会自动切换演示模式。
完成首次安装后,在项目根目录运行:
bash scripts/dev.sh脚本会同时启动:
- FastAPI:
http://127.0.0.1:8000 - React:
http://127.0.0.1:5173
浏览器访问:
停止服务:
在运行服务的终端按 Ctrl+C
以后每次启动通常只需要:
bash scripts/dev.sh不需要重复安装依赖。
调试时也可以使用两个终端分别启动。
终端一,在项目根目录启动后端:
.venv/bin/python -m uvicorn app.main:app \
--reload \
--host 127.0.0.1 \
--port 8000终端二,从项目根目录进入前端目录并启动:
cd frontend
npm run dev -- --host 127.0.0.1检查后端状态:
http://127.0.0.1:8000/api/health
正常情况下会返回类似:
{
"status": "ok",
"mock_mode": true,
"step_model": "step-3.7-flash",
"review_model": "deepseek-v4-pro",
"runtime": {
"mode": "demo",
"source": "demo",
"workflow_model": "本地规则",
"evaluation_model": "本地规则",
"review_model": "本地规则",
"message": "环境配置启用了 APP_MOCK_LLM"
}
}- 打开
http://127.0.0.1:5173。 - 选择环境配置、自定义 API 或演示模式。
- 使用自定义 API 时,分别验证两组接口并选择模型。
- 粘贴岗位 JD,或者上传 JD PDF。
- 上传 1–20 份 PDF 简历。
- 点击“分析岗位要求”。
- 编辑并确认系统整理的岗位职责和必备技能。
- 等待简历处理完成。
- 在排名表中点击候选人,查看单人详细评估。
- 点击“导出 Excel”下载汇总结果。
任务创建后,页面地址会包含:
?job=任务ID
刷新或重新打开该地址,可以恢复并查看对应批次。
总分 100,每项 20 分:
| 维度 | 关注内容 |
|---|---|
| 任务具体度 | 是否有数据处理、模型训练、接口开发、部署等具体动作 |
| 技术链条完整性 | 是否说明输入、处理流程、输出和评估方式 |
| 结果可验证性 | 是否有指标、规模、上线、用户量、论文或奖项 |
| 逻辑一致性 | 技术、时间、角色和成果之间是否合理 |
| 表述自然度 | 是否像真实参与者陈述,而非技术名词堆砌 |
“经历可信度”只表示简历文本的证据强弱与逻辑一致性,不直接判定候选人造假。
总分 100:
| 维度 | 分值 | 关注内容 |
|---|---|---|
| 问题复杂度 | 50 | 是否解决真实业务问题或技术难题 |
| 技术深度 | 50 | 是否涉及模型、算法、系统设计或性能优化 |
Evaluation Agent 对已确认的岗位职责和必备技能逐项进行语义证据对齐,最后转换 为 0–100 分。
这里是语义相关性评分,不宣称读取模型内部的真实 cross-attention 权重。
原始分 =
经历可信度 / 100 ×
(0.8 × 经历含金量 + 0.2 × 岗位匹配度)
最终分 = 原始分 + 学历加分
最终分允许超过 100。
- 本科命中 2026 QS Top 100 或清北华五:加 10 分。
- 本科未命中,但硕士命中:加 5 分。
- 本科已经加分时,硕士不重复加分。
- 华五指复旦、上海交大、浙江大学、南京大学和中国科学技术大学。
- 加分会单独显示,不混入经历或匹配评分。
学校名单位于:
config/qs-top-100-2026.txt
该文件可以直接编辑,不需要修改 Python 代码。
| 最终分 | 建议 |
|---|---|
>= 85 |
优先面试 |
70–84.99 |
建议面试 |
55–69.99 |
建议人工复核 |
< 55 |
匹配度较低 |
- 任务、评分和报告保存在本机 SQLite。
- 上传的 PDF 保存在本机
data/jobs/。 - 数据库位于
data/resume_evaluator.sqlite3。 data/和.env默认不会提交到 Git。- 姓名、邮箱和电话只用于结果展示。
- 进入 Evaluation Agent 和 Review Agent 前,上述字段会被清空。
- 性别、年龄、照片、婚育和籍贯不参与评分。
正式模式会把用于评估的简历文本发送给环境配置或首页自定义的模型 API。使用真实 候选人简历前,应确认公司的数据处理及隐私政策允许这样做。自定义 API Key 不会 写入数据库、任务结果或导出的 Excel。
默认配置:
APP_MAX_CONCURRENCY=3
APP_RETRY_COUNT=3
APP_DATA_DIR=./data- 同时最多评估 3 份简历。
- 单次模型调用失败时最多尝试 3 次。
- 模型调用重试后仍失败时,当前批次自动切换本地演示逻辑。
- PDF 无法提取等单份简历错误不会阻止其他简历继续处理。
- 失败原因会显示在任务结果中。
运行后端测试:
.venv/bin/python -m pytest -q测试覆盖:
- 三 Agent Mock 流程
- 最终评分公式
- 本科和硕士学历加分
- PDF 上传、JD 确认、评估、落库和 Excel 导出
- 自定义 API 配置校验与无效接口演示模式回退
构建前端:
cd frontend
npm run build
cd ..构建结果位于 frontend/dist/。
验证三个 Agent Skills:
.venv/bin/python scripts/validate_skills.py.
├── app/
│ ├── agents/
│ │ ├── workflow.py
│ │ ├── evaluation.py
│ │ └── review.py
│ ├── main.py
│ ├── orchestrator.py
│ ├── llm.py
│ ├── runtime.py
│ ├── pdf.py
│ ├── scoring.py
│ ├── excel.py
│ ├── db.py
│ └── schemas.py
├── agent_skills/
│ ├── workflow-agent/
│ ├── evaluation-agent/
│ └── review-agent/
├── config/
│ └── qs-top-100-2026.txt
├── frontend/
│ └── src/
├── scripts/
│ ├── dev.sh
│ └── validate_skills.py
├── tests/
├── .env.example
└── requirements.txt
尚未创建虚拟环境:
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt需要先安装 Node.js。安装后重新检查:
node --version
npm --version说明 React 页面无法访问 FastAPI。检查终端中后端是否正在运行,然后访问:
http://127.0.0.1:8000/api/health
典型日志:
[vite] http proxy error: /api/health
Error: connect ECONNREFUSED 127.0.0.1:8000
这段日志表示:
- React/Vite 已经在
127.0.0.1:5173运行。 - 前端正在把
/api/health转发给127.0.0.1:8000。 - 端口
8000没有 FastAPI 服务监听,因此连接被操作系统拒绝。
这不是 Vite 代理地址写错,通常是因为只启动了前端:
cd frontend
npm run dev推荐解决方式:
- 在当前 Vite 终端按
Ctrl+C。 - 回到项目根目录。
- 使用一键脚本同时启动前后端:
bash scripts/dev.sh新版 scripts/dev.sh 会依次:
- 检查
.venv、npm 和frontend/node_modules。 - 检查端口
8000和5173是否被占用。 - 启动 FastAPI。
- 等待
/api/health返回成功。 - 确认后端正常后再启动 Vite。
一键脚本默认不启用 FastAPI 热重载,以减少本地文件监听权限问题。需要开发时自动 重载代码,可以使用下方的双终端启动方式。
也可以使用两个终端手动启动。
终端一,在项目根目录运行:
.venv/bin/python -m uvicorn app.main:app \
--reload \
--host 127.0.0.1 \
--port 8000看到以下日志表示后端已经启动:
Uvicorn running on http://127.0.0.1:8000
终端二,在项目根目录运行:
cd frontend
npm run dev -- --host 127.0.0.1单独检查后端:
curl http://127.0.0.1:8000/api/health如果后端终端立即退出,查看退出前的错误。常见原因包括:
- 尚未创建
.venv或没有安装requirements.txt。 - 端口
8000已被其他程序占用。 - 后端命令没有从项目根目录执行。
端口 8000 或 5173 已被其他程序占用。先关闭之前启动的项目终端,再重新执行:
bash scripts/dev.sh检查 Tesseract 是否包含中文语言包:
tesseract --list-langs确认输出包含 chi_sim。
检查 .env:
STEP_API_KEY=...
DEEPSEEK_API_KEY=...
APP_MOCK_LLM=false配置后停止并重新启动服务。如果 Key、请求地址或模型无效,后端仍会正常运行, 但创建批次时会自动回退演示模式。也可以在首页选择“自定义 API”,验证接口并 重新选择模型。
这是 Mock 演示模式的启发式评分,只用于测试系统流程。查看页面右上角,如果显示 “演示模式”,结果就不是由 StepFun 和 DeepSeek 生成的正式评估。
点击页面右上方的“新建批次”,或者直接打开: