ARTICLE DETAIL

资讯详情

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

LangChain与机器学习融合:构建双层垃圾邮件检测系统

LangChain与机器学习融合:构建双层垃圾邮件检测系统 这次我们看的是一个很典型的“毕业设计升级版”技术项目用 LangChain 编排 LLM 大语言模型再叠加上传统机器学习分类模型共同完成垃圾邮件检测与分析。和直接调一个现成接口不同这个系统要自己处理数据、训练模型、设计置信度判断再让大模型介入“疑难邮件”复核最后通过接口或 Web 页面把整条链路暴露出去。对于计算机毕业设计、网络安全方向的综合实战、或者想入门 LangChain 应用开发的人来说这套架构能把“机器学习 LLM 应用”两个热门点一次性串起来。这个项目最值得关注的点有三个一是传统机器学习负责快速粗筛延迟低、可解释性强二是 LLM 负责深度语义复核能给出检测理由弥补关键词过滤在语义绕过上的短板三是把数据预处理、模型训练、LangChain 编排、FastAPI 接口和批量任务整合成完整系统而不是一堆零散的 notebook 代码。纯 CPU 环境可以完成机器学习的训练和推理LLM 部分可以选择调用 API也可以在本地跑一个小模型硬件门槛完全取决于你选哪条链路。下面我会按照“规格速览 → 系统设计 → 环境准备 → 数据预处理 → 机器学习训练 → LangChain 增强 → 接口与批量任务 → 性能观察 → 排错 → 毕设落地”的顺序把整个系统从零到一讲清楚代码部分可以直接照着改。1. 核心能力速览能力项说明项目类型垃圾邮件检测分析系统毕业设计 / 综合实战项目技术栈LangChain、LLM 大语言模型、Scikit-learn、Pandas、FastAPI检测模式机器学习粗筛 LLM 深度复核的双层检测主要功能垃圾邮件二分类、语义理解、检测理由生成、批量检测、API 服务、分析报表推荐硬件机器学习部分 CPU 可跑LLM 部分可选云端 API 或本地模型显存需求不固定选用本地 LLM 时按模型参数量和量化方式实测支持平台Windows / Linux / macOS启动方式命令行启动、Web UI、API 服务批量任务支持可按目录批量导入或接口批量提交适合场景毕业设计、邮件内容安全分析、LLM 应用开发练习从表格能看出来这个项目并不是纯“调包炼丹”而是更接近一个能演示、能答辩、能扩展成论文原型的完整系统。2. 适用场景与使用边界这套系统适合三类人第一类是计算机相关专业的学生需要一个既能体现机器学习基础、又能展示大模型应用能力的毕业设计题目第二类是做网络安全或内容安全方向的初学者希望理解垃圾邮件检测的基本流程和纵深防御思路第三类是后端开发想用最短路径把 LangChain 接入到实际业务链路里。它解决的问题也很具体邮件内容中大量重复、群发、诱导性文本需要被自动识别同时攻击者会通过变体拼写、图片文字、伪装正常句式来绕过传统规则。传统机器学习可以快速识别“已知垃圾模式”LLM 则更适合识别“语义上是垃圾但关键词不明显”的样本。两者的结合能明显改善单一模型的鲁棒性。但使用边界也要说清楚这个项目适合做检测分析与教学演示不适合直接当作生产级邮件安全网关。它不负责邮件传输层的 SPF/DKIM/DMARC 校验也不处理附件木马分析更无法替代完整的反钓鱼体系。另外凡是涉及真实邮件数据的场景必须遵守数据来源授权、用户隐私保护和内容展示规范不能把真实用户邮件库直接公开或拿去训练商用模型。演示环境建议使用公开数据集或自建脱敏语料。3. 系统架构与整体设计整个系统可以拆成五个层次数据层、特征层、机器学习层、LLM 增强层、服务层。数据层负责读取邮件文本、标注数据和原始邮件目录并做基础清洗。特征层把中文或英文邮件文本转成 TF-IDF 向量、邮件头特征、URL 特征、文本长度特征等。机器学习层使用朴素贝叶斯或逻辑回归等模型做粗筛输出是否为垃圾邮件的概率。LLM 增强层接收低置信度样本通过 LangChain 组装 Prompt要求大模型输出判断结果和简短理由。服务层用 FastAPI 暴露/predict、/batch等接口并提供一个简单的 Web 页面用于人工复核。处理流程如下邮件输入 - 文本清洗 - 特征提取 - 机器学习粗筛 - 高置信度直接输出结果 - 低置信度LangChain LLM 复核 - 合并结果返回标签、置信度、检测理由这样设计的核心原因只有一个成本控制。LLM 调用比传统模型昂贵且耗时如果每封邮件都走大模型批量场景根本扛不住。先让机器学习处理大部分明显样本只把边界样本送进 LLM既能提升整体准确率又能把系统延迟控制在可接受范围内。4. 环境准备与前置条件4.1 基础软件清单建议使用 Python 3.10 或 3.11Windows、Linux、macOS 均可。项目本质上是 Python 生态应用不需要依赖特定操作系统。机器学习部分建议安装 Scikit-learn、Pandas、Numpy、Jieba处理中文分词时需要。LLM 部分可选安装 LangChain 和对应模型接入包。服务层需要 FastAPI、Uvicorn。虚拟环境是必需品避免把全局 Python 环境搞乱。首次安装时如果网络条件一般可以考虑使用国内镜像源加速。# 创建虚拟环境 python -m venv .venk # Windows 激活虚拟环境 .venk\Scripts\activate # Linux / macOS 激活虚拟环境 source .venk/bin/activate # 升级 pip python -m pip install --upgrade pip4.2 核心依赖安装示例pip install pandas numpy scikit-learn jieba pip install fastapi uvicorn pip install langchain langchain-openai如果计划使用本地 Ollama 模型还需要额外安装langchain-ollama。这类指令在不同版本下依赖差异较大建议以官方文档为准。4.3 硬件与显存说明机器学习训练阶段不强制要求 GPU几万条邮件样本的 TF-IDF 和逻辑回归在普通 CPU 上通常可以接受。LLM 部分有两种选择云端 API 方式不要求本地显存本地部署方式则需要根据模型大小准备对应显存和内存。本地跑 7B 级别量化模型时建议先用nvidia-smi观察实际占用不同量化等级、上下文长度和并发数会带来成倍差异不能只凭模型参数量推断。4.4 端口规划FastAPI 服务默认使用 8000 端口如果本机端口被占用可以在启动时手动指定。这里建议固定一个端口写入配置方便后续接口联调。5. 数据集准备与文本预处理5.1 数据集选取公开可用的垃圾邮件数据集有 SpamAssassin、Enron-Spam 等中文场景有 trec06c 这类学术数据集。使用前必须确认数据集的版权许可并在论文或 README 中标注来源。自建数据集时建议从公开语料中抽样而不是直接导出个人邮箱数据。数据集建议采用两列结构字段说明示例text邮件正文或主题行“恭喜您获得 9980 元大礼包”label0 表示正常邮件1 表示垃圾邮件1这里需要注意类别不平衡问题。真实场景中垃圾邮件比例往往不低但正常邮件和垃圾邮件的具体比例随数据集变化。训练前先统计两类的数量避免出现全部预测为多数类的情况。5.2 文本清洗流程垃圾邮件的文本噪声非常大包含 HTML 标签、URL、数字、特殊符号、繁体字、异体字和拼写变体。清洗的核心目的是把有效语义信息保留下来去掉过程性噪声。完整的清洗模块可以这样写import re import jieba STOP_WORDS set([的, 了, 是, 在, 我, 有, 和, 就, 不, 人]) def clean_text(text: str) - str: if not isinstance(text, str): return # 去掉 HTML 标签 text re.sub(r[^], , text) # 去掉 URL text re.sub(rhttp[s]?://\S, , text) # 去掉邮箱地址 text re.sub(r\S\S, , text) # 去掉数字和特殊符号英文场景可改保留字母 text re.sub(r[^\u4e00-\u9fa5a-zA-Z\s], , text) # 转小写 text text.lower() return text def tokenize(text: str) - list[str]: cleaned clean_text(text) words jieba.lcut(cleaned) words [w.strip() for w in words if w.strip() and w not in STOP_WORDS] return words这一步会给后面的特征工程省下大量麻烦。分词质量直接影响 TF-IDF 向量质量中文场景建议把自定义词典和停用词表单独保存成文件便于后续维护。5.3 训练集与测试集划分按 8:2 或 7:3 的比例划分训练集和测试集并固定随机种子保证结果可复现。邮件数据常常存在时间相关性更严谨的做法是按照时间先后划分防止未来信息泄漏到训练集。from sklearn.model_selection import train_test_split train_df, test_df train_test_split( df, test_size0.2, random_state42, stratifydf[label] )使用stratify做分层抽样能保证训练集和测试集中正负样本比例接近。6. 机器学习模型训练与评估6.1 特征工程文本特征最常用的是 TF-IDF 向量简单且稳定。可以开启ngram_range(1, 2)让模型捕捉短语特征再限制max_features防止维度爆炸。from sklearn.feature_extraction.text import TfidfVectorizer vectorizer TfidfVectorizer( tokenizertokenize, ngram_range(1, 2), max_features20000, min_df2, max_df0.95 ) X_train vectorizer.fit_transform(train_df[text]) X_test vectorizer.transform(test_df[text]) y_train train_df[label] y_test test_df[label]这里要注意测试集只能transform不能fit否则就发生了数据泄漏。很多初学者在这里踩坑得到一个虚高的准确率换新数据立刻崩掉。6.2 模型选择与训练垃圾邮件检测常用的传统模型有朴素贝叶斯、逻辑回归、线性 SVM 和随机森林。从实际效果看逻辑回归和朴素贝叶斯在该任务中表现稳定训练速度快可解释性也好。下面以逻辑回归为例from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report, confusion_matrix model LogisticRegression(max_iter1000, class_weightbalanced) model.fit(X_train, y_train) y_pred model.predict(X_test) print(classification_report(y_test, y_pred, target_names[正常邮件, 垃圾邮件])) print(confusion_matrix(y_test, y_pred))class_weightbalanced会在类别不平衡时自动调整权重通常能带来明显收益。如果数据集较大可以尝试随机森林但训练和推理成本更高收益不一定匹配。6.3 评估与调优重点评估时不要只看 accuracy重点看三个指标精确率、召回率、F1。垃圾邮件检测场景里召回率低意味着漏放垃圾邮件精确率低意味着误杀正常邮件。具体偏重哪个指标取决于系统定位偏安全的系统更看重召回率偏用户体验的系统更看重精确率。调优路线建议调优方向操作建议特征维度调整max_features、ngram_range类别不平衡使用class_weight或过采样/欠采样模型选择对比逻辑回归、朴素贝叶斯、SVM阈值调整不一定要用默认 0.5可以根据验证集调整概率阈值下面这段代码演示如何自定义分类阈值。把概率低于阈值的样本判定为低置信度交给后续 LLM 处理。proba model.predict_proba(X_test)[:, 1] threshold 0.6 y_rule (proba threshold).astype(int) # 置信度区间不适合直接下结论的样本 low_confidence_mask (proba 0.4) (proba 0.6)7. LangChain LLM 增强检测模块7.1 为什么需要 LLM 增强传统模型对拼写变体和隐晦语义的识别能力有限。攻击者会把“免费”写成“免费”、“发财”写成“fa cai”或者把整个话术包装成正常商务邮件。单纯靠 TF-IDF 很难捕捉这种语义层面的垃圾特征。LLM 的长处在于它能理解整段文本的意图即使关键词被改写也能做出判断。但这个增强模块不能每封邮件都调用所以在系统设计里增加了一个“置信度分流”机制模型输出概率在 0.4 到 0.6 之间的样本认为是边界样本交给 LLM概率大于 0.6 直接判为垃圾邮件概率小于 0.4 直接判为正常邮件。阈值数值需要按实际验证集调整。7.2 LangChain Prompt 设计LangChain 在这里的作用是管理 Prompt 模板、组织少样本示例、构建立场化的输出格式。最简单的用法是ChatPromptTemplate加一个输出解析器。from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser prompt ChatPromptTemplate.from_messages([ (system, 你是一名邮件内容安全分析专家负责判断邮件是否为垃圾邮件。 垃圾邮件包括广告推销、诈骗、钓鱼、恶意诱导等内容。 只输出 JSON{{\label\: 0 或 1, \reason\: \简要判断理由\}}), (human, 请分析以下邮件\n{email_text}) ]) llm ChatOpenAI( modelgpt-4o-mini, temperature0, api_keyyour-api-key, base_urlhttps://your-api-endpoint # 兼容 OpenAI 格式的服务 ) chain prompt | llm | StrOutputParser()如果不方便使用云端 API也可以把ChatOpenAI换成本地模型接入方式比如配合 Ollama 中的开源模型。具体模型选择不在这里展开原则是优先选指令跟随能力好、支持中文的小模型。7.3 与机器学习结果合并实际调用时不要把 LLM 结果直接覆盖机器学习结果而是把它作为“复核意见”合并。最终标签、置信度、理由都保留在结果对象里。def final_decision(ml_label: int, proba: float, llm_text: str): ml_label: 机器学习预测标签 proba: 机器学习预测为垃圾邮件的概率 llm_text: LLM 返回的 JSON 字符串 if 0.4 proba 0.6: # 边界样本以 LLM 复核结果为准 result parse_llm_output(llm_text) return { label: result[label], source: llm, reason: result[reason], ml_proba: round(proba, 4), } return { label: ml_label, source: ml, reason: 机器学习模型高置信度判断, ml_proba: round(proba, 4), }在实际项目中这里还需要加异常处理。LLM 调用可能超时、返回非 JSON 内容、或者因限流失败系统必须能在 LLM 不可用时回退到机器学习结果保证主流程不中断。7.4 少样本与多轮能力如果发现某个类型的垃圾邮件漏检严重可以在 Prompt 中加入几条少样本示例帮助模型理解任务边界。LangChain 支持从示例列表中动态构建消息这一点比直接拼字符串更优雅。8. Web 服务、接口 API 与批量任务8.1 FastAPI 服务搭建为了方便演示和二次开发系统服务层使用 FastAPI 实现。下面是一个最小可运行示例包含健康检查、单条预测、批量预测三个接口。from fastapi import FastAPI from pydantic import BaseModel app FastAPI(title垃圾邮件检测分析系统) class EmailInput(BaseModel): text: str class BatchInput(BaseModel): items: list[EmailInput] app.get(/health) def health(): return {status: ok} app.post(/predict) def predict(email: EmailInput): text email.text # 业务中需要替换为完整检测流程清洗 - 特征 - 模型 - LLM 增强 result { text: text, label: 1, reason: 演示结果请接入完整检测流程, source: demo } return result app.post(/batch) def batch_predict(batch: BatchInput): results [] for item in batch.items: results.append(predict(item)) return {total: len(results), results: results}启动服务uvicorn main:app --host 127.0.0.1 --port 8000 --reload启动后访问http://127.0.0.1:8000/docs就能看到 Swagger 文档可以直接在页面里发送测试请求。FastAPI 自带交互式文档在接口调试和毕设答辩演示里很好用。8.2 接口调用示例可以使用 Python 的requests测试接口import requests url http://127.0.0.1:8000/predict payload { text: 恭喜您获得万元大奖点击链接立即领取! } response requests.post(url, jsonpayload, timeout30) print(response.json())也可以用 curl 直接调curl -X POST http://127.0.0.1:8000/batch \ -H Content-Type: application/json \ -d {items: [{text: 免费领取优惠券}, {text: 周四下午项目评审会议室见}]}8.3 批量任务设计批量检测如果做成同步接口文件较大或样本较多时容易超时。更合理的做法是上传文件后生成任务 ID后端异步处理前端轮询任务状态。这个模式也能让毕设增加一个“任务队列”的亮点。流程可以简化为上传邮件文件 - 生成 task_id - 后台线程逐条读取 - 清洗 - 模型判断 - LLM 复核 - 写结果文件 - 更新任务状态批量任务最容易忽略的问题是失败重试。单条数据可能因为格式异常、编码问题、LLM 限流而失败。建议每条记录都记录独立状态成功、失败、跳过失败原因写入日志。全部处理完后汇总统计文件方便用户查看哪些邮件被判定为垃圾邮件以及理由。import csv from pathlib import Path OUTPUT_DIR Path(./outputs) OUTPUT_DIR.mkdir(exist_okTrue) def write_result(task_id: str, rows: list[dict]): output_file OUTPUT_DIR / f{task_id}.csv with open(output_file, w, newline, encodingutf-8) as f: writer csv.DictWriter(f, fieldnames[text, label, source, reason, ml_proba]) writer.writeheader() writer.writerows(rows)9. 资源占用与性能观察这是一个需要重点观察的模块。部署完成后建议先跑小批量数据记录三个核心数据训练耗时、单条预测耗时、LLM 复核耗时。9.1 CPU 与内存观察传统机器学习的训练过程会占用较多 CPU但推理阶段非常快单条预测通常只有几毫秒。问题主要集中在 TF-IDF 向量化阶段max_features设置过大、ngram_range过大、文本过长都会显著拉高内存。观察方式很简单任务运行时打开系统监视器或使用top/htop。9.2 显存观察如果 LLM 采用本地部署观察显存占用是必要的。推理过程中可以另开终端执行nvidia-smi -l 2这里要强调显存占用不是固定值它和模型量化等级、上下文长度、批处理大小、并发请求数都有关系。不要套用别人机器的数据一定要用自己机器跑一遍。如果显存吃紧优先降低上下文长度、减小批量数或者换更小的量化模型。9.3 延迟与成本控制单条邮件如果走“机器学习 LLM 复核”耗时会从毫秒级跳到秒级。因此系统要重点关注“LLM 调用占比”。占比越高整体延迟越高成本也越高。调优方向是提高机器学习置信度阈值让更多样本直接出结果或者把低置信度区间压缩。9.4 并发与限流FastAPI 本身是异步框架可以处理一定并发但 LLM 接口通常有速率限制。批量任务必须做简单的并发控制比如限制同时最多 5 个 LLM 请求避免触发限流导致大量失败。10. 常见问题与排查方法问题现象可能原因排查方式解决方案依赖安装失败Python 版本不兼容或网络原因查看 pip 报错信息换用 3.10/3.11 虚拟环境使用镜像源中文乱码或分词结果异常文件编码不是 UTF-8检查数据文件编码统一转为 UTF-8 后重新读取准确率低几乎全预测为多数类类别不平衡或特征没做清洗打印类别分布和分类报告使用class_weight、调整阈值、补充数据测试集效果不错新数据很差数据泄漏或数据分布不一致检查是否对测试集执行了fit确认只对测试集执行transformLLM 接口调用超时网络波动或服务端限流查看日志和响应码增加超时时间、重试机制、并发控制LLM 返回内容无法解析模型输出了非 JSON 内容打印原始输出使用强约束的 Prompt增加回退解析逻辑批量任务中途卡住异常数据导致线程阻塞查看任务日志定位具体批次逐条增加 try/except记录失败原因服务启动后页面打不开端口被占用或服务未启动检查终端日志和本机端口更换端口或重启服务这里有一个比较隐蔽的问题需要单独提醒模型文件、输出目录和日志目录最好在项目初始化时自动创建否则批量任务跑到一半可能因为目录不存在直接崩掉。11. 毕业设计落地与答辩建议11.1 模块划分与工作量展示这个项目非常适合做毕业设计因为它的模块划分天然对应论文结构需求分析、系统设计、数据集构建、模型训练、LLM 增强、系统实现、测试评估。建议在 README 里画一张简单的系统架构图把五个层次和核心数据流标清楚答辩时直接围绕这张图讲。11.2 答辩高频问题准备答辩时大概率被问到几个问题“为什么用了机器学习还要用大模型”“大模型调用成本那么高怎么保证系统可用性”“数据集从哪里来是否存在隐私问题”“如何处理中文邮件和英文邮件的差异”回答思路分别是机器学习适合快速处理常规样本LLM 适合处理语义模糊样本两者是“成本与效果”的平衡系统通过置信度分流控制 LLM 调用占比并做了失败回退数据集全部采用公开语料或人工脱敏数据中文和英文分别使用不同分词与清洗策略。11.3 效果展示建议答辩演示时不要只跑一条邮件建议准备一个本地测试集包含明显垃圾邮件、正常邮件、带变体的垃圾邮件、伪装成正常邮件的钓鱼邮件四类。重点展示前两类由机器学习快速判断后两类触发 LLM 复核并给出理由。这个对比最能体现系统价值。11.4 后续扩展方向如果时间和精力充足可以在现有系统上加三个方向垃圾邮件多分类广告、诈骗、钓鱼、邮件附件危险链接分析、基于知识库的钓鱼邮件特征库。这些方向都能把项目深度再做一层。12. 最佳实践与合规提醒代码工程层面建议从一开始就把配置项抽离出来。API Key、模型名称、端口、阈值、文件路径都放配置文件不要直接写死在代码里。模型训练完的vectorizer和model用joblib或pickle保存接口启动时加载一次避免每次请求重新训练。安全合规方面这是这篇博客里最需要重视的一部分。垃圾邮件检测项目天然涉及大量邮件内容真实邮件属于个人隐私数据使用前必须确保数据来源合法匿名化处理后再进入实验环境。模型文件、数据集、日志都包含文本内容不能随意公开。涉及 LLM 的调用也要注意不要把未经脱敏的邮件内容直接发送到外部 API。如果是在企业内部或毕设演示中使用建议使用本地模型或专门审批过的 API 服务。另外系统如果发布成在线服务建议增加简单的访问认证和限流。FastAPI 中实现一个简单的 API Key 校验并不复杂成本低但能防止接口被别人恶意刷量。from fastapi import Header, HTTPException API_KEY your-secret-token def verify_api_key(x_api_key: str Header(default)): if x_api_key ! API_KEY: raise HTTPException(status_code401, detailInvalid API Key)13. 总结与下一步这个项目最值得尝试的点是把“传统机器学习”和“LangChain LLM”组合到一个真实的检测任务里而不是为了用大模型而用大模型。整套系统跑通之后你会发现它比单一模型更容易解释也比纯 Prompt 方案的稳定性更好。建议先验证的功能是机器学习模块能否在测试集上稳定复现分类指标以及置信度分流是否能把边界样本挑出来。最容易踩的坑有两个一个是测试集上做fit导致数据泄漏一个是 LLM 调用没有做异常回退导致单点故障拖垮整个批量任务。后续可以继续扩展的方向包括把邮件头信息、发件人信誉、URL 检测接入特征层用向量数据库构建钓鱼邮件知识库让 LLM 复核时能参考历史案例或者在批量任务里引入消息队列把吞吐量再提上去。无论你是做毕业设计还是想入门 LangChain 应用开发这套系统都值得动手跑一遍。
返回列表