关于 blue-team
blue-team 是针对 red-team 测试或 CI 报告中的具体失败目录进行修复的防御技能。它每次处理一个根因类别,只有在故障减少且没有回归时才保留补丁。
主要功能
- 01导入 red-team 或 JUnit 故障
- 02按根因类别归组案例
- 03使用回归防护验证修复
- 04逐项保留或撤销补丁
- 05跟踪残留故障与迭代预算
- 06准备 PR 交接材料
适用场景
- 01修复 red-team 测试发现的问题
- 02处理一批 CI 测试失败
- 03加固过滤器并检查新增误报
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ gaasher/ agent-loop-skills --skill blue-team安装后在 Claude Code 中输入/blue-team确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
examples/run.example.yamltests.run.yamltools/ingest.pyverify.py详细介绍
蓝队
一个防御性修复循环——与 red-team 相反。现在可以修改目标产物;反馈信号由两部分组成,类似于 optimize-loop:一个必须保持通过的门槛(之前通过的内容不能回归),以及一个必须下降的指标(未解决失败类别的数量,目标为零)。将一组具体失败案例交给它,逐个根因类别进行修复。每次迭代修复一个类别,然后运行 tools/verify.py;只有在修复该类别且没有回归时才保留补丁,否则就撤销。持续循环,直到所有类别都已解决(归零)或预算耗尽,然后将补丁集作为拉取请求提交。这是查找→修复流程中的修复部分(见配对)。
失败案例来自真实来源;tools/ingest.py 会将它们规范化到同一个目录中:
oracle模式——red-team的failures.jsonl:每个案例都是一个输入,其中目标的判定与真实情况预言机不一致。目标与预言机现在达成一致时,案例即为已解决;回归指某个良性的<holdout>输入新出现了不一致(通常是新增了过度拦截)。tests模式——CI/CD 测试失败报告(pytest --junitxml/ JUnit XML,或失败的节点 ID 列表):每个案例都是一个失败测试。测试现在通过时,案例即为已解决;回归指任何其他原本通过的测试现在失败。
适用场景
用于修复代码或用户拥有的防护栏/分类器/过滤器/提示词/API 中一组具体失败案例——无论是红队目录,还是 CI 运行中的失败测试——在不破坏已有功能的前提下,将未解决类别的数量降至零。class 是循环作为一个整体予以解决的根因组(红队技术,或 CI 失败领域/测试类)。
默认情况下,根据来源选择匹配的模式(红队用 oracle,CI/CD 用 tests)。例外情况:在没有单独功能测试套件的 oracle 模式下,仅用 <holdout> 作为回归防护;在 tests 模式下,由测试套件中此前已通过的测试作为防护。此工具不用于发现新失败(请运行 red-team),也不用于修改真实标准(预言机、测试或 <holdout>)。
设置
以交互方式解析绑定项。如果存在 loop.run.yaml,则加载它,用一行确认各项值,然后跳到循环步骤。否则:在 Claude Code 上(可使用 AskUserQuestion 工具),为每个绑定项推断一个可能的值并给出建议;在其他宿主上,则将每项作为引用提示逐一询问。然后写入 loop.run.yaml,并在创建任何其他文件之前确认。两个配置示例:
examples/run.example.yaml(oracle 模式)和 examples/tests.run.yaml(tests 模式)。
| 绑定项 | 含义 | 默认值 | 推断方式 |
|---|---|---|---|
<source> | 失败用例的来源:oracle(红队)或 tests(CI/CD) | — | 红队 failures.jsonl → oracle;失败的 pytest/JUnit → tests |
<target_files> | 循环可编辑以修复目标的文件 | — | 失败背后的源代码/护栏/分类器 |
<catalogue> | 待解决的失败用例,格式为 JSONL;使用 tools/ingest.py 构建(见下文) | <sandbox_root>/catalogue.jsonl | 红队的 <failures_log>,或 JUnit 报告 |
<oracle_cmd> | (oracle 模式) 真实判定结果(已冻结),与红队相同的 stdin→判定结果约定 | — | 参考检查器/策略实现 |
<holdout> | (oracle 模式) 必须继续通过的良性输入(回归防护) | <sandbox_root>/holdout.jsonl | oracle 判定为正确的已知良性输入 |
<test_cmd> | (tests 模式) 运行测试套件并写入 JUnit XML;回归信息从中读取 | — | pytest --junitxml=<junit>(或任何能生成 JUnit 的运行器) |
<junit> | (tests 模式) <test_cmd> 写入的 JUnit XML 路径 | <sandbox_root>/junit.xml | — |
<iter_strategy> | branches(每个保留的修复对应一个提交 → 纳入 PR)或 snapshots(每次迭代对应一个文件夹) | branches | 工作区有未提交更改/非 git 工作区 → snapshots |
<pr_branch> | 修复提交到的分支,以及 PR 从该分支发起 | blue-team/<tag> | 将今天的日期用作 <tag> |
<sandbox_root> | 快照和运行记录的存放位置 | ./sandbox | — |
<budget> | 最大迭代次数 | 8 | — |
<patience> | 在对某个类别尝试失败 N 次后放弃,并将其标记为遗留项 | 3 | — |
<skill_dir> 是此技能的安装文件夹;写入 loop.run.yaml 时,请替换为实际路径。
先构建目录:使用 tools/ingest.py 将任意来源规范化为 {id, ..., class}:
python3 <skill_dir>/tools/ingest.py --from red-team --in <failures.jsonl> --out <catalogue> # oracle mode
python3 <skill_dir>/tools/ingest.py --from junit --in <report.xml> --out <catalogue> # tests mode
每次迭代的信号是 tools/verify.py,模式需与 <source> 匹配:
# oracle mode — <target_cmd> runs <target_files>, e.g. "python3 ./guardrail.py"
python3 <skill_dir>/tools/verify.py --target "<target_cmd>" --oracle "<oracle_cmd>" \
--catalogue <catalogue> --holdout <holdout>
# tests mode — <test_cmd> writes the JUnit report verify.py then reads
python3 <skill_dir>/tools/verify.py --test-cmd "<test_cmd>" --junit <junit> --catalogue <catalogue>
无论哪种模式,都会打印一个 JSON 对象:
{mode, open_classes, closed_classes, open_count, closed_count, regressions, regression_count, still_failing}。
循环
复制此检查清单,并逐项勾选:
- 第 0 轮 — 基线:在
<source>模式下运行tools/verify.py;将未解决类别 (应与目录一致)记录为当前状态,并确认regression_count为 0 — 如果不是,则目录或 留出集存在问题,请先修复,再处理目标。记录基线行。将<target_files>的原始副本 保存到<sandbox_root>/iter0/(快照模式),或记下分支基点(分支模式)——这就是最终 交接进行差异比较的基线,也是第 1 轮恢复到的快照。 - 在
branches模式下,在新分支上开始运行:git checkout -b <pr_branch>。 - 对于第 N 轮(≥1):在编辑之前,将当前、修改前的
<target_files>快照保存到iter<N>/(或记下 git HEAD),以便丢弃时能精确恢复到此状态。 - 选择一个未解决类别。阅读目录中的
still_failing示例和建议的修复方案,并从 根本原因入手修改<target_files>— 一项修复应关闭该类别的所有载荷(例如,只 需统一规范大小写一次,而不是为每个关键词分别处理)。每轮只处理一个类别,以便明确 归因每次改动。 - 检查信号:运行
tools/verify.py。如果regression_count > 0(门槛),或目标类别 仍未解决,则丢弃 — 恢复快照 / 执行git reset --hard。verify.py的回归检查 就是门槛:在 oracle 模式下,回归指新变为失败的<holdout>用例(例如,某项修复因 过度拦截良性输入而关闭了绕过);在 tests 模式下,回归指补丁破坏了任何此前通过的测试。 - 如果没有回归且
open_count严格下降,则保留。在branches模式下提交:git commit -am "close <class>: <one-line fix>"。追加一行台账记录。 - 如果某个类别经过
<patience>次尝试仍未解决,则将其标记为未解决残项并继续处理, 不要反复折腾。当open_count= 0(已清空)、达到<budget>,或所有剩余类别都是残项时 停止。<budget>计算的是尝试次数(每次保留或丢弃都算一轮),而非已关闭的类别数 — 丢弃也会消耗预算。
停止时,将工作文件恢复到最佳轮次(关闭类别最多且无回归),并报告:已关闭类别与残项数量、 已解决的失败(oracle 模式:绕过 / 过度拦截的分类),以及避免的回归。然后创建拉取请求(参见 交接)。
修复工具包。 在 tests 模式下,补丁是常规缺陷修复,按失败领域分组,每轮处理一个领域。
在 oracle 模式下(强化防护规则 / 过滤器),可参考以下根因修复模式,对应红队攻击工具包:
- 匹配前先规范化 — 大小写折叠、去 leet 化(同形异义字符 / leet → 字母)、去除空格和标点, 对 unicode 进行 NFKC 规范化。一次规范化即可关闭大小写 / leetspeak / 空格类问题。
- 扩展策略覆盖范围 — 将缺失的同义词 / 扩展词加入拦截集合(
missing-synonym类别), 按 oracle 的分类处理,而非临时添加字符串。 - 收紧过宽规则 — 将匹配范围限定为完整单词 / 正确上下文,避免误触发良性输入(
overblock类别);这是最常见的回归来源。
注意交互顺序(两种模式均适用):先修复收窄范围 / 过宽规则的问题,再做大范围修复。
去除分隔符的修复(关闭 spacing)可能会将良性输入重新组合成过宽子串,悄然导致
overblock 类别再次出现 — 大范围代码改动也可能重新引入较窄修复原本防住的测试失败。先修复
范围较窄 / 过宽的情况,再推广处理。
Ledger
<sandbox_root>/ledger.tsv,以制表符分隔,描述中绝不使用逗号。regr = regression_count
本次迭代(门槛:0 表示通过);status ∈ {keep,discard,baseline,residual}。表头
iter class_targeted regr open_classes status description:
iter class_targeted regr open_classes status description
0 - 0 5 baseline catalogue: 5 open classes
1 case-bypass 0 4 keep case-fold the input before matching
2 leetspeak 1 4 discard de-leet regex also over-blocked a holdout input (regression)
3 leetspeak 0 3 keep de-leet via translate table, holdout clean
4 missing-synonym 0 2 keep add passphrase/credentials/api-key to the policy set
5 overblock 0 1 keep require whole-word "secret key", not bare "secret"
6 spacing 0 0 keep strip non-alphanumerics before matching — dry
报告最佳迭代(regr 为 0 且 open_classes 最低的迭代),不一定是最后一次。
约束
- 只能编辑
<target_files>。 真实依据——oracle +<holdout>(oracle 模式)或测试套件(tests 模式)——以及tools/verify.py都是冻结的;编辑用于衡量修复的内容等于人为制造通过(与 red-team 和 optimize-loop 的规则相同)。如果 oracle 或测试本身有误,应将其报告为发现,而不是在此处修补。 - 修复根因,而不是载荷。 一项修复应关闭某个类别的所有条目;只修补单个示例字符串,而同类项仍然失败,意味着该类别并未关闭。这与 red-team 的类别计数方式一致,确保两个循环对“关闭”的定义相同。
- 回归门槛不可妥协。 如果补丁破坏了之前通过的内容——新增过度拦截/绕过(oracle 模式)或导致之前通过的测试失败(tests 模式)——这就是回归,而非进展;无论关闭了多少类别,都必须撤销。优先采用范围更窄的修复,而非大范围修改。
- 每次迭代处理一个类别,以便明确归因每次改动,并能低成本撤销错误修复。
- 修改须限于项目现有依赖集(标准库即可);操作范围限于仓库和
<sandbox_root>;不要暂停循环询问是否继续——一直运行,直到没有待处理项、预算耗尽或只剩残留问题。
交接:拉取请求
交付物是一份便于人工审查的拉取请求——这是与目标负责人沟通的接口(与 Copilot Autofix 一样,最终审批权由人工保留)。停止时,确保工作树处于最佳迭代状态:
- 在
branches模式下,每项保留的修复都已作为提交保存在<pr_branch>上,提交说明写明类别 + 一行修复内容。推送并使用gh pr create创建 PR,正文使用 ledger(问题目录 → 修复、已关闭的类别、列出的残留问题、避免的回归),并为每个已关闭类别提供一个可复现示例。 - 创建 PR 前确认一次——推送分支和创建 PR 会对外产生影响;绝不可静默自动推送。
- **降级处理,不要失败:**如果没有远程仓库,或
gh不可用/未通过身份验证,仍须完成交接——将提交保留在<pr_branch>上,在<sandbox_root>中写入git format-patch输出和PR_BODY.md,并告知用户一条可自行创建 PR 的命令。在snapshots模式(无 git)下,则输出<target_files>相对于iter0/基线副本的统一diff,并另附PR_BODY.md。
配对
此技能负责修复——是查找→修复循环的后半部分。它假设问题目录已存在;它自身会关闭类别,但不会查找新问题。
- 查找 —
red-team针对冻结的目标运行 →failures.jsonl(不同类别)。 - 修复(本循环)— 在 red-team 两次运行之间修补目标,使其在门槛下关闭这些类别,绝不要在一次 red-team 运行期间修补。
- 重新验证— 针对已修补目标运行一次全新的
red-team,确认每个类别已关闭,并发现修复引入的任何新类别(本循环中的回归门槛已防护过度拦截方向的风险)。
确保两个 Agent 相互独立——编写问题目录的攻击者不应评估自己的补丁。
purple-team 循环负责协调完整的查找 → 修复 → 重新验证周期,直到一次全新的查找未发现问题;本技能有意仅涵盖修复阶段。