工作内容
AI 算法实习生 · 深信服科技 · 2026 年 2 月—4 月 · 深圳
当时面对的不是一个已经整理好的分类数据集,而是一批持续增长的终端安全告警。完整数据约 12 万条,其中包含大量重复事件、模板化研判文本和同一事件在不同时间点产生的“生长记录”。如果把它们全部交给运营人员逐条审查,绝大多数时间都会花在相似告警上。
项目目标因此被拆成两件事:
- 把相同或高度相似的告警归到一起,选出能够代表每个模式的样本;
- 保留与已有模式距离较远的 rare 候选,交给安全运营人员复核。
这里的 rare 只表示值得人工关注的稀有候选,不是模型已经确认的新型攻击,也不能直接等同于 Rare TTP。
从原始告警到 review 包
整条管道可以概括为:字段提取 → 语义聚类 → 行为图聚类 → 分数归一化与汇总 → 生长事件后处理 → 代表样本选择 → 原始记录回捞。
两条路径并不是把向量简单拼接后训练一个分类器:
- 语义路径处理
gptResponse、analyseAnswer等研判文本,用 SBERT 表示攻击描述; - 行为图路径处理
treeList与virtualEdges,用 Weisfeiler–Lehman Kernel 表示进程树结构; - 两侧分别产生簇、相似度和异常程度,汇总阶段再做百分位归一化。
这样既能看“这两条告警说的是不是同一类行为”,也能看“它们的进程结构是不是真的相似”。
语义路径:先去掉模板,再谈相似度
告警文本中有大量固定套话,例如“发现一起……攻击”或“攻击者通过……”。直接编码整段文本时,模型会被这些高频句式主导,不同攻击模式也可能得到很高的余弦相似度。
实际处理分成三步:
- 按优先级从
gptResponse和analyseAnswer中回退提取有效文本; - 过滤在多数样本中都出现的模板词,保留进程名、安全术语和关键英文 token;
- 使用
paraphrase-multilingual-MiniLM-L12-v2生成 384 维向量。
为什么没有沿用 DBSCAN / HDBSCAN
早期方案考虑过密度聚类和 Union-Find,但真实数据中出现了明显的链式传递:A 接近 B,B 接近 C,并不代表 A 与 C 足够相似。最终采用簇中心法,每个新样本只与已有簇中心比较,超过 pattern_threshold 才加入最相近的簇,否则建立新簇。
这仍不是完美方案。875 条小样本实验中,420 条黑样本里出现过一个包含 305 条数据的超大簇,说明凭证窃取、恶意程序等描述在文本空间中仍会重叠。项目因此保留了二级聚类和人工复核,而不是把“成功聚成大簇”当成算法正确。
行为图路径:结构信息不能靠 DFS 字符串替代
每条告警的进程行为由 treeList 和 virtualEdges 表示。部分数据是嵌套树,如果不先展平,程序会误以为它只有一个根节点,后面的图相似度就失去意义。
行为图处理包含:
- 展平嵌套
treeList; - 按 file path、command line、signature 等字段逐级构造节点标签;
- 合并父子关系和额外行为边;
- 使用 WL Kernel 生成图结构表示;
- 使用完全链接层次聚类,限制簇内最不相似样本的距离。
旧页面写成了“DFS 序列化 + 树编辑距离 / 子树同构”,这并不是最终落地路线,现已删除。
图路径也有自己的边界:进程树一旦新增节点,WL 特征就可能发生明显变化。对于随时间不断生长的同一事件,这种敏感性会把同一个 cgId 拆成大量图簇。因此图特征适合判断结构差异,但不能直接作为生长事件去重的强信号。
两个分数怎样汇总
语义相似度通常分布在一个较窄的连续区间,图相似度却可能接近二值。如果直接做固定权重平均,某一维很容易因为数值分布不同而主导结果。
当前方案分别计算:
semantic anomaly = percentile_rank(1 - semantic_similarity)
graph anomaly = percentile_rank(1 - graph_similarity)
汇总后输出的是运营排序信号,而不是攻击概率。典型样本、簇边界样本、rare 候选和标签冲突样本会进入不同的 review 优先级。
这也修正了旧页面里并不存在的 0.65 × semantic + 0.35 × structural 固定权重,以及“两个分数都超过 0.8 就确认 Rare TTP”的伪代码。
最棘手的问题:同一个事件会一直长
同一次攻击事件可能在几十毫秒内连续触发多条记录。它们共享 cgId,但进程树和研判文本会随着新行为加入不断扩展。若逐条送进聚类:
- 同一事件会占据多个 review 名额;
- 新节点导致图簇频繁跳变;
- 运营人员看到的仍然是一组时间上相邻的重复记录。
所以项目在聚类完成后、生成 review 包之前增加 cgId 后处理。它依据语义簇跳变、文本变化和时间顺序保留关键 checkpoint,不把每次图结构变化都当成新模式。
在一组 1,118 条生长记录上:
| 策略 | 保留记录 | 结果 |
|---|---|---|
| 把图簇跳变作为强信号 | 993 | 几乎没有压缩,图结构过于敏感 |
| 以语义变化为主要触发条件 | 240 | 压缩约 78%,仍保留关键阶段 |
这次对比比“换一个更复杂的图模型”更有价值,因为它直接解释了业务数据为什么会重复,以及哪个信号适合做保留决策。
从全量聚类到增量处理
12 万条告警无法每次都重算完整相似度矩阵。首批数据用于建立语义簇心库和行为图代表库,后续批次只与已有簇心比较:
batch_0000
└─ 全量聚类 → 初始化 semantic / graph centers
batch_0001+
└─ 新样本 × 现有簇心 → 归并或建立 candidate center
新图簇不会立即升级为稳定簇心,而是先进入 candidate 状态,避免一个偶然离群点污染后续批次。每个 checkpoint 会冻结当前结果、执行生长数据后处理,并导出 review 包。
review 包不是简单截取异常分最高的若干行,而是组合:
- 每个稳定簇的中心样本;
- 簇内边界样本;
- rare 候选;
- 标签冲突或需要二次核查的样本。
最后根据 AIID 回到原始 JSONL 回捞完整字段,确保运营拿到的不是被特征工程裁剪后的中间记录。
已验证结果
在 12 万条数据的前两个真实批次中,管道完成了 10,000 条告警 → 680 条代表与待审样本 的压缩,约减少 93% 的人工审查量。
| 验证项 | 结果 |
|---|---|
| 输入记录 | 10,000 |
| review 候选 | 680 |
| AIID 原始记录回捞 | 680 / 680 |
| 产物闭环 | 聚类结果、去重结果、簇心库、checkpoint review 包均生成 |
这 680 条是运营待审候选,不是已经审核通过的训练样本。旧页面中的“识别准确率 >70%”“运营合格率 >80%”“生成 2,000+ 高价值训练样本”缺少与当前结果一一对应的验收记录,因此全部移除。
保密边界与项目收获
这项工作涉及真实终端安全数据,公开页面不会展示告警正文、客户信息、内部界面截图或私有代码。这里保留的是经过抽象的算法结构、排错过程和能够公开说明的规模结果。
这段实习最重要的收获不是“用聚类发现攻击”,而是学会把算法输出变成运营可以消费的交付物:既要控制 review 数量,又不能把稀有模式在压缩过程中一起删掉;既要支持增量运行,也要保留回溯到原始记录的路径。
项目说明
- 项目源码与原始数据属于公司内部资产,不提供公开仓库。