# 对你自己的大模型应用做红队测试：Promptfoo、garak 与 PyRIT，测什么，怎么读结果

> 对大模型应用做红队测试，就是在别人动手之前，自己用生成的对抗性输入去攻击它。Promptfoo、NVIDIA 的 garak 和微软的 PyRIT 都是开源工具，它们生成攻击，对你的应用运行，再报告哪些攻击得手了。先用几句话写明应用是做什么的，运行一次扫描，再逐个读失败的用例。

Mindket 编辑部 · 发布于 2026-11-06 · 更新于 2026-11-06 · https://mindket.com/cn/learn/ai-security/red-team-llm-app

## 要点

- 运行任何扫描之前，先用两句话写明应用的用途，因为生成的攻击是围着它来的。
- 扫描只对一份预发布副本运行，副本里只放测试数据和测试权限。
- 读每个失败用例背后的日志，问一问你的应用是否真会造成所展示的损害。
- 每个目标只用一个标签，每次修复之后再运行一次扫描。

## 三个开源的红队测试工具

红队测试，就是在别人动手之前，先攻击你自己的系统。对大模型应用来说，就是给它喂大量对抗性输入，数量远超你手写的，再看哪些会让它出问题。三个开源工具把这个循环自动化了。

[Promptfoo 的 README](https://github.com/promptfoo/promptfoo) 说，它现在是 OpenAI 的一部分，仍然开源，采用 MIT 许可证。[garak](https://github.com/NVIDIA/garak) 是 NVIDIA 的扫描器，它的 README 把它比作针对大模型的 nmap 和 Metasploit。[PyRIT](https://github.com/microsoft/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 目标的配置像下面这样，抄自[入门页面](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/quickstart.md)。`label` 在报告里给目标命名，所以为同一个目标生成新配置时要沿用它。`purpose` 是可选的，但页面说它能显著提高生成的测试用例和评分的质量，所以要写清用户是谁、能碰什么。想跳过网页界面，用 `promptfoo redteam init --no-gui` 就能写出一份起始配置。

````yaml
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.'
````

1. 运行 `npx promptfoo@latest redteam setup`。它会打开一个网页界面，问你一些关于项目的问题。
2. 在 Application Details 页面，至少填写 Purpose 字段。页面顶部的 Load Example 可以让你快速试一下。
3. 配置目标：一个 HTTP 端点、一个模型，或者你自己的代码。
4. 选择插件。插件是对抗性生成器，会产出恶意输入。拿不准就用 Default 预设。
5. 选择策略，也就是把生成的输入包进某种攻击模式的技术。
6. 检查并把文件保存为 `promptfooconfig.yaml`，然后在那个文件夹里运行 `npx promptfoo@latest redteam run`。它会生成几百条对抗性输入，存进 `redteam.yaml`，再对目标运行。
7. 运行 `npx promptfoo@latest redteam report`，打开结果。

[Red Team an AI App with Promptfoo](https://www.youtube.com/watch?v=e7MlDhfN22s)

Promptfoo 频道在 YouTube 上的演示视频。

## 测什么

Promptfoo 的[插件页面](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/plugins/index.md)建议，先用一小组插件拿到基线，再随着你了解模型弱在哪里，逐步加。插件越多，运行越久，推理也越多。对有智能体或检索的应用，它建议测应用层面的漏洞，下面是它的节选。注释是 Promptfoo 写的。

前面几课里的两个插件，也该放进你的清单：第 1 课的 indirect-prompt-injection，和第 2 课的 prompt-extraction。两个插件各有一个必填的配置项。

````yaml
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 课](https://mindket.com/cn/learn/ai-security/prompt-injection)旅行助手提示词里的 `{{name}}`。据它的[插件页面](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/plugins/indirect-prompt-injection.md)，Promptfoo 会把对抗性载荷注入这个变量，模型照着做了，测试就算失败。prompt-extraction 需要 `systemPrompt`，也就是你交给模型的系统提示词，[第 2 课](https://mindket.com/cn/learn/ai-security/llm-jailbreaks)讲过，它的[插件页面](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/plugins/prompt-extraction.md)也要求填写。

下面的配置把这两个插件页面里的例子合在了一起。把占位符换成你真实的系统提示词，并写上你自己的不可信变量名。

````yaml
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.'
````

## 选攻击策略

插件负责写攻击，策略负责改变攻击的投递方式。[策略页面](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/strategies/index.md)给大多数应用推荐两种：用于单轮攻击的 jailbreak:meta，和用于多轮对话的 jailbreak:hydra。[配置参考](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/configuration.md)里列的默认值是 basic、jailbreak:meta 和 jailbreak:composite，除非你设置 numTests，每个插件默认生成 5 个测试。

````yaml
redteam:
  strategies:
    - jailbreak:meta # Single-turn agentic attacks
    - jailbreak:hydra # Multi-turn adaptive conversations
````

- 静态策略套用固定的变换，比如 base64 编码。它们成本低，也容易被检测到，页面说基础模型常常已经把它们修掉了。
- 动态策略用一个攻击者模型，在多次尝试中不断改进一条输入。它们成功率更高，成本也更高。默认情况下，它们会在用完词元预算后停止，或者在产生有害输出后停止。
- 多轮策略在整段对话里展开。页面说它们的成功率最高，适合有状态的应用，也比单轮策略更耗资源。

## 用 garak 或 PyRIT 做同样的事

[garak](https://github.com/NVIDIA/garak) 是一个命令行工具。默认情况下，它会对你指定的模型尝试它知道的所有探针，并使用每个探针推荐的检测器。`--spec` 可以把运行范围缩小到某个探针族，比如 `probes.promptinject`，或者某一个探针。对不是单纯模型的应用，它的 REST 生成器能连到任何返回纯文本或 JSON 的端点，只需一个简短的 YAML 文件来描述端点。

PyRIT 的[扫描器](https://github.com/microsoft/PyRIT/blob/main/doc/scanner/0_scanner.md)对一个目标运行一个场景，场景把攻击技术、数据集和评分打包在一起。它自带六个场景族：Adaptive、AIRT、Benchmark、Foundry、Garak 和 Technique。其中 Garak 族包含 SystemPromptExtraction。`pyrit_scan` 适合 CI 和批量运行，`pyrit_shell` 适合交互式探索。PyRIT 要先配置好你的端点，它的[配置页面](https://github.com/microsoft/PyRIT/blob/main/doc/getting_started/configuration.md)从为 OpenAI 聊天目标设置三个环境变量讲起。[安装页面](https://github.com/microsoft/PyRIT/blob/main/doc/getting_started/install_local.md)写的是 Python 3.11 到 3.14。

下面的命令是它们文档里的示例：garak 的 README，以及 PyRIT 的两个扫描器页面。garak 的 README 要求你把示例密钥换成真实的密钥。

````bash
# 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 的[风险评分](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/risk-scoring.md)，建立在 CVSS 的原则上，表里把它换成了区间。

garak 会为每个探针打印一个进度条，再给出每个检测器一行结果。一个回复被标成 FAIL，意思是有些尝试产生了不良行为，旁边附有失败率。像 840/840 这样的数字，数的是生成次数：先是总数，再是其中看起来表现正常的数量。这个数字会很大，因为 garak 默认每个提示词生成 10 次。错误写进 `garak.log`，详情写进一份 JSONL 报告，`analyse/analyse_log.py` 会列出命中最多的探针和提示词。

打开每个失败用例的日志，核对你的应用是否真会造成回答里描述的损害。如果某个失败依赖一个你能去掉的工具，去掉这个工具就修好了，[第 3 课](https://mindket.com/cn/learn/ai-security/owasp-llm-top-10)里的第一个修复办法就是这么说的。然后用同一个标签再运行一次扫描。Promptfoo 用评分请求给自己的结果打分，所以遇到你不同意的判定，就去读日志，[把大模型当评审](https://mindket.com/cn/learn/ai-evals/llm-as-a-judge)一课讲了怎么检查评分器。

| 风险评分 | 等级 | 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 里的评估](https://mindket.com/cn/learn/ai-evals/evals-in-ci)讲了怎样在每次改动时运行检查。
- 如果应用是个智能体，先让它运行在[智能体护栏](https://mindket.com/cn/learn/harness-engineering/agent-guardrails)里讲的沙盒和权限规则之下。

## 常见错误

- 把扫描器指向生产系统，或者不属于你的应用。它从你的机器发出，会攻击它够得着的任何端点。
- 把 Purpose 留空，再把泛泛的失败当成关于你应用的发现。
- 把一次干净的运行当成安全的证明。它只说明试过的攻击没有得手。就像第 1 课讲过的，会针对你的防御调整的攻击者，是另一场测试。
- 没打开日志，就把严重程度标签当成最终结论。
- 给被测试的智能体真实的凭据和真实的数据。

## 动手试试

- 运行 `npx promptfoo@latest redteam setup`，在 Application Details 页面按下 Load Example，把各个界面点一遍，先不运行扫描。
- 为你自己的一个应用写两句用途说明：用户是谁，哪些东西他们不该碰到。
- 对一份预发布副本运行扫描，用第 1、2 课里的插件 indirect-prompt-injection 和 prompt-extraction，再加上适合你应用的那些。
- 打开第一个失败用例，写下它属于第 3 课里的哪个 OWASP 条目，以及哪个第一修复办法能挡住它。

## 下一门课：AI 评估

红队测试显示应用在攻击下怎么出问题。下一门课[AI 评估：衡量你的大模型应用和智能体是否好用](https://mindket.com/cn/learn/ai-evals/what-are-llm-evals)，把同样的思路变成每次改动都能运行的测试。

## 自测一下

1. 在 Promptfoo 设置的 Application Details 页面，至少该填写哪个字段？

   A. Purpose
   B. Strategies
   C. Severity
   D. Tags

   答案：A。 页面说要用 Purpose 描述你的应用，因为细节越多，生成的测试用例越贴合。

2. `promptfoo redteam run` 做什么？

   A. 在浏览器里打开报告
   B. 安装这个工具
   C. 只检查配置文件
   D. 把测试输入生成到 redteam.yaml，再对目标运行

   答案：D。 它生成几百条对抗性输入，存进 redteam.yaml，并对目标运行。

3. 在 garak 的输出里，一个探针出现 FAIL 是什么意思？

   A. 工具崩溃了
   B. 探针被跳过了
   C. 有些尝试产生了检测器标为不良的行为
   D. 找不到目标模型

   答案：C。 只要有尝试产生了不良行为，回复就被标成 FAIL，并给出失败率。

4. 关于在 Promptfoo 里强制本地生成，文档怎么说？

   A. 速度更快，质量不变
   B. 质量取决于你的模型，对大多数模型而言通常偏低
   C. 它会关闭评分
   D. 它让你不再需要目标

   答案：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 仓库](https://github.com/promptfoo/promptfoo) (2026-11-06 查阅)
- [GitHub：Promptfoo，红队测试入门](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/quickstart.md) (2026-11-06 查阅)
- [GitHub：Promptfoo，红队测试配置](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/configuration.md) (2026-11-06 查阅)
- [GitHub：Promptfoo，插件](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/plugins/index.md) (2026-11-06 查阅)
- [GitHub：Promptfoo，策略](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/strategies/index.md) (2026-11-06 查阅)
- [GitHub：Promptfoo，风险评分](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/risk-scoring.md) (2026-11-06 查阅)
- [GitHub：Promptfoo，间接提示词注入插件](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/plugins/indirect-prompt-injection.md) (2026-11-06 查阅)
- [GitHub：Promptfoo，提示词提取插件](https://github.com/promptfoo/promptfoo/blob/main/site/docs/red-team/plugins/prompt-extraction.md) (2026-11-06 查阅)
- [GitHub：NVIDIA garak 仓库](https://github.com/NVIDIA/garak) (2026-11-06 查阅)
- [GitHub：微软 PyRIT 仓库](https://github.com/microsoft/PyRIT) (2026-11-06 查阅)
- [GitHub：PyRIT 扫描器](https://github.com/microsoft/PyRIT/blob/main/doc/scanner/0_scanner.md) (2026-11-06 查阅)
- [GitHub：PyRIT 扫描命令](https://github.com/microsoft/PyRIT/blob/main/doc/scanner/1_pyrit_scan.ipynb) (2026-11-06 查阅)
- [GitHub：PyRIT 本地安装](https://github.com/microsoft/PyRIT/blob/main/doc/getting_started/install_local.md) (2026-11-06 查阅)
- [GitHub：PyRIT 配置](https://github.com/microsoft/PyRIT/blob/main/doc/getting_started/configuration.md) (2026-11-06 查阅)
- [YouTube：Red Team an AI App with Promptfoo（Promptfoo 频道）](https://www.youtube.com/watch?v=e7MlDhfN22s) (2026-11-06 查阅)

[什么是大模型评估？](https://mindket.com/cn/learn/ai-evals/what-are-llm-evals)
