# 基于手机的招聘代理平台系统设计说明书 ## 1 引言 ### 1.1 项目背景 在互联网招聘场景中,企业普遍面临以下问题: * 试题缺乏针对性,无法准确考察岗位所需能力; * 试题缺乏时效性,不能反映最新项目技术栈或业务需求; * 试题的录入与维护成本高,复用性差,题库质量难以持续优化。 为此,设计并实现一个**招聘试题代理定制服务平台**(下称“本平台”),以“岗位需求 + 项目场景 + 应聘者背景”为驱动,自动生成个性化试题并持续优化题库质量,为多家招聘企业提供 SaaS 级服务。 ### 1.2 设计目标 * 提供**多角色协同**的在线招聘试题定制与考试平台; * 支持**岗位级别的试卷自动生成**与个性化定制; * 支持**在线答题、自动评分、结果分析**; * 通过**统计与反馈驱动的算法**持续优化题库质量; * 面向多租户企业,以云端部署形式提供服务。 ## 2 业务概述与角色 ### 2.1 业务角色 1. **招聘企业 HR** * 维护岗位信息与能力要求; * 配置试题策略(题量、题型比例、难度分布); * 发布考试、查看统计报表; * 对试题效果给出评价与反馈。 2. **应聘者 Candidate** * 注册/登录平台; * 选择目标岗位,领取并完成在线试卷; * 查看成绩与解析; * 对题目给出主观评价(难度、贴合度、清晰度等)。 3. **平台管理员 Admin** * 审核企业接入与企业题库; * 管理系统题库、试题标签、难度标注; * 监控题目质量与淘汰策略执行; * 管理模型训练与推荐策略。 4. **内部系统模块(逻辑角色)** * **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 | 姓名 | | email | 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 分层架构说明 1. **客户端层(Clients)** * HR Web 前端(Vue/React SPA); * 应聘者 Web/H5/APP; * 通过 HTTPS 调用后端 REST API。 2. **接入层(Gateway)** * Nginx 作为统一入口; * 实现 HTTPS 终止、静态资源分发、反向代理和负载均衡。 3. **应用服务层(Services)** * `Auth Service`:登录、鉴权、Token 管理; * `Job & Company Service`:企业与岗位管理; * `Question Service`:题库管理、统计指标计算; * `Exam Service`:考试流程、会话管理; * `Scoring Service`:客观题 & 主观题自动评分; * `ML / Recommend Service`:试题生成、质量打分、模糊定制; * `Admin Console`:运营后台接口。 4. **数据层(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`:负反馈惩罚。 线性组合示意: ```text score(q) = w1 * skill_match + w2 * difficulty_fit + w3 * freshness + w4 * discrimination - w5 * bad_feedback ``` #### 6.1.4 伪代码示例 ```python 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 客观题评分 * 单选/判断:完全匹配得满分; * 多选:集合比对,可支持“部分正确部分得分”; * 填空:字符串归一化后精确匹配。 ```python 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 主观题评分(规则 + 关键词覆盖率) 简化实现:基于关键词覆盖率进行线性赋分。 ```python 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 会话总分计算 ```python 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 伪代码示例 ```python 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 思路 1. 使用文本向量化(TF-IDF 或预训练 Embedding)对岗位描述和题目文本编码; 2. 计算岗位向量与题目向量间的余弦相似度; 3. 返回相似度最高的 Top-K 题目。 #### 6.4.3 伪代码 ```python 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 图,刻画系统的结构与行为; * **数据层面**:设计了围绕“岗位–试卷–试题–作答–反馈”的关系型数据库模型; * **架构层面**:采用客户端–接入层–服务层–数据层的分层部署方案,便于扩展与运维; * **算法层面**:给出自适应试题生成、自动评分、试题质量评估与模糊定制等核心算法的伪代码。