全部项目详解

硕士论文:对 AI 生成钓鱼邮件的可解释检测

已提交,成绩待公布

我在 Liverpool John Moores University 的硕士论文:检测 AI 写的钓鱼邮件,并衡量每个检测器给出的解释是否忠实于它实际的行为。

我的角色
作者:实验设计、代码、评估和写作
年份
2026
使用技术
Python · scikit-learn · XGBoost · LightGBM · PyTorch · Transformers · SHAP · LIME · Integrated Gradients

问题

语言模型写的钓鱼邮件,读起来和过去的模板不一样;而一个没人能解释的检测器,很难让人信任,也很难审计。我提了两个问题:哪类模型在 AI 写的邮件上站得住?这些解释是否忠实于模型真正在做的事?

实现方式

在同一套数据划分上比较了三类模型:经典模型(逻辑回归、朴素贝叶斯、SVM、决策树、随机森林)、梯度提升集成模型(XGBoost、LightGBM)和 Transformer 模型(BERT、DistilBERT、RoBERTa),并在旧式邮件和 AI 生成邮件之间做了跨语料库测试。SHAP、LIME 和 Integrated Gradients 给出的解释,以随机归因为基线,按忠实度、稳定性和合理性打分。实验方案在实验开始前就做了预注册,线索词表在得出任何结果之前就已提交,一套阳性对照测试用来校验各个解释器,合理性指标也和人工评分者以及 LLM 评审做了对照校验。所有实验都在一块本地 RTX 3090 上运行。

关键决策

  • 跑实验前先预注册

    实验方案、词表和假设都在任何结果出现之前就提交了,所以不可能事后挑选。

  • 对解释做了度量

    得分和随机归因差不多的方法,会如实报告为与随机无异。当 LIME 的得分和随机差不多时,原因是我写的 LIME 适配器里有个 bug:tokenizer 的一个参数传反了。我公开说明了这个问题,修复后重新跑了一遍。修正后的 LIME 是忠实的,但在所有方法里稳定性最差。

  • 简单模型胜出

    在 AI 生成的邮件上,调优后的线性 TF-IDF 模型在 ROC-AUC 上胜过了 RoBERTa(0.9993 对 0.9976),而且 SHAP 能忠实地解释它,速度是修正后 LIME 的 64.5 倍。

仓库里的代码

src/xai/metrics.py以随机基线为参照来衡量忠实度
def faithfulness(champ, texts, attrs, preds, seed: int = 42) -> dict:
    rng = np.random.default_rng(seed)
    preds = np.asarray(preds)
    p_orig = _p_pred(champ.proba(texts), preds)1
 
    variants: list[str] = []
    meta: list[tuple] = []   # (doc_i, kind, k, is_random)
    for i, (text, attr, pred) in enumerate(zip(texts, attrs, preds)):
        nw = len(textops.word_spans(text))
        top = textops.top_k_positions(attr, int(pred), min(20, nw))
        randperm = rng.permutation(nw).tolist()2
        for k in K_AOPC:
            variants.append(textops.remove_words(text, top[:k])); meta.append((i, "comp", k, False))3
            variants.append(textops.remove_words(text, randperm[:k])); meta.append((i, "comp", k, True))
        for k in K_REPORT:
            variants.append(textops.keep_only_words(text, top[:k])); meta.append((i, "suff", k, False))
            variants.append(textops.keep_only_words(text, randperm[:k])); meta.append((i, "suff", k, True))
 
    P = _p_pred(champ.proba(variants), preds[[m[0] for m in meta]])4
  1. 第 4 行. 原始文档上预测类别的概率,是所有比较的参照。

  2. 第 11 行. 随机基线:以随机的词序做同样的删除,走完全相同的流水线。

  3. 第 13 行. 全面性(comprehensiveness):删除解释所指出的前 k 个词。概率下降得越多,解释就越忠实。

  4. 第 19 行. 所有文档的所有变体都在一个批次里过一遍 GPU。

目前进展

2026 年 8 月已提交,成绩尚未公布。每张表格和每幅图都能用已提交的脚本和固定的随机种子复现。现在我正和导师一起,把它写成会议论文。

下一篇FitEscala