garak 入门:别急着扫,先看懂一条数据是怎么被判“命中”的

5 阅读1分钟

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 的一生

与其背组件定义,不如跟着一条数据走一遍。

Probe 取出攻击提示
  →(可选)Buff 做编码、改写或翻译变异
  → Generator 统一调用目标模型
  → 同一提示重采样多次,得到文本输出
  → Detector 对每条输出判定 hit / pass
  → Evaluator 聚合结果
  → report.jsonl / hitlog / HTML 摘要

一次典型过程是:

  1. Probe 取出一条攻击提示。 例如一段 DAN 越狱话术,或者一条经过编码的注入指令。
  2. 可选地经过 Buff 变异。 原始提示可以被转换成另一种表示形式,用来测试模型是否仍能识别其中的恶意意图。
  3. Generator 把提示发给目标。 无论背后是 OpenAI 兼容接口、Hugging Face 模型还是自定义 REST 服务,上层看到的都是统一的调用抽象。
  4. 目标返回文本输出。 同一提示可以重采样多次,而不是只问一次。
  5. Detector 对每条输出做判定。 判定方式可能是关键词、正则、分类器,也可能是另一个模型充当 judge。
  6. Evaluator 聚合结果。 最终形成通过率、失败率或攻击成功率,并写入结构化报告和命中日志。

如果某次输出被判定为出现了不期望行为,就记为一次 hit。粗略地说:

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 下可以这样准备:

python3.13 -m venv .venv
source .venv/bin/activate
python -m pip install -U garak

garak --version
garak --list_probes

如果想看某个 probe 的说明、分级和标签:

garak --list_probes -v --spec probes.dan
garak --plugin_info probes.dan.Dan_11_0

5.2 跑一个小范围扫描

以官方 README 的 OpenAI API 示例为例,模型名请替换成你实际可用的测试模型:

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。

读完一次结果,建议按这个顺序来:

  1. 先打开 hitlog,确认“命中”究竟是什么输出;
  2. 再看 detector 是否适用于当前语言和任务;
  3. 最后才看 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 安全评估”的分界线。


参考资料