# job-backend **Repository Path**: happy_source/job-backend ## Basic Information - **Project Name**: job-backend - **Description**: agent 智能招聘系统 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-06-17 - **Last Updated**: 2026-06-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: 知了课堂 ## README # HR Backend 基于 FastAPI + LangGraph 的 AI 驱动招聘管理系统后端。覆盖职位发布、简历上传与 OCR 解析、候选人全流程管理、AI 评分、面试安排,并通过邮件机器人 + 钉钉日历实现面试时间的自动协商与日程创建。 ## 技术栈 | 分类 | 技术 | | ------------- | --------------------------------------------------------- | | 语言 / 运行时 | Python ≥ 3.13,[uv](https://docs.astral.sh/uv/) 包管理 | | Web 框架 | FastAPI(异步)、Uvicorn | | 数据库 | PostgreSQL + SQLAlchemy 2.0(async)+ psycopg | | 数据库迁移 | Alembic(async 模板) | | 缓存 | Redis + fastapi-cache3 | | 认证 | JWT(PyJWT)+ 密码哈希(pwdlib / argon2) | | AI / Agent | LangChain + LangGraph,Postgres Checkpoint 持久化会话状态 | | 定时任务 | APScheduler(邮件轮询) | | OCR | 百度 PaddleOCR、SiliconFlow OCR(降级方案) | | 文档处理 | PyMuPDF、Word 转 PDF | | 第三方 | 钉钉(OAuth 登录 + 日历日程)、IMAP/SMTP 邮件机器人 | ## 项目结构 ``` hr-backend/ ├── main.py # FastAPI 入口,lifespan 初始化 Redis 缓存与邮件轮询调度 ├── init_data.py # 初始化部门与测试用户数据 ├── settings/ # 配置(pydantic-settings,读取 .env) ├── models/ # SQLAlchemy ORM 模型(user / position / candidate / interview) ├── schemas/ # Pydantic 请求 / 响应模型 ├── routers/ # 路由层 │ ├── user_router.py # 用户、部门、钉钉授权 │ ├── position_router.py # 职位管理 │ ├── candidate_router.py # 候选人、简历上传与解析、AI 评分 │ ├── dashboard_router.py # 数据统计 │ └── media_router.py # 静态文件(简历 PDF,带 token 校验) ├── repository/ # 数据访问层(user / position / candidate / interview) ├── dependencies/ # FastAPI 依赖注入(DB 会话、认证、缓存、当前用户、超级用户) ├── core/ # 核心能力 │ ├── auth.py # JWT 编解码(access / refresh token) │ ├── cache.py # Redis 缓存封装(邀请码、钉钉 token、任务状态、邮件 UID) │ ├── mail.py # 系统通知邮件 │ ├── dingtalk.py # 钉钉 API(token 刷新、日历日程) │ ├── ocr.py # PaddleOCR / SiliconFlow OCR │ ├── pdf.py # Word 转 PDF │ ├── single.py # 线程安全单例元类 │ └── email_bot/ # IMAP/SMTP 邮件机器人(收发邮件) ├── agents/ # AI Agent │ ├── llms.py # DeepSeek / GLM 模型实例 │ ├── resume.py # 简历信息抽取 Agent │ ├── candidate.py # 候选人处理 Agent(评分 / 协调面试) │ └── prompts.py # 各 Agent 系统提示词 ├── tasks/ # 后台任务(发邮件、OCR 解析简历、运行候选人 Agent) ├── scheduler/ # APScheduler 邮件轮询调度 ├── utils/ # 工具(ISO8601 时间转换、可用面试时段计算) ├── templates/ # Jinja2 模板(钉钉授权成功页) ├── alembic/ # 数据库迁移脚本 └── data/ # Redis 配置与持久化数据 ``` ## 核心功能 - **用户与权限**:邮箱密码登录(JWT 双 token)、邀请码注册、员工状态管理、部门管理、HR 列表、部门分配;区分 `superuser` / `hr` / 普通用户权限。 - **钉钉集成**:OAuth 授权登录、获取钉钉账号、读取面试官日历日程、为面试官创建面试日程。 - **职位管理**:创建 / 列表 / 删除职位(按部门隔离权限)。 - **候选人招聘全流程**: - 简历上传(支持图片 / PDF / Word,Word 自动转 PDF)。 - OCR 解析(PaddleOCR 优先,失败降级 SiliconFlow)+ LLM 抽取候选人结构化信息。 - AI 评分(工作经验、技术、软技能、学历、项目等多维度打分),分数 > 8 自动通过 AI 筛选。 - 候选人状态单向流转管理。 - **AI Agent 自动化**(LangGraph):候选人评分 → 查询面试官空闲时段 → 发送面试协商邮件 → 确认时间后创建钉钉日程与系统面试记录。会话状态通过 Postgres Checkpoint 持久化。 - **邮件机器人**:定时轮询收件箱,由 Agent 处理候选人邮件回复(如确认 / 改期),实现多轮协商。 - **数据看板**:最近 7 天新增候选人统计。 - **静态文件**:简历文件访问,通过 query 参数携带 access token 鉴权,并做路径穿越防护。 ### 候选人状态流转 ``` 已投递 → AI筛选失败 已投递 → AI筛选成功 → 待面试 → 拒绝面试 → 面试通过 → 已入职 → 面试未通过 → 已拒绝 ``` ## 快速开始 ### 1. 环境准备 - Python ≥ 3.13 - [uv](https://docs.astral.sh/uv/) - PostgreSQL - Redis ### 2. 安装依赖 ```shell uv sync ``` ### 3. 配置环境变量 复制 `.env.example` 为 `.env`,按需填写: ```shell cp .env.example .env ``` 关键配置项(详见 `settings/__init__.py`): | 变量 | 说明 | | ----------------------------------------------------------------- | ----------------------------------------------------- | | `DB_USERNAME` / `DB_PASSWORD` / `DB_HOST` / `DB_PORT` / `DB_NAME` | 主业务库(默认 `hr_system`) | | `DB_AGENT_NAME` | LangGraph Checkpoint 状态库(默认 `hr_system_agent`) | | `REDIS_HOST` / `REDIS_PORT` | Redis 连接 | | `JWT_SECRET_KEY` | JWT 签名密钥 | | `MAIL_USERNAME` / `MAIL_PASSWORD` | 系统邮件与邮件机器人账号(163 邮箱默认) | | `DINGTALK_CLIENT_ID` / `DINGTALK_CLIENT_SECRET` | 钉钉应用凭证 | | `BACKEND_BASE_URL` | 后端域名(用于钉钉授权回调) | | `DEEPSEEK_API_KEY` / `ZHIPU_API_KEY` / `SILICONFLOW_API_KEY` | LLM / OCR 服务密钥 | | `PADDLE_OCR_ACCESS_TOKEN` | 百度 PaddleOCR token | ### 4. 启动 Redis 在 `data/` 目录下(参考 `data/README.md`): ```shell cd data docker run -d \ -v ./job_redis_data_dev:/data \ -v ./redis.conf:/etc/redis/redis.conf \ -p 6379:6379 \ --name job-redis-dev \ redis:8.2 \ redis-server /etc/redis/redis.conf ``` ### 5. 创建数据库 在 PostgreSQL 中预先创建两个数据库: ```sql CREATE DATABASE hr_system; CREATE DATABASE hr_system_agent; ``` ### 6. 数据库同步 **① 创建 alembic 仓库** 执行以下命令创建 alembic 仓库: ```shell alembic init alembic --template async ``` 首先将项目根路径下的 `alembic.ini` 中的 `sqlalchemy.url` 注释: ```ini # sqlalchemy.url = ``` 然后在 `alembic/env.py` 中将代码修改为以下: ```python ... # 新增的导入包 from models import Base from settings import settings import asyncio import sys if sys.platform == "win32": asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) config = context.config # 添加连接数据库的配置 database_url = settings.DATABASE_URL if database_url is None: raise ValueError("DB_URI没有设置!") config.set_main_option("sqlalchemy.url", database_url) # Interpret the config file for Python logging. # This line sets up loggers basically. if config.config_file_name is not None: fileConfig(config.config_file_name) # add your model's MetaData object here # for 'autogenerate' support # from myapp import mymodel # target_metadata = mymodel.Base.metadata target_metadata = Base.metadata ... ``` **② 生成迁移脚本** 执行以下命令,将 ORM 模型生成迁移脚本: ```shell alembic revision --autogenerate -m "init model" ``` **③ 执行迁移脚本** 执行以下命令,将上一步生成的迁移脚本同步到数据库中: ```shell alembic upgrade head ``` ### 7. 初始化部门与测试用户 ```shell python init_data.py ``` 会创建 8 个部门(人事 / 技术 / 运营 / 市场 / 财务 / 法务 / 行政 / 客服)及若干测试用户,超级管理员账号: - 邮箱:`boss@qq.com` - 密码:`111111` ### 8. 启动服务 ```shell uvicorn main:app --reload ``` 默认监听 `http://127.0.0.1:8000`,API 文档位于 `http://127.0.0.1:8000/docs`。 ## 生产环境部署 生产环境基于 Docker 部署,配套 PostgreSQL 与 Redis 作为外部服务,敏感配置通过**环境变量注入**而非打包进镜像。 ### 1. 构建镜像 ```shell docker build -t hr-backend:latest . ``` 默认镜像不含 LibreOffice(最小,约 600–800MB)。如需支持 Word(.doc/.docx)简历转 PDF,构建时加参数: ```shell docker build --build-arg INSTALL_LIBREOFFICE=1 -t hr-backend:latest . ``` ### 2. 配置环境变量 镜像**不包含 .env**(已被 .dockerignore 排除)。项目使用 pydantic-settings,加载优先级为**环境变量 > .env 文件 > 默认值**,容器内无 .env 文件时自动读取环境变量,因此通过环境变量注入即可。 推荐方式: | 场景 | 方式 | | ---- | ------------------------------------------------------------------------------------------------------- | | 单机 | 宿主机维护 `.env`,`docker run -v .env:/app/.env:ro`
(文件不进镜像,仅宿主机读取后注入为环境变量) | | 编排 | docker compose 的 `env_file:` / `environment:` | | 集群 | Kubernetes Secret / HashiCorp Vault / 云厂商 KMS | 敏感变量(`DB_PASSWORD`、`JWT_SECRET_KEY`、`DEEPSEEK_API_KEY`、`ZHIPU_API_KEY`、`SILICONFLOW_API_KEY`、`PADDLE_OCR_ACCESS_TOKEN`、`MAIL_PASSWORD`、`DINGTALK_CLIENT_SECRET`)禁止提交到 git 或打进镜像。 ### 3. docker-compose 部署示例 以下编排整合 PostgreSQL + Redis + 后端,可直接作为生产参考: ```yaml services: db: image: postgres:17 environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: hr_system volumes: - pg-data:/var/lib/postgresql/data restart: unless-stopped redis: image: redis:8 command: ["redis-server", "--appendonly", "yes"] volumes: - redis-data:/data restart: unless-stopped app: image: hr-backend:latest env_file: .env environment: DB_HOST: db REDIS_HOST: redis volumes: - upload-data:/app/upload ports: - "8000:8000" depends_on: [db, redis] restart: unless-stopped volumes: pg-data: redis-data: upload-data: ``` > LangGraph checkpointer 需要第二个数据库 `hr_system_agent`,需在 PostgreSQL 中单独创建。可在 db 服务挂载初始化脚本到 `/docker-entrypoint-initdb.d/` 自动建库。 启动: ```shell docker compose up -d ``` ### 4. 数据库迁移与初始化 首次部署或版本升级时执行迁移: ```shell docker compose exec app alembic upgrade head ``` 首次部署初始化部门与超级管理员: ```shell docker compose exec app python init_data.py ``` ### 5. 注意事项 - **单进程运行**:lifespan 内启动了全局 APScheduler(邮件轮询)与 LangGraph checkpointer,容器必须单进程,已固化在 Dockerfile CMD 中,禁止覆盖为多 worker,否则邮件轮询会重复执行。 - **数据持久化**:`/app/upload`(简历文件)必须挂载 volume,否则容器重建会丢失文件。 - **反向代理**:生产建议前置 Nginx,并覆盖启动命令启用代理头识别: ```yaml command: [ "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--proxy-headers", "--forwarded-allow-ips", "*", ] ``` ## API 概览 | 模块 | 前缀 | 主要接口 | | -------- | ---------------- | ------------------------------------------------------------------- | | 用户 | `/user` | 登录、邀请、注册、员工列表、状态修改、部门列表、HR 列表、分配部门 | | 钉钉 | `/user/dingtalk` | 授权 URL、OAuth 回调、获取钉钉账号 | | 职位 | `/position` | 创建、列表、删除 | | 候选人 | `/candidate` | 简历上传、简历解析(异步任务)、候选人创建、列表、状态更新、AI 评分 | | 看板 | `/dashboard` | 最近 7 天候选人统计 | | 静态文件 | `/media` | 简历文件访问(query 参数 `token` 鉴权) | ## 备注 - 项目使用两个数据库:`hr_system`(业务数据)与 `hr_system_agent`(LangGraph 会话状态),需分别创建。 - 邮件机器人与系统通知共用 `MAIL_USERNAME` 账号,默认使用 163 邮箱(IMAP / SMTP)。 - 候选人状态只能单向向后流转,前端更新状态时需遵守 `candidate_router.py` 中定义的状态机顺序。 ## License 本项目基于 [MIT License](./LICENSE) 开源。