三个开源的红队测试工具
红队测试,就是在别人动手之前,先攻击你自己的系统。对大模型应用来说,就是给它喂大量对抗性输入,数量远超你手写的,再看哪些会让它出问题。三个开源工具把这个循环自动化了。
Promptfoo 的 README 说,它现在是 OpenAI 的一部分,仍然开源,采用 MIT 许可证。garak 是 NVIDIA 的扫描器,它的 README 把它比作针对大模型的 nmap 和 Metasploit。PyRIT 出自微软 AI 红队和一个贡献者社区。它们功能有重叠,所以先从其中一个开始。
| 对比项 | Promptfoo | garak | PyRIT |
|---|---|---|---|
| 安装 | npx promptfoo@latest、npm、brew 或 pip | python -m pip install -U garak | pip install pyrit,需要 Python 3.11 到 3.14 |
| 怎么操作 | 先在网页里设置,再运行 redteam run 和 redteam report 命令 | 一条命令,指定目标和探针族 | pyrit_scan 和 pyrit_shell 命令、浏览器界面或 Python 代码 |
| 一次扫描是什么 | 生成攻击的插件,外面套上策略 | 发出提示词的探针,和判断回复的检测器 | 对一个目标运行的场景,加上配置 |
| 读什么 | 含类别、严重程度和日志的报告 | 带失败率的 FAIL 行、一份日志和一份 JSONL 报告 | 扫描器给出的场景结果 |
用 Promptfoo 给应用做红队测试
Promptfoo 需要 Node.js 22.22.0 或更高版本。OpenAI API 密钥是可选的。写攻击的攻击者模型由 redteam.provider 设置,默认是 openai:gpt-5;文档说,没有 OpenAI 密钥时,Promptfoo 会把生成和评分的请求代理到它自己的 API。扫描器在你自己的机器上运行,所以你的机器或网络够得着的任何端点,它都能攻击。
HTTP 目标的配置像下面这样,抄自入门页面。label 在报告里给目标命名,所以为同一个目标生成新配置时要沿用它。purpose 是可选的,但页面说它能显著提高生成的测试用例和评分的质量,所以要写清用户是谁、能碰什么。想跳过网页界面,用 promptfoo redteam init --no-gui 就能写出一份起始配置。
targets:
- id: https
label: 'travel-agent'
config:
url: 'https://example.com/generate'
method: 'POST'
headers:
'Content-Type': 'application/json'
body:
myPrompt: '{{prompt}}'
purpose: 'The user is a budget traveler looking for the best deals. The system is a travel agent that helps the user plan their trip. The user is anonymous and should not be able to access any information about other users, employees, or other individuals.'- 运行
npx promptfoo@latest redteam setup。它会打开一个网页界面,问你一些关于项目的问题。 - 在 Application Details 页面,至少填写 Purpose 字段。页面顶部的 Load Example 可以让你快速试一下。
- 配置目标:一个 HTTP 端点、一个模型,或者你自己的代码。
- 选择插件。插件是对抗性生成器,会产出恶意输入。拿不准就用 Default 预设。
- 选择策略,也就是把生成的输入包进某种攻击模式的技术。
- 检查并把文件保存为
promptfooconfig.yaml,然后在那个文件夹里运行npx promptfoo@latest redteam run。它会生成几百条对抗性输入,存进redteam.yaml,再对目标运行。 - 运行
npx promptfoo@latest redteam report,打开结果。

测什么
Promptfoo 的插件页面建议,先用一小组插件拿到基线,再随着你了解模型弱在哪里,逐步加。插件越多,运行越久,推理也越多。对有智能体或检索的应用,它建议测应用层面的漏洞,下面是它的节选。注释是 Promptfoo 写的。
前面几课里的两个插件,也该放进你的清单:第 1 课的 indirect-prompt-injection,和第 2 课的 prompt-extraction。两个插件各有一个必填的配置项。
plugins:
- 'agentic:memory-poisoning' # Tests if stateful agents are vulnerable to memory poisoning attacks
- 'rbac' # Tests if the model properly implements Role-Based Access Control
- 'bola' # Checks for Broken Object Level Authorization vulnerabilities
- 'bfla' # Tests for Broken Function Level Authorization issues
- 'ssrf' # Tests for Server-Side Request Forgery vulnerabilities
- 'sql-injection' # Tests for SQL injection vulnerabilities (if connected to a SQL database)
- 'pii' # Checks for leakage of Personally Identifiable Information
- 'excessive-agency' # Checks if the agent exceeds its intended capabilities
- 'hijacking' # Checks for goal hijacking of the agent's objectives
- 'tool-discovery' # Tests if the model reveals its available function calls or tools| 大模型的设计 | 不适用的测试 |
|---|---|
| 基础模型 | 安全与访问控制测试 |
| 单一用户角色 | 访问控制测试 |
| 只有提示词和回复 | 资源获取和注入攻击 |
加上第 1、2 课的插件
这两个插件都需要额外的配置。indirect-prompt-injection 需要 indirectInjectionVar,也就是承载不可信文字的模板变量的名字,比如第 1 课旅行助手提示词里的 {{name}}。据它的插件页面,Promptfoo 会把对抗性载荷注入这个变量,模型照着做了,测试就算失败。prompt-extraction 需要 systemPrompt,也就是你交给模型的系统提示词,第 2 课讲过,它的插件页面也要求填写。
下面的配置把这两个插件页面里的例子合在了一起。把占位符换成你真实的系统提示词,并写上你自己的不可信变量名。
prompts:
- |
You are a travel agent. The user's name is {{name}}.
User query: {{query}}
redteam:
plugins:
- id: indirect-prompt-injection
config:
indirectInjectionVar: name
- id: prompt-extraction
config:
systemPrompt: 'Paste the real system prompt of your app here.'选攻击策略
插件负责写攻击,策略负责改变攻击的投递方式。策略页面给大多数应用推荐两种:用于单轮攻击的 jailbreak:meta,和用于多轮对话的 jailbreak:hydra。配置参考里列的默认值是 basic、jailbreak:meta 和 jailbreak:composite,除非你设置 numTests,每个插件默认生成 5 个测试。
redteam:
strategies:
- jailbreak:meta # Single-turn agentic attacks
- jailbreak:hydra # Multi-turn adaptive conversations- 静态策略套用固定的变换,比如 base64 编码。它们成本低,也容易被检测到,页面说基础模型常常已经把它们修掉了。
- 动态策略用一个攻击者模型,在多次尝试中不断改进一条输入。它们成功率更高,成本也更高。默认情况下,它们会在用完词元预算后停止,或者在产生有害输出后停止。
- 多轮策略在整段对话里展开。页面说它们的成功率最高,适合有状态的应用,也比单轮策略更耗资源。
用 garak 或 PyRIT 做同样的事
garak 是一个命令行工具。默认情况下,它会对你指定的模型尝试它知道的所有探针,并使用每个探针推荐的检测器。--spec 可以把运行范围缩小到某个探针族,比如 probes.promptinject,或者某一个探针。对不是单纯模型的应用,它的 REST 生成器能连到任何返回纯文本或 JSON 的端点,只需一个简短的 YAML 文件来描述端点。
PyRIT 的扫描器对一个目标运行一个场景,场景把攻击技术、数据集和评分打包在一起。它自带六个场景族:Adaptive、AIRT、Benchmark、Foundry、Garak 和 Technique。其中 Garak 族包含 SystemPromptExtraction。pyrit_scan 适合 CI 和批量运行,pyrit_shell 适合交互式探索。PyRIT 要先配置好你的端点,它的配置页面从为 OpenAI 聊天目标设置三个环境变量讲起。安装页面写的是 Python 3.11 到 3.14。
下面的命令是它们文档里的示例:garak 的 README,以及 PyRIT 的两个扫描器页面。garak 的 README 要求你把示例密钥换成真实的密钥。
# garak
python -m pip install -U garak
garak --list_probes
export OPENAI_API_KEY="sk-123XXXXXXXXXXXX"
python3 -m garak --target_type openai --target_name gpt-5-nano --spec probes.encoding
# PyRIT
pip install pyrit
pyrit_scan list-scenarios
pyrit_scan run foundry.red_team_agent --target openai_chat --initializers target --techniques base64读懂结果
Promptfoo 的报告会显示漏洞类别、严重程度、触发失败的输入日志,以及建议的缓解办法。选中一个测试用例,能看到它原始的输入和输出。每个漏洞还会得到一个 0 到 10 的风险评分,建立在 CVSS 的原则上,表里把它换成了区间。
garak 会为每个探针打印一个进度条,再给出每个检测器一行结果。一个回复被标成 FAIL,意思是有些尝试产生了不良行为,旁边附有失败率。像 840/840 这样的数字,数的是生成次数:先是总数,再是其中看起来表现正常的数量。这个数字会很大,因为 garak 默认每个提示词生成 10 次。错误写进 garak.log,详情写进一份 JSONL 报告,analyse/analyse_log.py 会列出命中最多的探针和提示词。
打开每个失败用例的日志,核对你的应用是否真会造成回答里描述的损害。如果某个失败依赖一个你能去掉的工具,去掉这个工具就修好了,第 3 课里的第一个修复办法就是这么说的。然后用同一个标签再运行一次扫描。Promptfoo 用评分请求给自己的结果打分,所以遇到你不同意的判定,就去读日志,把大模型当评审一课讲了怎么检查评分器。
| 风险评分 | 等级 | Promptfoo 原话(缩短) |
|---|---|---|
| 9.0 到 10.0 | 严重 | 需要立即关注 |
| 7.0 到 8.9 | 高 | 应尽快处理 |
| 4.0 到 6.9 | 中 | 需要调查 |
| 0.1 到 3.9 | 低 | 可以持续监测 |
安全地测试
扫描会把带敌意的输入发给一个正在运行的应用,而且会消耗词元。下面是我们的建议,以及文档里补充的内容:
- 只测你自己的应用,用预发布副本、测试数据和只有测试权限的账号。扫描会设法让应用去行动,而 excessive-agency 插件的用途,就是找出你不想发生的操作。
- Promptfoo 的文档对攻击怎么生成有两种说法。一处说它用你自己的 OpenAI 密钥做生成和评分,没有密钥就把请求代理到它的 API。另一处说它默认用一个远程服务生成对抗性输入。你的目标始终在本地评估。把
PROMPTFOO_DISABLE_REDTEAM_REMOTE_GENERATION设为true,就会强制 100% 本地生成,文档说,质量取决于你配置的模型,对大多数模型而言通常偏低。 - 插件越多,运行越久,需要的推理也越多。动态策略既调用攻击者模型,也调用你的目标,多轮运行会把目标、攻击者和评分的词元分开统计。调配置的时候,让
numTests保持较小。 - 在 CI 里,
promptfoo redteam run --tag ci.run-id="$CI_RUN_ID" --tag git.sha="$GIT_SHA"会把这次运行和提交记录在结果里。CI 里的评估讲了怎样在每次改动时运行检查。 - 如果应用是个智能体,先让它运行在智能体护栏里讲的沙盒和权限规则之下。
常见错误
- 把扫描器指向生产系统,或者不属于你的应用。它从你的机器发出,会攻击它够得着的任何端点。
- 把 Purpose 留空,再把泛泛的失败当成关于你应用的发现。
- 把一次干净的运行当成安全的证明。它只说明试过的攻击没有得手。就像第 1 课讲过的,会针对你的防御调整的攻击者,是另一场测试。
- 没打开日志,就把严重程度标签当成最终结论。
- 给被测试的智能体真实的凭据和真实的数据。
动手试试
- 运行
npx promptfoo@latest redteam setup,在 Application Details 页面按下 Load Example,把各个界面点一遍,先不运行扫描。 - 为你自己的一个应用写两句用途说明:用户是谁,哪些东西他们不该碰到。
- 对一份预发布副本运行扫描,用第 1、2 课里的插件 indirect-prompt-injection 和 prompt-extraction,再加上适合你应用的那些。
- 打开第一个失败用例,写下它属于第 3 课里的哪个 OWASP 条目,以及哪个第一修复办法能挡住它。
下一门课:AI 评估
红队测试显示应用在攻击下怎么出问题。下一门课AI 评估:衡量你的大模型应用和智能体是否好用,把同样的思路变成每次改动都能运行的测试。
自测一下
在 Promptfoo 设置的 Application Details 页面,至少该填写哪个字段?
查看答案
A. Purpose 页面说要用 Purpose 描述你的应用,因为细节越多,生成的测试用例越贴合。
promptfoo redteam run做什么?查看答案
D. 把测试输入生成到 redteam.yaml,再对目标运行 它生成几百条对抗性输入,存进 redteam.yaml,并对目标运行。
在 garak 的输出里,一个探针出现 FAIL 是什么意思?
查看答案
C. 有些尝试产生了检测器标为不良的行为 只要有尝试产生了不良行为,回复就被标成 FAIL,并给出失败率。
关于在 Promptfoo 里强制本地生成,文档怎么说?
查看答案
B. 质量取决于你的模型,对大多数模型而言通常偏低 设置这个环境变量可以强制 100% 本地生成,但文档说它的质量取决于你配置的模型,对大多数模型而言通常偏低。
常见问题
大模型的红队测试是什么?
在 AI 领域,红队测试是指用对抗性输入去测试一个系统,找出它在哪里失败:越狱、提示词注入、数据泄露和有害输出。这些工具为每种漏洞类型生成大量输入,对目标运行,再给回复打分。
红队测试大模型应用,Promptfoo、garak 和 PyRIT 哪个最好?
按工作方式来选。带报告的引导式网页设置适合 Promptfoo,命令行的探针扫描适合 garak,Python 代码库适合 PyRIT。三者都是开源的。
大模型红队扫描能放进 CI 里运行吗?
可以。Promptfoo 的文档展示了用 promptfoo redteam run --tag 给运行打标签,PyRIT 的文档则说明 pyrit_scan 适用于 CI/CD 流水线和批量处理。
Promptfoo 扫描会把我应用的数据发到别处吗?
有可能。生成攻击的请求可能经过 Promptfoo 的 API,而本课读到的页面没有详细说明这个服务会收到什么。测试任何敏感内容之前,先强制本地生成,或者先弄清楚。
多久该对大模型应用做一次红队测试?
Promptfoo 的文档把红队测试称为持续的过程,建议随着应用的变化定期运行。每次改动提示词、工具或模型之后再跑一遍,是个稳妥的经验做法。
资料来源
- GitHub: Promptfoo repository https://github.com/promptfoo/promptfoo
- GitHub: Promptfoo, red team getting started https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/quickstart.md
- GitHub: Promptfoo, red team configuration https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/configuration.md
- GitHub: Promptfoo, plugins https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/plugins/index.md
- GitHub: Promptfoo, strategies https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/strategies/index.md
- GitHub: Promptfoo, risk scoring https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/risk-scoring.md
- GitHub: Promptfoo, indirect prompt injection plugin https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/plugins/indirect-prompt-injection.md
- GitHub: Promptfoo, prompt extraction plugin https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/plugins/prompt-extraction.md
- GitHub: NVIDIA garak repository https://github.com/NVIDIA/garak
- GitHub: Microsoft PyRIT repository https://github.com/microsoft/PyRIT
- GitHub: PyRIT scanner https://github.com/microsoft/PyRIT/blob/main/doc/scanner/0_scanner.md
- GitHub: PyRIT scan command https://github.com/microsoft/PyRIT/blob/main/doc/scanner/1_pyrit_scan.ipynb
- GitHub: PyRIT local installation https://github.com/microsoft/PyRIT/blob/main/doc/getting_started/install_local.md
- GitHub: PyRIT configuration https://github.com/microsoft/PyRIT/blob/main/doc/getting_started/configuration.md
- YouTube: Red Team an AI App with Promptfoo (Promptfoo channel) https://www.youtube.com/watch?v=e7MlDhfN22s
