garak 入门:别急着扫,先看懂一条数据是怎么被判"命中"的
第一次接触 LLM 安全工具时,很容易把 garak 理解成一台"模型体检仪":跑一遍,拿个分数,分数高就说明模型安全。
这个理解会把后面的实验全部带偏。
garak 更像一个面向 LLM 的漏洞扫描器:它拿一批已知攻击样本反复打目标,再用 detector 判断输出里有没有出现不期望的行为。它回答的不是"这个模型好不好",而是:
在这批攻击、这组判定规则、这次采样下,目标有多少次被打穿。
这句话里的每个限定条件都不可省略,少一个,分数就可能被误读。
这篇文章先不急着晒扫描结果,而是把 garak 的基本功能、核心原理和使用边界讲清楚。后面再用它分别测试 DeepSeek 和 codex,才会知道数字到底意味着什么。
1. garak 是什么
garak 的全称是 Generative AI Red-teaming & Assessment Kit,是一个免费、开源(Apache 2.0)的 LLM 漏洞扫描与红队评估工具,目前由 NVIDIA 主导维护,并有配套论文公开其设计思路。
官方常把它类比成 LLM 领域的 nmap 或 Metasploit:nmap 扫端口和服务,garak 扫模型的失败模式。它可以检查的方向包括:
- 越狱与提示注入
- 数据泄露、系统提示泄露
- 编码绕过
- 有害内容与误导信息
- 幻觉与虚假依赖包名
- 恶意代码、XSS 等不安全输出
- 多轮诱导与部分 Agent 工具滥用场景
它支持的目标也不只是某一家模型:Hugging Face、OpenAI API、AWS Bedrock、LiteLLM、GGUF,以及大多数能通过 REST 访问的模型接口,都可以作为被测对象。
但 garak 和传统扫描器有一个本质区别:网络服务对同一个请求的响应通常比较稳定,LLM 不是。 同一个越狱提示,模型可能九次拒答、一次破防。因此,garak 的结果天然是统计量,而不是简单的"有漏洞 / 没漏洞"。
2. 用一张映射表看懂它的组件
garak 的组件名不少,但如果从安全工程的视角看,它们并不陌生。
| garak 组件 | 在一次扫描里做什么 | 可以类比成什么 |
|---|---|---|
| Generator | 把不同模型或接口统一成调用对象 | 协议归一化 / 适配层 |
| Probe | 提供某一类攻击或测试提示 | 攻击样本库 |
| Buff | 对原始提示做编码、改写、翻译等变异 | 对抗样本生成器 |
| Detector | 判断模型输出是否命中某种失败模式 | 规则引擎 + 分类器 |
| Harness | 组织 probe 执行、调度调用流程 | 扫描调度层 |
| Evaluator | 汇总判定结果,形成分数与报告 | 审计与评估层 |
| Report / Hitlog | 保存结构化记录和命中样本 | 审计流水 + 证据留存 |
其中最容易被忽略的是 Buff。很多介绍只讲"probe 发提示、detector 看结果",但 Buff 往往会直接改变攻击强度:同一条提示,经过 Base64、ROT13、字符扰动或语言转换后,模型的表现可能完全不同。
所以,比较两次扫描时,不能只问"是不是同一个模型",还要问:probe、buff、detector 和采样参数是不是也一样。
3. 原理:一个 attempt 的一生
与其背组件定义,不如跟着一条数据走一遍。
text
Probe 取出攻击提示
→(可选)Buff 做编码、改写或翻译变异
→ Generator 统一调用目标模型
→ 同一提示重采样多次,得到文本输出
→ Detector 对每条输出判定 hit / pass
→ Evaluator 聚合结果
→ report.jsonl / hitlog / HTML 摘要
一次典型过程是:
- Probe 取出一条攻击提示。 例如一段 DAN 越狱话术,或者一条经过编码的注入指令。
- 可选地经过 Buff 变异。 原始提示可以被转换成另一种表示形式,用来测试模型是否仍能识别其中的恶意意图。
- Generator 把提示发给目标。 无论背后是 OpenAI 兼容接口、Hugging Face 模型还是自定义 REST 服务,上层看到的都是统一的调用抽象。
- 目标返回文本输出。 同一提示可以重采样多次,而不是只问一次。
- Detector 对每条输出做判定。 判定方式可能是关键词、正则、分类器,也可能是另一个模型充当 judge。
- Evaluator 聚合结果。 最终形成通过率、失败率或攻击成功率,并写入结构化报告和命中日志。
如果某次输出被判定为出现了不期望行为,就记为一次 hit。粗略地说:
text
ASR(攻击成功率)≈ 被判定为命中的尝试数 / 总尝试数
具体指标口径还要看 probe 和报告定义,不能把这个近似公式机械地套到所有测试上。
这里有两个设计特别值得注意。
3.1 为什么不能只问一次
因为模型输出有随机性。一次拒答不能证明模型能稳定拒答,一次破防也不能说明每次都必然破防。
重采样次数由 --generations 控制。当前 main 分支核心配置里可以看到默认值,但文档中的部分旧示例仍使用其他数字,不同版本也可能调整。因此,做对比实验时最好显式写出 --generations,不要依赖默认值。
3.2 Detector 不是"真相机器"
Detector 只是判定器,不是上帝视角。
关键词规则可能漏掉同义表达,英文毒性分类器可能误判中文输出,LLM judge 也会有自己的偏差。看到"0% 命中"时,至少要先排除三种情况:
- 攻击提示根本没有有效打到目标;
- 目标语言与 detector 的适用语言不一致;
- detector 的判定标准与你想测的风险不是一回事。
因此,报告里的命中样本比汇总百分比更重要。先看证据,再谈分数。
4. 它到底能测什么:按问题而不是按字母表看 Probe
garak --list_probes 会列出很长的清单。如果按模块名逐个介绍,很容易变成字典。更实用的方式是按你想问的问题来组织。
| 你想问的问题 | 可以关注的 probe 方向 |
|---|---|
| 会被 DAN、自动越狱或对抗后缀带跑吗 | dan、tap、pair、suffix、phrasing 等 |
| 会被 Base64、ROT13、特殊字符绕过吗 | encoding、badchars、glitch 等 |
| 会被提示注入覆盖原有指令吗 | promptinject、latentinjection 等 |
| 会泄露训练数据或系统提示吗 | leakreplay、系统提示提取相关 probe |
| 会编出不存在但看似可用的依赖包吗 | packagehallucination |
| 会生成恶意代码或 XSS 吗 | malwaregen、xss |
| 会输出有毒、歧视或误导内容吗 | realtoxicityprompts、lmrc、misleading 等 |
| 会在多轮对话里逐渐被诱导吗 | goat 等多轮 probe |
| 会滥用 Agent 工具、越权执行吗 | agent_breaker 等 Agent 方向 probe |
具体模块和类名以你所安装版本的 --list_probes -v 为准。部分多轮或 Agent probe 还需要额外配置红队模型,并不是安装后就会自动全量启用。
这张表里有两个方向值得单独关注。
一是 packagehallucination。 它测的不是一般意义上的"说错事实",而是模型会不会编造依赖包名。若攻击者抢注了这些名字,幻觉就可能进一步变成软件供应链风险。
二是多轮与 Agent 方向。 它说明 garak 正在从单轮文本扫描向更复杂的交互场景扩展,但这不等于它已经能完整审计 Agent 行为。这个区别会在测试 codex 时变得非常关键。
5. 最小复现:先跑通链路,再扩大范围
下面命令用于搭一个最小实验环境。建议使用独立虚拟环境,并使用专门的测试 Key,不要直接对生产服务或高权限账号扫描。
5.1 安装
garak 当前要求较新的 Python 版本,官方源码安装示例使用 Python 3.11 至 3.14。macOS / Linux 下可以这样准备:
bash
python3.13 -m venv .venv
source .venv/bin/activate
python -m pip install -U garak
garak --version
garak --list_probes
如果想看某个 probe 的说明、分级和标签:
bash
garak --list_probes -v --spec probes.dan
garak --plugin_info probes.dan.Dan_11_0
5.2 跑一个小范围扫描
以官方 README 的 OpenAI API 示例为例,模型名请替换成你实际可用的测试模型:
bash
export OPENAI_API_KEY="换成你的测试 Key"
python -m garak \
--target_type openai \
--target_name gpt-5-nano \
--spec probes.encoding \
--generations 1 \
--parallel_attempts 8 \
--report_prefix encoding_demo
这里故意做了三件事:
- 用
--spec probes.encoding限定范围,避免一上来全量扫描; - 用
--generations 1降低首轮成本,跑通后再提高采样数; - 用
--report_prefix给本次运行加前缀,方便区分不同实验。
当前版本推荐使用 --target_type、--target_name 和 --spec。一些旧教程里的 --model_type、--model_name、--probes 已进入弃用路径;读旧文章时,不要直接照抄命令。
5.3 结果保存在哪里
运行日志和报告文件名会在控制台输出中给出。默认报告目录通常是 garak_runs/,可以重点关注三类材料:
- report.jsonl:结构化记录,包括尝试、输出和评估信息;
- hitlog:被判定为命中的样本,适合逐条复核;
- HTML 摘要:适合快速查看不同 probe 的聚合结果。
排障时还可以看 garak.log。
读完一次结果,建议按这个顺序来:
- 先打开 hitlog,确认"命中"究竟是什么输出;
- 再看 detector 是否适用于当前语言和任务;
- 最后才看 ASR、通过率或校准分数。
部分版本还提供 bootstrap 置信区间、Z-score 校准等能力。它们能让统计表达更稳健,但不能修复错误的 probe,也不能修复不合适的 detector。
6. garak 不是什么
这一节比功能清单更重要。
它不是运行时护栏
garak 主要用于上线前评估、版本对比和回归测试,不会在生产流量里实时拦截风险。扫描发现问题之后,仍然需要输入输出管控、权限隔离、工具审批、审计和处置策略。
它不是零日攻击发现器
大量 probe 的本质是已知攻击样本库。它很适合回答"这些已知打法能不能打穿",不等于能自动发现所有新型攻击。
它不是模型能力排行榜
garak 的分数描述的是特定安全失败模式,不代表推理、编程或知识能力。一个更聪明的模型,不一定在这些测试上更安全。
它默认不测"误杀"
只看攻击样本,会漏掉另一个重要维度:模型是不是把正常请求也一并拒绝了。一个对所有问题都拒答的系统,可能在部分攻击测试里表现很好,却没有实际可用性。
因此,真正做护栏或模型评估时,还需要额外的良性样本集来测误伤率。漏放和误杀要一起看。
它看不到文本之外的副作用
这是测试 Agent 时最大的边界。
garak 的基本闭环是"输入提示---得到文本---判定文本"。但 Agent 的风险常常发生在中间:它可能调用 shell、读写文件、访问网络、修改代码,最后只回复一句"已完成"。
如果 detector 只看最后这句话,它就无法判断中间到底发生了什么。
所以,用 garak 测 codex 这类工具时,得到的首先是文本层面的攻击结果,不能直接等价为"Agent 不会执行危险操作"。要测后者,还需要把工具调用轨迹、权限和实际副作用纳入观测。
7. 总结:garak 的真正价值是什么
garak 的价值,不是给模型发一张"安全证书",而是把安全测试从"随手试几句"变成三件可管理的东西:
- 可重复的攻击样本;
- 可检查的判定过程;
- 可留存、可比较的审计记录。
但它的结论只在几个条件内成立:这批 probe、这些 buff、这个 detector、这组采样参数,以及这个目标形态。
后面用它测 DeepSeek,真正要解决的是接口接入、中文攻击样本和中文判定可靠性;用它测 codex,则要进一步面对一个更难的问题:当风险发生在工具调用里,而不是最终文本里,我们应该怎样定义"命中"。
这才是从"会用 garak"走向"会做 LLM / Agent 安全评估"的分界线。
参考资料
- garak GitHub:github.com/NVIDIA/gara...
- garak 用户指南:docs.garak.ai
- garak 参考文档:reference.garak.ai
- 论文:garak: A Framework for Security Probing Large Language Models :arxiv.org/abs/2406.11...
- OWASP Top 10 for LLM Applications:genai.owasp.org/llm-top-10/