ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于BERT-BiLSTM-CRF与文本相似度的智能招聘推荐系统毕业设计实践

基于BERT-BiLSTM-CRF与文本相似度的智能招聘推荐系统毕业设计实践 如果你正在为毕业设计选题发愁或者想做一个既有技术深度又有实际应用价值的项目那么“基于深度学习的智能招聘推荐系统”绝对是一个能让你在答辩时脱颖而出的选择。它听起来高大上但核心逻辑其实很清晰用AI模型读懂简历和职位描述然后精准地匹配它们。这不仅是NLP自然语言处理技术的典型应用更切中了当前招聘市场的真实痛点——海量信息下的低效筛选。很多人以为这类项目门槛极高需要复杂的算法和庞大的算力。但事实是借助像BERT这样的预训练模型我们可以在相对有限的资源下快速搭建一个效果不错的原型系统。本文将为你完整拆解一个融合了BERT-BiLSTM-CRF命名实体识别、文本相似度计算以及前后端可视化的毕业设计项目。你不仅能拿到可运行的源码更能理解从数据处理、模型训练到系统集成的全链路逻辑真正做到“知其然也知其所以然”。1. 这篇文章真正要解决的问题毕业设计的核心矛盾是什么是“技术新颖性”、“工作量饱满度”与“个人可实现性”之间的平衡。选择一个纯理论算法研究可能难以落地展示做一个简单的CRUD管理系统又缺乏技术亮点。智能招聘推荐系统恰好解决了这个矛盾技术深度足够涉及前沿的预训练语言模型BERT、序列标注模型BiLSTM-CRF、以及相似度匹配算法技术栈丰富。应用价值明确解决了简历与职位匹配的效率问题有清晰的应用场景和商业逻辑容易在答辩中阐述价值。可视化展示性强最终成果是一个包含前端页面的完整系统可以直观地进行“输入-处理-输出”的演示远比只展示一个算法准确率数字要生动。学习路径清晰项目模块化程度高可以分步攻克数据爬取/处理 → 模型训练与评估 → 后端API开发 → 前端界面实现。本文将围绕“BERT-BiLSTM-CRF用于简历信息抽取”和“文本相似度用于智能匹配”这两个核心模块展开带你从零搭建整个系统并重点剖析那些容易踩坑的细节。2. 基础概念与核心原理在动手之前我们需要厘清几个关键概念理解它们是如何在这个系统中协同工作的。2.1 BERT文本的“理解者”BERTBidirectional Encoder Representations from Transformers是一种预训练语言模型。你可以把它想象成一个博览群书海量互联网文本的语言专家。它的核心能力是为文本中的每个词或字生成一个富含上下文信息的向量表示Embedding。为什么用BERT传统方法如Word2Vec无法很好地处理一词多义。例如“Java”在简历中可能是编程语言也可能是地理名词。BERT能根据上下文动态调整“Java”的向量表示从而更精准地理解语义。在本项目中的作用我们将使用BERT来获取简历文本和职位描述JD的深度语义表示这是后续进行相似度计算的基础。同时BERT提取的特征也可以作为序列标注模型的输入。2.2 BiLSTM-CRF信息的“抽取者”这是一个经典的序列标注模型组合常用于命名实体识别NER。BiLSTM双向长短期记忆网络擅长捕捉文本序列中的长距离上下文依赖。双向意味着它同时考虑了一个词的前文和后文信息。CRF条件随机场在BiLSTM的输出之上CRF层可以学习标签之间的转移规则例如在“B-PER”人名开始之后更可能是“I-PER”人名内部而不是“O”非实体从而保证预测出的实体标签序列在整体上是最优、最合理的。在本项目中的作用我们用它从简历文本中结构化地抽取关键信息例如姓名、电话、邮箱用于系统录入或去重技能如Python, TensorFlow、项目经验、教育背景工作年限、期望职位抽取出的结构化信息是进行精准匹配和筛选的重要维度。2.3 文本相似度计算匹配的“裁判”有了文本的向量表示来自BERT和结构化信息来自NER我们需要一个方法来量化简历和职位描述的匹配程度。余弦相似度最常用的方法之一。计算两个文本向量在空间中的夹角余弦值值越接近1语义越相似。匹配策略整体语义匹配将整份简历和整个JD通过BERT编码计算向量间的余弦相似度。关注宏观的匹配度。关键信息匹配针对NER抽出的“技能”、“项目经验”等与JD中要求的“任职资格”、“技能要求”进行关键词匹配或更精细的语义匹配。这能确保硬性条件的满足。综合排序将上述多种相似度得分进行加权融合得到最终的综合匹配分用于排序推荐。2.4 系统架构全景图理解了核心组件我们来看它们如何组成一个完整的系统用户前端 (Web页面) ↓ (提交简历/选择职位) 后端服务 (Flask/Django) ↓ 1. 简历解析模块 ├── 文本提取 (解析PDF/Word) └── NER信息抽取 (BERT-BiLSTM-CRF模型) ↓ 2. 职位库 简历库 (数据库: MySQL/PostgreSQL) ↓ 3. 智能匹配引擎 ├── 文本向量化 (BERT) ├── 相似度计算 (余弦相似度等) └── 综合排序算法 ↓ 4. 结果返回与可视化 └── 匹配列表、详情、图表 (Echarts等)这个架构清晰地将数据处理、AI模型和服务应用解耦便于开发和维护。3. 环境准备与前置条件工欲善其事必先利其器。以下是搭建本项目开发环境所需的清单。3.1 硬件与操作系统建议CPU: 建议4核以上。内存: 至少8GB16GB或以上为佳用于加载BERT模型和数据处理。GPU(可选但强烈推荐): 拥有一块NVIDIA GPU如GTX 1060 6G或更高将极大加速模型训练和推理过程。如果没有GPUCPU也可运行但速度会慢很多。操作系统: Ubuntu 18.04/20.04 LTS 或 Windows 10/11 (需配置WSL2或直接使用)。本文示例以Ubuntu环境为主Windows用户需注意路径差异。3.2 软件与工具安装Python环境: 使用conda或venv创建独立的Python环境避免包冲突。推荐Python 3.8或3.9。# 使用conda创建环境 conda create -n job_recommend python3.8 conda activate job_recommend # 或者使用venv python -m venv job_recommend_env source job_recommend_env/bin/activate # Linux/Mac # job_recommend_env\Scripts\activate # Windows深度学习框架: 我们使用PyTorch因其动态图特性对研究和实验友好。# 访问PyTorch官网 (https://pytorch.org/get-started/locally/) 获取最适合你环境的安装命令。 # 例如对于CUDA 11.3的Linux系统 pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113 # 对于仅CPU的环境 # pip install torch torchvision torchaudio关键Python库:pip install transformers # Hugging Face库用于加载BERT模型 pip install seqeval # 用于序列标注任务评估 pip install flask # 轻量级后端框架 pip install pandas numpy scikit-learn # 数据处理和相似度计算 pip install jieba # 中文分词如果处理中文简历 pip install pymupdf # 解析PDF简历比pdfminer更友好 # 数据库驱动根据选择而定 pip install pymysql # MySQL # pip install psycopg2-binary # PostgreSQL前端相关(可选如果你计划独立开发前端):Node.js npmVue.js / React 相关脚手架数据库: 安装MySQL或PostgreSQL并创建一个名为job_recommend_db的数据库。3.3 数据准备简历数据: 由于隐私问题很难获取真实简历。可以通过以下方式构建模拟数据集从招聘网站遵守robots.txt爬取公开的职位描述将其部分内容改写为“简历”格式。使用开源的中文简历数据集如ResumeNER或英文数据集。手动构造编写脚本根据模板随机生成包含姓名、技能、经历等字段的模拟简历文本。职位数据: 可以从拉勾、BOSS直聘等网站爬取注意频率和版权或使用开源的职位数据集。关键字段包括职位名称、公司、职位描述、技能要求、学历要求、工作经验等。4. 核心流程拆解从文本到推荐让我们将整个项目分解为可执行的步骤。4.1 第一步数据预处理与标注这是所有NLP项目的基础也是最繁琐但至关重要的一步。文本清洗: 去除简历/JD中的HTML标签、特殊字符、多余空格等。分词(针对中文): 使用jieba进行分词。对于NER有时按字character划分效果更好。序列标注:定义标签体系。例如采用BIO或BIOES标注法。BIO: B-实体开始I-实体内部O-非实体。示例句子: “熟练掌握Python和Java编程。”标注后:熟/O 练/O 掌/O 握/O Python/B-SKILL 和/O Java/B-SKILL 编/O 程/O 。/O你需要对一定数量的简历句子进行人工或半自动的标注形成训练集和测试集。4.2 第二步训练BERT-BiLSTM-CRF模型我们将使用Hugging Face的transformers库轻松加载BERT并自定义后面的BiLSTM和CRF层。加载预训练BERT: 选择适合你语言的模型如中文可选bert-base-chinese。构建模型架构:BERT层负责获取每个字符/词的上下文向量。接一个BiLSTM层进一步捕捉序列特征。最后接一个CRF层输出最优标签序列。训练循环: 定义损失函数CRF负对数似然损失、优化器如AdamW在训练集上迭代在验证集上评估性能使用seqeval计算精确率、召回率、F1值。4.3 第三步构建文本相似度匹配模块文本向量化:对于一份简历和一个JD分别用BERT模型不微调或微调后的均可获取它们的句子级表示。通常取[CLS]标记的向量或所有标记向量的平均作为句子向量。计算相似度:计算两个句子向量的余弦相似度得到基础匹配分。融合关键信息:利用NER模块抽出的简历技能列表与JD的技能要求列表进行匹配。可以采用Jaccard相似度或词向量平均后计算相似度。为“整体语义相似度”和“技能匹配度”分配不同的权重加权求和得到最终得分。4.4 第四步搭建后端API服务使用Flask或FastAPI创建RESTful API。POST /api/upload_resume: 接收上传的简历文件PDF/Word调用解析和NER模块将结构化信息存入数据库。GET /api/jobs: 获取所有职位列表。POST /api/match: 传入简历ID或文本返回匹配度排序后的职位列表及详情。GET /api/visualize/{resume_id}: 返回用于前端图表的数据如技能匹配雷达图。4.5 第五步开发前端可视化界面一个简洁的前端可以极大提升项目展示效果。页面1: 简历上传与管理文件上传区域展示已解析出的结构化信息如技能、经验。页面2: 职位浏览与推荐以卡片或列表形式展示职位按匹配度从高到低排序。每个职位卡片显示匹配分数、关键匹配点如“技能匹配度90%”。页面3: 匹配详情可视化使用Echarts绘制雷达图直观对比简历与某职位在“技能”、“经验”、“学历”等维度的匹配情况。5. 完整示例与代码实现让我们聚焦于最核心的模型部分看代码如何实现。5.1 数据标注示例 (data/train.txt)文件内容格式为每行“字符 标签”句子之间空行分隔。张 B-NAME 三 I-NAME O 男 B-GENDER O 应 O 聘 O 机 B-TITLE 器 I-TITLE 学 I-TITLE 习 I-TITLE 工 B-TITLE 程 I-TITLE 师 I-TITLE 。 O 熟 O 练 O 掌 O 握 O P B-SKILL y I-SKILL t I-SKILL h I-SKILL o I-SKILL n I-SKILL O T B-SKILL e I-SKILL n I-SKILL s I-SKILL o I-SKILL r I-SKILL F I-SKILL l I-SKILL o I-SKILL w I-SKILL 。 O5.2 BERT-BiLSTM-CRF模型定义 (model/bert_bilstm_crf.py)import torch import torch.nn as nn from transformers import BertModel, BertConfig from torchcrf import CRF class BertBiLSTMCRF(nn.Module): def __init__(self, bert_path, num_tags, lstm_hidden256, lstm_layers1, dropout0.1): super(BertBiLSTMCRF, self).__init__() # 加载预训练BERT self.bert BertModel.from_pretrained(bert_path) bert_hidden_size self.bert.config.hidden_size # 双向LSTM层 self.bilstm nn.LSTM( input_sizebert_hidden_size, hidden_sizelstm_hidden, num_layerslstm_layers, bidirectionalTrue, batch_firstTrue, dropoutdropout if lstm_layers 1 else 0 ) # 全连接层将LSTM输出映射到标签空间 self.fc nn.Linear(lstm_hidden * 2, num_tags) # 双向所以*2 # CRF层 self.crf CRF(num_tags, batch_firstTrue) self.dropout nn.Dropout(dropout) def forward(self, input_ids, attention_mask, labelsNone): # BERT编码 bert_outputs self.bert(input_idsinput_ids, attention_maskattention_mask) sequence_output bert_outputs.last_hidden_state # [batch, seq_len, hidden] sequence_output self.dropout(sequence_output) # BiLSTM编码 lstm_output, _ self.bilstm(sequence_output) # [batch, seq_len, hidden*2] lstm_output self.dropout(lstm_output) # 全连接层得到发射分数 emissions self.fc(lstm_output) # [batch, seq_len, num_tags] # 计算损失或预测 if labels is not None: # 训练模式计算CRF负对数似然损失 # mask需要将padding部分忽略 loss -self.crf(emissions, labels, maskattention_mask.bool(), reductionmean) return loss else: # 预测模式使用维特比算法解码最优路径 best_paths self.crf.decode(emissions, maskattention_mask.bool()) return best_paths # 假设标签数量包含O标签 num_tags 9 # 例如: O, B-NAME, I-NAME, B-SKILL, I-SKILL, B-EXP, I-EXP, B-EDU, I-EDU model BertBiLSTMCRF(bert_pathbert-base-chinese, num_tagsnum_tags) print(model)5.3 相似度计算模块 (utils/similarity.py)import numpy as np from sklearn.metrics.pairwise import cosine_similarity from transformers import BertTokenizer, BertModel import torch class TextSimilarity: def __init__(self, model_namebert-base-chinese): self.tokenizer BertTokenizer.from_pretrained(model_name) self.model BertModel.from_pretrained(model_name) self.model.eval() # 设置为评估模式 def get_embedding(self, text): 获取文本的BERT句子向量[CLS]向量 inputs self.tokenizer(text, return_tensorspt, truncationTrue, paddingTrue, max_length512) with torch.no_grad(): outputs self.model(**inputs) # 取[CLS]位置的向量作为句子表示 cls_embedding outputs.last_hidden_state[:, 0, :].squeeze().numpy() return cls_embedding def cosine_sim(self, text1, text2): 计算两段文本的余弦相似度 emb1 self.get_embedding(text1).reshape(1, -1) emb2 self.get_embedding(text2).reshape(1, -1) similarity cosine_similarity(emb1, emb2)[0][0] return similarity def match_resume_jd(self, resume_text, jd_text, skills_from_resume, skills_from_jd): 综合匹配函数 :param resume_text: 简历全文 :param jd_text: 职位描述全文 :param skills_from_resume: NER抽取的简历技能列表如 [Python, 机器学习] :param skills_from_jd: 从JD中提取的技能要求列表 :return: 综合匹配分数 # 1. 整体语义相似度 semantic_score self.cosine_sim(resume_text, jd_text) # 2. 技能匹配度 (Jaccard相似度) set_resume_skills set(skills_from_resume) set_jd_skills set(skills_from_jd) if len(set_jd_skills) 0: skill_score 1.0 # 如果JD未列技能则此项不计入惩罚 else: intersection set_resume_skills.intersection(set_jd_skills) union set_resume_skills.union(set_jd_skills) skill_score len(intersection) / len(union) if union else 0 # 3. 加权综合 (权重可根据业务调整) final_score 0.6 * semantic_score 0.4 * skill_score return { final_score: round(final_score, 4), semantic_score: round(semantic_score, 4), skill_score: round(skill_score, 4), matched_skills: list(intersection) } # 使用示例 sim_calculator TextSimilarity() resume 五年Python开发经验精通Django框架有机器学习项目经历。 jd 招聘高级Python后端工程师要求熟悉Django有大数据处理经验者优先。 resume_skills [Python, Django, 机器学习] jd_skills [Python, Django, 大数据] result sim_calculator.match_resume_jd(resume, jd, resume_skills, jd_skills) print(f匹配结果: {result})5.4 Flask后端API核心路由示例 (app/main.py)from flask import Flask, request, jsonify from utils.resume_parser import parse_resume_pdf # 假设的简历解析函数 from model.bert_bilstm_crf import BertBiLSTMCRF # 导入模型 from utils.similarity import TextSimilarity import joblib # 用于加载模型 import torch app Flask(__name__) # 加载模型 (示例实际需根据训练好的模型路径加载) device torch.device(cuda if torch.cuda.is_available() else cpu) ner_model BertBiLSTMCRF(bert_path./model/bert-base-chinese, num_tags9) ner_model.load_state_dict(torch.load(./model/best_ner_model.pth, map_locationdevice)) ner_model.to(device) ner_model.eval() similarity_model TextSimilarity() # 模拟数据库中的职位列表 job_database [ {id: 1, title: Python后端工程师, jd: 负责后端系统开发要求精通Python和Django..., required_skills: [Python, Django, MySQL]}, {id: 2, title: 机器学习算法工程师, jd: 负责推荐算法研发要求熟悉TensorFlow/PyTorch..., required_skills: [Python, 机器学习, TensorFlow]}, # ... 更多职位 ] app.route(/api/upload_resume, methods[POST]) def upload_resume(): 上传并解析简历 if file not in request.files: return jsonify({error: No file part}), 400 file request.files[file] if file.filename : return jsonify({error: No selected file}), 400 # 1. 解析简历文本 resume_text parse_resume_pdf(file) # 解析PDF/Word # 2. NER信息抽取 # 将文本转换为模型输入格式 (此处简化实际需要tokenize和padding) # inputs tokenizer(resume_text, ...) # with torch.no_grad(): # predicted_tags ner_model(inputs) # extracted_info convert_tags_to_entities(predicted_tags, resume_text) # 模拟抽取结果 extracted_info { name: 张三, skills: [Python, Django, 机器学习], experience: 5年, education: 本科 } # 3. 存储到数据库 (此处省略数据库操作) # db.save_resume(extracted_info) resume_id 1001 # 模拟生成的简历ID return jsonify({resume_id: resume_id, extracted_info: extracted_info}) app.route(/api/match/int:resume_id, methods[GET]) def match_jobs(resume_id): 为指定简历匹配职位 # 1. 从数据库获取简历信息 (此处用模拟数据) resume_info { text: 五年Python开发经验精通Django框架有机器学习项目经历。, skills: [Python, Django, 机器学习] } matched_results [] for job in job_database: # 2. 计算匹配度 match_result similarity_model.match_resume_jd( resume_info[text], job[jd], resume_info[skills], job[required_skills] ) matched_results.append({ job_id: job[id], job_title: job[title], **match_result # 展开匹配分数等详情 }) # 3. 按最终得分排序 matched_results.sort(keylambda x: x[final_score], reverseTrue) return jsonify({resume_id: resume_id, matched_jobs: matched_results}) if __name__ __main__: app.run(debugTrue, host0.0.0.0, port5000)6. 运行结果与效果验证6.1 模型训练验证启动模型训练脚本后你会在控制台看到类似以下的输出表明模型正在学习Epoch 1/10, Step 100/500, Loss: 2.3456, F1: 0.6543 Epoch 2/10, Step 200/500, Loss: 1.8765, F1: 0.7234 ... Epoch 10/10, Step 500/500, Loss: 0.2345, F1: 0.9123训练完成后在测试集上评估应能得到一个较高的F1分数例如0.85这表明你的NER模型能较准确地识别出简历中的实体。6.2 API服务验证启动Flask应用后使用curl或Postman测试API。启动服务:python app/main.py输出:* Running on http://0.0.0.0:5000/ (Press CTRLC to quit)测试匹配接口:curl -X GET http://127.0.0.1:5000/api/match/1001预期返回的JSON响应:{ resume_id: 1001, matched_jobs: [ { job_id: 1, job_title: Python后端工程师, final_score: 0.8721, semantic_score: 0.8567, skill_score: 0.8963, matched_skills: [Python, Django] }, { job_id: 2, job_title: 机器学习算法工程师, final_score: 0.7215, semantic_score: 0.6982, skill_score: 0.7561, matched_skills: [Python, 机器学习] } ] }可以看到简历与“Python后端工程师”职位匹配度更高且列出了具体匹配的技能。6.3 前端可视化验证在浏览器中打开前端页面例如http://localhost:8080上传一份模拟的PDF简历。页面应展示解析出的技能、经验等信息。进入推荐页面职位应按匹配分从高到低排列。点击某个职位应能弹窗或跳转到详情页展示如雷达图等可视化图表清晰展示各维度匹配情况。7. 常见问题与排查思路在实现过程中你几乎一定会遇到以下问题。这里提供排查思路。问题现象可能原因排查方式解决方案BERT模型加载失败或非常慢1. 网络问题无法从Hugging Face下载模型。2. 本地缓存路径不正确。1. 检查网络连接。2. 查看transformers缓存目录通常~/.cache/huggingface/。1. 使用国内镜像源或在能访问的环境下载后离线加载。2. 指定本地路径BertModel.from_pretrained(‘/your/local/path/bert-base-chinese’)。NER模型训练Loss不下降或F1值很低1. 学习率设置不当。2. 数据标注质量差或数量太少。3. 标签体系定义混乱。4. BiLSTM层数或隐藏层大小不合适。1. 绘制Loss和F1曲线图。2. 检查训练集和验证集的样本数量和质量。3. 打印一些预测样例看错误模式。1. 调整学习率尝试1e-5,2e-5,5e-5。2. 清洗和扩增数据确保标注一致。3. 简化标签体系或检查数据预处理代码。4. 尝试调整BiLSTM参数或先只用BERTCRF试试。相似度计算得分普遍很高或很低没有区分度1. BERT向量没有进行归一化。2. 文本过长BERT截断导致信息丢失。3. 使用的BERT层不合适如未使用[CLS]。1. 检查余弦相似度计算前是否对向量做了L2归一化。2. 尝试对长文本分段编码再聚合如平均。1. 计算相似度前对向量进行归一化emb emb / np.linalg.norm(emb)。2. 对简历和JD提取关键部分如职责、要求进行计算而非全文。3. 尝试使用Sentence-BERT等专门为句子相似度训练的模型。Flask服务调用模型时内存溢出(OOM)1. 模型加载多份副本。2. 未使用GPU或批处理过大。1. 使用htop或nvidia-smi监控内存/显存使用。2. 检查代码是否在每次请求都加载模型。1. 确保模型全局只加载一次在应用启动时。2. 在GPU上运行并限制推理时的批处理大小batch_size1。3. 考虑使用模型量化或ONNX Runtime加速。前端页面调用API跨域(CORS)错误浏览器安全策略阻止跨域请求。浏览器开发者工具Console标签页查看错误信息。在Flask后端安装flask-cors并初始化CORS(app)。PDF简历解析乱码或提取不到文本1. PDF是扫描件图片。2. 编码问题。3. 使用了不兼容的解析库。1. 用文本编辑器打开PDF看是否能复制文字。2. 打印解析出的原始字节。1. 对于扫描件需要先进行OCR如pytesseract。2. 尝试不同的PDF解析库如pdfplumber,PyMuPDF。3. 指定正确的编码。8. 最佳实践与工程建议要让你的毕业设计从“能运行”升级到“有工程价值”请注意以下几点数据质量至上NLP项目七分靠数据。即使模型再高级脏数据也训练不出好结果。花时间清洗和规范你的训练数据定义清晰、一致的标注规则。模型轻量化与部署训练后量化使用PyTorch的量化工具减小模型体积提升推理速度。使用ONNX将模型转换为ONNX格式便于在不同框架和环境中部署。API异步处理对于耗时的简历解析和匹配请求使用Celery等工具进行异步任务队列处理避免HTTP请求超时。系统可扩展性设计模块化将NER模块、相似度模块、API模块分离方便独立优化和替换。例如未来可以轻松将BERT换成更先进的模型。配置化将模型路径、权重参数、数据库连接等信息写入配置文件如config.yaml而非硬编码在代码中。前端用户体验提供反馈文件上传时显示进度条匹配计算时显示加载动画。解释性不仅展示匹配分数更要用高亮、图表等形式解释“为什么匹配度高”例如“您的‘Python’技能与职位要求高度吻合”。安全与隐私数据脱敏在演示和存储简历数据时对姓名、电话、邮箱等个人敏感信息进行脱敏处理。文件安全对上传的文件进行类型、大小检查防止恶意文件上传。API限流对公开的API接口实施简单的限流策略防止恶意调用。答辩准备要点讲清脉络重点介绍“问题背景 → 技术选型为什么用BERTBiLSTMCRF→ 系统架构 → 核心实现 → 效果展示”这条主线。展示亮点现场演示系统从上传简历到出推荐结果配合可视化图表直观有力。思考与展望能清晰说明当前系统的不足如数据量小、未考虑薪资地点等硬性条件并提出可行的改进方向如引入知识图谱、强化学习进行个性化排序。通过这个项目你不仅完成了一个完整的AI应用更实践了从数据处理、模型研发到Web系统部署的全栈流程。这其中的每一个环节都是你技术能力的有力证明。
返回列表