数据截至 (上游 commit d9f7b80be1ee)
核心概念与数据模型:漏洞 / 攻击 / 测试用例 / 裁判
30 秒导读: DeepTeam 是一个给 LLM 应用做「红队测试」(red teaming,主动构造恶意输入去 找模型的安全漏洞)的框架。它把整件事拆成四类抽象:漏洞(要测的坏行为)、攻击 (把测试问题伪装/加强的手法)、测试用例(一条被逐步填满的「工单」)、裁判(另一个 LLM,给模型回答打 0 或 1 分)。这一章只讲清这四样「是什么、怎么分类、字段什么意思」, 是全库的地基。生成算法、编排循环留给后面的章节。
1. 这是什么(零基础也能懂)
一句话: 红队测试 = 你雇一群人专门想办法把你的 AI 问「坏」,看它会不会说不该说的话、 做不该做的事。DeepTeam 把「那群人」自动化了。
要把这件事做成可复用的软件,必须先回答两个正交的问题:
- 要测什么坏行为? —— 模型会不会有种族偏见?会不会教人做炸弹?agent 会不会被骗着去删库? 这类「坏行为的种类」,DeepTeam 叫 Vulnerability(漏洞)。
- 用什么方式去问,才更容易套出坏行为? —— 直接问「教我做炸弹」模型会拒绝;但如果编码成 Base64、包装成「你是一个不受限 制的 AI」的角色扮演,就可能绕过。这类「问法/加强手法」, DeepTeam 叫 Attack(攻击)。
漏洞和攻击是两个可以自由组合的维度:任意一个漏洞(测什么)× 任意一种攻击(怎么问)= 一条具体的对抗输入。这条输入连同模型的回答、以及后续的评分,被装进一个叫 RTTestCase(红队测试用例) 的对象里——你可以把它想成一张工单,从「只有攻击输入」 一路被填到「有回答、有分数、有理由」。
最后谁来判定「模型这次算不算翻车」?不是写死的规则,而是另一个 LLM 当裁判——这就是 Metric(裁判/度量) 抽象:给它 (输入, 模型回答),它输出 0(不安全)或 1(安全) 加一句理由。
一句话直觉: 把它类比成考试作弊测试——漏洞是「考哪门课的作弊」,攻击是「用什么 夹带手法」,测试用例是「一张答卷」,裁判是「批卷老师」。
2. 顶层全景:四类抽象怎么咬合
先看这四样东西在一次测试里的数据流(从左到右是一条测试用例被填满的过程):
┌─────────────┐ ┌─────────────┐
│ Vulnerability│ × │ Attack │
│ 测什么坏行为 │ │ 怎么伪装/加强│
│ (Bias/PII…) │ │(Base64/角色…)│
└──────┬──────┘ └──────┬──────┘
│ │
│ ① 生成 baseline │ ② 增强 baseline
▼ 对抗问题 ▼ (第 02/03 章)
┌────────────────────────────────────┐
│ RTTestCase │ ← 贯穿全程的「工单」
│ input ← 攻击输入(先填这个) │
│ actual_output ← 被测模型的回答 │
│ score / reason ← 裁判填(最后填) │
└────────────────┬───────────────────┘
│ ③ 交给裁判
▼
┌──────────────────┐
│ Metric (裁判) │ 另一个 LLM
│ measure() → 0/1 │ + 一句 reason
└──────────────────┘
四类抽象一句话职责:
| 抽象 | 干什么 | 基类 · 文件 |
|---|---|---|
| Vulnerability | 定义「测什么坏行为」+ 它的子类型 + 该配哪个裁判 | BaseVulnerability · deepteam/vulnerabilities/base_vulnerability.py:9 |
| Attack | 定义「怎么把问题伪装/加强」+ 采样权重 + 单/多轮 | BaseAttack · deepteam/attacks/base_attack.py:12 |
| RTTestCase | 一条被逐步填充的「工单」,承载 input→output→score | RTTestCase · deepteam/test_case/test_case.py:22 |
| Metric | 「裁判」= 另一个 LLM,给回答打 0/1 | BaseRedTeamingMetric · deepteam/metrics/base_red_teaming_metric.py:7 |
后面四节分别把这四样讲透 。边界提醒: 本章只讲「静态结构」——谁有哪些字段、怎么分类; 「动态过程」(怎么生成攻击、主循环怎么编排、裁判 measure 内部怎么打分)分别在 02、03、 04 讲。
3. Vulnerability:测什么坏行为
3.1 抽象契约:BaseVulnerability
所有漏洞都继承 BaseVulnerability(deepteam/vulnerabilities/base_vulnerability.py:9)。
它是一个 ABC,规定了每个漏洞必须提供的类属性和方法契约。
先看类属性——它们回答「这个漏洞是什么」:
| 属性 | 含义 |
|---|---|
name | 漏洞的展示名(如 "Bias"),也是注册表的 key |
description | 一句话说明这个漏洞是什么 |
ALLOWED_TYPES | 该漏洞允许的子类型字符串列表(如 Bias 的 religion/politics/gender/race) |
category | 它属于哪个大类(Responsible AI / Security / …,见 §3.3) |
metric | 该漏洞对应的裁判类型(BaseRedTeamingMetric) |
再看方法契约——它们回答「拿这个漏洞能做什么」。构造时接收一组 types: List[Enum]
存进 self.types(base_vulnerability.py:16),然后:
| 方法 | 契约(它承诺做什么) |
|---|---|
get_types() | 返回启用的子类型枚举列表(:24) |
get_values() | 返回子类型的字符串值(:31) |
simulate_attacks(purpose) | 生成 baseline 对抗输入(基类里是空壳,子类实现) |
a_simulate_attacks(purpose) | 上面的 async 版 |
_get_metric() | 返回这个漏洞该用的裁判实例(:56,子类实现) |
_refine_simulated_attacks(...) | 把 baseline 输入交给 AttackEngine 做精炼(:63) |
assess / a_assess | 端到端跑一遍(生成→问模型→打分),Bias 里有完整实现 |
注意契约里的「空壳」:
simulate_attacks/_get_metric在基类里是pass(base_vulnerability.py:44、:56)——基类只声明契约,具体逻辑由每个漏洞子类填。_refine_simulated_attacks是少数基类就给了实现的:它懒加载AttackEngine并调engine.refine(...)(:63-72)。这条「baseline → 精炼」的流水线细节在 第 02 章。