16 KiB
16 KiB
基于手机的招聘代理平台系统设计说明书
1 引言
1.1 项目背景
在互联网招聘场景中,企业普遍面临以下问题:
- 试题缺乏针对性,无法准确考察岗位所需能力;
- 试题缺乏时效性,不能反映最新项目技术栈或业务需求;
- 试题的录入与维护成本高,复用性差,题库质量难以持续优化。
为此,设计并实现一个招聘试题代理定制服务平台(下称“本平台”),以“岗位需求 + 项目场景 + 应聘者背景”为驱动,自动生成个性化试题并持续优化题库质量,为多家招聘企业提供 SaaS 级服务。
1.2 设计目标
- 提供多角色协同的在线招聘试题定制与考试平台;
- 支持岗位级别的试卷自动生成与个性化定制;
- 支持在线答题、自动评分、结果分析;
- 通过统计与反馈驱动的算法持续优化题库质量;
- 面向多租户企业,以云端部署形式提供服务。
2 业务概述与角色
2.1 业务角色
-
招聘企业 HR
- 维护岗位信息与能力要求;
- 配置试题策略(题量、题型比例、难度分布);
- 发布考试、查看统计报表;
- 对试题效果给出评价与反馈。
-
应聘者 Candidate
- 注册/登录平台;
- 选择目标岗位,领取并完成在线试卷;
- 查看成绩与解析;
- 对题目给出主观评价(难度、贴合度、清晰度等)。
-
平台管理员 Admin
- 审核企业接入与企业题库;
- 管理系统题库、试题标签、难度标注;
- 监控题目质量与淘汰策略执行;
- 管理模型训练与推荐策略。
-
内部系统模块(逻辑角色)
- Question Service:题库管理、题目 CRUD;
- Exam Service:考试流程管理、会话控制;
- Scoring Service:自动评分与统计;
- ML / Recommendation Service:试题生成与质量评估。
3 UML 视图
3.1 用例图(Use Case Diagram)
3.2 核心业务活动图(Activity Diagram)
3.3 时序图(Sequence Diagram)
3.4 类图(Class Diagram)
3.5 ER 图(实体–关系图)
4 数据结构与数据库设计
4.1 主要数据表概述
表 user
| 字段名 | 类型 | 说明 |
|---|---|---|
| id (PK) | INT | 用户 ID |
| company_id | INT (FK company.id) | 所属公司(应聘者可为空) |
| name | VARCHAR | 姓名 |
| VARCHAR (UNIQUE) | 登录邮箱 | |
| role | ENUM | HR / CANDIDATE / ADMIN |
| password_hash | VARCHAR | 加密后的密码 |
| created_at | DATETIME | 注册时间 |
表 company
| 字段名 | 类型 | 说明 |
|---|---|---|
| id (PK) | INT | 公司 ID |
| name | VARCHAR | 公司名称 |
| industry | VARCHAR | 所属行业 |
| size | VARCHAR | 规模(人数区间) |
表 candidate_profile
| 字段名 | 类型 | 说明 |
|---|---|---|
| id (PK) | INT | 主键 |
| user_id (FK) | INT | 对应 user.id |
| degree | VARCHAR | 学历 |
| years_experience | INT | 工作年限 |
| skill_tags | JSON/VARCHAR | 技能标签集合 |
| resume_url | VARCHAR | 简历文件存储地址 |
表 job_position
| 字段名 | 类型 | 说明 |
|---|---|---|
| id (PK) | INT | 岗位 ID |
| company_id (FK) | INT | 所属公司 |
| title | VARCHAR | 岗位名称 |
| level | VARCHAR | 岗位级别 |
| required_skills | JSON/VARCHAR | 要求技能标签 |
| description | TEXT | 岗位详细说明 |
| exam_policy_id | VARCHAR(FK) | 对应考试策略 ID |
表 exam_policy
| 字段名 | 类型 | 说明 |
|---|---|---|
| id (PK) | VARCHAR | 策略 ID |
| total_questions | INT | 总题量 |
| easy_ratio | FLOAT | 容易题比例 |
| medium_ratio | FLOAT | 中等题比例 |
| hard_ratio | FLOAT | 困难题比例 |
| type_ratio | JSON | 题型比例(单选/多选/编程等) |
表 question
| 字段名 | 类型 | 说明 |
|---|---|---|
| id (PK) | INT | 题目 ID |
| content | TEXT | 题干 |
| type | VARCHAR | 题目类型 |
| skill_tag | VARCHAR | 技能标签 |
| difficulty | INT | 难度等级 1–5 |
| source | VARCHAR | 来源(企业题/通用题等) |
| is_active | BOOLEAN | 是否在用 |
表 question_stats
| 字段名 | 类型 | 说明 |
|---|---|---|
| question_id(PK) | INT | 对应 question.id |
| used_count | INT | 被使用次数 |
| avg_score | FLOAT | 平均得分 |
| correct_rate | FLOAT | 正确率 |
| discrimination | FLOAT | 区分度 |
| feedback_score | FLOAT | 反馈评分均值 |
| last_used_at | DATETIME | 最近使用时间 |
表 exam_template
| 字段名 | 类型 | 说明 |
|---|---|---|
| id (PK) | INT | 试卷模板 ID |
| job_id (FK) | INT | 对应岗位 |
| policy_id (FK) | VARCHAR | 对应策略 |
| question_slots | JSON | 题目占位或题目列表 |
表 exam_session
| 字段名 | 类型 | 说明 |
|---|---|---|
| id (PK) | INT | 考试会话 ID |
| candidate_id | INT | 应聘者(user.id) |
| job_id | INT | 岗位 ID |
| template_id | INT | 使用的模板 ID |
| start_time | DATETIME | 开始时间 |
| submit_time | DATETIME | 提交时间 |
| total_score | FLOAT | 总分 |
| status | VARCHAR | ONGOING / DONE |
表 answer
| 字段名 | 类型 | 说明 |
|---|---|---|
| id (PK) | INT | 答案 ID |
| session_id | INT | 所属考试会话 |
| question_id | INT | 对应题目 |
| content | TEXT | 作答内容 |
| score | FLOAT | 得分 |
| time_taken | FLOAT | 作答耗时(秒) |
表 question_feedback
| 字段名 | 类型 | 说明 |
|---|---|---|
| id (PK) | INT | 反馈 ID |
| question_id | INT | 对应题目 |
| from_user_id | INT | 反馈人用户 ID |
| session_id | INT | 所在考试会话 |
| rating | INT | 评分(1–5) |
| comment | TEXT | 文本评价 |
| created_at | DATETIME | 创建时间 |
5 系统架构与部署设计
5.1 分层架构说明
-
客户端层(Clients)
- HR Web 前端(Vue/React SPA);
- 应聘者 Web/H5/APP;
- 通过 HTTPS 调用后端 REST API。
-
接入层(Gateway)
- Nginx 作为统一入口;
- 实现 HTTPS 终止、静态资源分发、反向代理和负载均衡。
-
应用服务层(Services)
Auth Service:登录、鉴权、Token 管理;Job & Company Service:企业与岗位管理;Question Service:题库管理、统计指标计算;Exam Service:考试流程、会话管理;Scoring Service:客观题 & 主观题自动评分;ML / Recommend Service:试题生成、质量打分、模糊定制;Admin Console:运营后台接口。
-
数据层(Data Layer)
- 关系型数据库(MySQL/PostgreSQL);
- Redis 缓存热点题目、会话状态;
- 对象存储存放题目附件、解析文档;
- 日志分析存储(ELK/ClickHouse 等)。
5.2 部署/组件图
6 核心算法设计
6.1 自适应试题生成算法
6.1.1 目标
在满足岗位需求与考试策略(题量、题型、难度分布)的前提下,为特定岗位与候选人生成一套“技能匹配度高、区分度好、不过时”的个性化试卷。
6.1.2 关键输入
job:岗位信息(required_skills、level等)policy:试题策略(题量、难度比例、题型比例)candidate_profile:候选人画像(技能标签、经验)question_bank:题库(含QuestionStats统计信息)
6.1.3 题目综合评分函数
对题目 q 计算综合得分 score(q):
skill_match:技能匹配度;difficulty_fit:难度适配度;freshness:新鲜度;discrimination:区分度;bad_feedback:负反馈惩罚。
线性组合示意:
score(q) = w1 * skill_match
+ w2 * difficulty_fit
+ w3 * freshness
+ w4 * discrimination
- w5 * bad_feedback
6.1.4 伪代码示例
def generate_exam_paper(job, policy, candidate_profile, question_bank):
# 1. 抽取岗位 & 候选人技能标签
job_skills = extract_skill_tags(job.required_skills)
cand_skills = extract_skill_tags(candidate_profile.skill_tags)
# 2. 候选题集合:技能相关 & 在用
candidates = [
q for q in question_bank
if q.is_active and overlap(q.skill_tag, job_skills | cand_skills)
]
scored_questions = []
for q in candidates:
stats = q.stats # QuestionStats
skill_match = jaccard(q.skill_tag, job_skills | cand_skills)
difficulty_fit = 1.0 - abs(q.difficulty - target_difficulty(job)) / 4.0
freshness = time_decay(now() - stats.last_used_at)
discrimination = stats.discrimination
bad_feedback = max(0, 1 - stats.feedback_score)
score = (
0.30 * skill_match +
0.25 * difficulty_fit +
0.15 * freshness +
0.25 * discrimination -
0.05 * bad_feedback
)
scored_questions.append((q, score))
# 3. 按得分排序
scored_questions.sort(key=lambda x: x[1], reverse=True)
# 4. 按策略约束(题型 + 难度 + 数量)筛选
selected = []
counters = init_counters(policy)
for q, s in scored_questions:
if not satisfy_policy(q, counters, policy):
continue
selected.append(q)
update_counters(q, counters)
if len(selected) >= policy.total_questions:
break
# 5. 生成试卷模板对象
return build_exam_paper_template(job.id, policy.id, selected)
6.2 自动评分算法
拆分为客观题与主观题评分。
6.2.1 客观题评分
- 单选/判断:完全匹配得满分;
- 多选:集合比对,可支持“部分正确部分得分”;
- 填空:字符串归一化后精确匹配。
def score_objective_question(question, candidate_answer):
correct = question.standard_answer
if question.type in ("single_choice", "true_false"):
return question.full_score if candidate_answer == correct else 0.0
if question.type == "multi_choice":
cand_set = set(candidate_answer)
corr_set = set(correct)
if cand_set == corr_set:
return question.full_score
if cand_set.issubset(corr_set):
return question.full_score * len(cand_set) / len(corr_set)
# 选错选项则记 0 分
return 0.0
if question.type == "blank":
return question.full_score if normalize(candidate_answer) == normalize(correct) else 0.0
return 0.0
6.2.2 主观题评分(规则 + 关键词覆盖率)
简化实现:基于关键词覆盖率进行线性赋分。
def score_subjective_question(question, candidate_answer):
tokens = tokenize(candidate_answer) # 分词+规范化
key_points = question.key_points # 关键点列表
hit = sum(1 for k in key_points if k in tokens)
coverage = hit / len(key_points) if key_points else 0.0
return question.full_score * coverage
6.2.3 会话总分计算
def score_exam_session(session):
total = 0.0
for answer in session.answers:
q = load_question(answer.question_id)
if q.type in ("single_choice", "multi_choice", "true_false", "blank"):
s = score_objective_question(q, answer.content)
else:
s = score_subjective_question(q, answer.content)
answer.score = s
total += s
session.total_score = total
persist_scores(session)
return total
6.3 试题质量评估与淘汰算法
6.3.1 目标
根据题目使用情况、得分表现与主观反馈,动态计算题目质量分 quality_score。当样本量充足且质量分低于阈值时,将题目标记为淘汰候选。
6.3.2 伪代码示例
def update_question_statistics(question_id):
# 1. 从数据库汇总最新统计信息
stats = aggregate_stats_from_answers_and_feedback(question_id)
# 包含:used_count, avg_score, correct_rate,
# discrimination, feedback_score, last_used_at
# 2. 计算质量分
quality = (
0.25 * stats.correct_rate +
0.35 * stats.discrimination +
0.25 * stats.feedback_score +
0.15 * freshness_factor(stats.last_used_at)
)
# 3. 更新统计表
save_question_stats(question_id, stats, quality)
# 4. 判定是否进入淘汰池
MIN_USED = 30
THRESHOLD = 0.4
if stats.used_count >= MIN_USED and quality < THRESHOLD:
mark_question_as_candidate_for_deprecation(question_id)
6.4 模糊定制题目推荐算法
6.4.1 场景
HR 只输入自然语言岗位描述(如“做高并发订单系统的 Java 后端工程师”),系统自动推荐若干候选题目供其选择。
6.4.2 思路
- 使用文本向量化(TF-IDF 或预训练 Embedding)对岗位描述和题目文本编码;
- 计算岗位向量与题目向量间的余弦相似度;
- 返回相似度最高的 Top-K 题目。
6.4.3 伪代码
def fuzzy_recommend_questions(job_free_text, question_bank, top_k=50):
job_vec = encode_text(job_free_text) # 向量化岗位描述
scored = []
for q in question_bank:
q_text = q.content + " " + q.skill_tag
q_vec = encode_text(q_text)
sim = cosine_similarity(job_vec, q_vec)
scored.append((q, sim))
scored.sort(key=lambda x: x[1], reverse=True)
return [q for q, _ in scored[:top_k]]
7 总结
本报告从业务角色与流程出发,给出了招聘试题定制平台的完整系统设计方案:
- 业务层面:明确 HR、应聘者、平台管理员等角色及其用例;
- 模型层面:通过 UML 用例图、活动图、时序图、类图与 ER 图,刻画系统的结构与行为;
- 数据层面:设计了围绕“岗位–试卷–试题–作答–反馈”的关系型数据库模型;
- 架构层面:采用客户端–接入层–服务层–数据层的分层部署方案,便于扩展与运维;
- 算法层面:给出自适应试题生成、自动评分、试题质量评估与模糊定制等核心算法的伪代码。