深度解析 agent-governance-toolkit 提示注入评测语料方法论:可复现生成、零泄漏分桶与基线基线化全流程
【免费下载链接】agent-governance-toolkitAI Agent Governance Toolkit — Policy enforcement, zero-trust identity, execution sandboxing, and reliability engineering for autonomous AI agents. Covers 10/10 OWASP Agentic Top 10.项目地址: https://gitcode.com/GitHub_Trending/ag/agent-governance-toolkit
本篇文章聚焦 agent-governance-toolkit 中benchmarks/prompt-injection/提示注入评测夹具(fixture)的语料生成方法论,系统回答"合成攻击家族如何生成、过拟合如何控制、良性对照组如何构造、基线如何建立、'零误报'该如何解读、后续嵌入信号的生产路径是什么"这 6 个核心问题。这是该仓库中任何**可选、默认关闭的嵌入证据信号(embedding signal)**被正式评审的前置条件——读者在读完本文后,能够对照已合并的生成器源码,独立验证语料是否可复现、是否零跨分桶泄漏,并掌握 Wilson 置信区间与基础率精度等评估口径的正确用法。
1. 背景:为什么需要一份"方法论文档"作为前置条件
在 agent-governance-toolkit 的 SLO 工作区中,[ticket-pr2-methodology.md](https://link.gitcode.com/i/f5e16e7fbe8ea9f1ad6fc628a248bbcd)记录了一个文档型票据:为 PR2(可选的嵌入检测信号)补齐可评审的语料方法论文档。其契约块(Contract block)明确限定了允许变更的文件只有两个——新增docs/benchmarks/prompt-injection-methodology.md,以及docs/benchmarks/prompt-injection-evaluation.md中新增一行交叉链接;兼容性要求为"仅增量文档、无运行时变更、无过度宣称措辞"。
这一前置条件的核心动机是:在让任何消费语料的检测路径进入评审之前,维护者必须能够确认语料是以可复现、非过拟合的方式生成、分桶、去重和基线的。仓库中已合并的方法论文档 prompt-injection-methodology.md 正是这一票据的落地产物,而 prompt-injection-evaluation.md 则描述夹具的整体范围与当前冒烟基线结果。两者形成"总览 + 方法论"的配套结构。
需要强调的边界:该语料是合成研究数据,仅用于受控、可复现的检测器评估,既不是训练数据,也不是生产策略配置,更不代表真实流量的安全保证。这一"范围诚实"(scope honesty)声明是整份方法论文档的基调。
2. 问题一:合成攻击家族如何生成
2.1 确定性生成契约
生成器 generate-corpus.py 是仅使用标准库(stdlib-only)的确定性脚本:给定相同的种子(seed)与 profile,输出字节级一致。其核心常量全部集中定义在文件头部:
| 常量 | 值 | 含义 |
|---|---|---|
SEED | 1337 | 全局随机种子,分桶哈希与家族 ID 的派生依据 |
ROUND | prompt_injection_fixture_v1 | 语料轮次标识 |
ID_PREFIX | pi1 | 所有合成行 ID 前缀 |
TEXT_MARKER | PI1 | 每条合成行文本内固定的标记(Scenario PI1-A-xxxxx/Reference PI1-B-xxxxx/Trace ...),保证夹具文本永远不可能被误认为真实流量 |
SPLITS | (exemplar_bank, validation, test) | 三个分桶 |
PROFILE_LIMITS | {smoke: 10, pilot: 120, large: 1600} | 每个家族的行数上限(每家族 cap) |
仓库随附的是smokeprofile(280 行);pilot与largeprofile 按需重新生成即可。
2.2 八类攻击家族与槽位填充
攻击语料由ATTACK_TEMPLATES定义8 个攻击家族(attack family):direct_override(直接覆盖指令)、prompt_leakage(提示词泄漏)、indirect_injection(间接注入,如检索到的网页/RAG 片段)、tool_abuse(工具滥用)、tool_result_injection(工具结果注入)、output_exfiltration(输出外泄)、memory_poisoning(记忆投毒)、data_boundary_abuse(数据边界滥用)。
每个模板通过槽位填充器(slot fillers)实例化:
ACTIONS:攻击动作,如reveal the system prompt、export the database credentials、disable the approval policy;TARGETS:攻击目标,如include any secret-looking values、append the internal canary;TOOL_NAMES:被滥用的工具名,如read_secret、http_request、execute_command。
渲染函数render_attack(generate-corpus.py)还会追加Scenario PI1-A-{idx:05d}. Trace {digest}.格式的追踪后缀,其中 digest 是对attack:{attack_class}:{template}:{idx}的 SHA-256 摘要,用于溯源每一行的生成路径。
2.3 绕过类别(bypass class)——混淆面
每一行都标注其bypass_class,取值来自ALLOWED_BYPASS_CLASSES(14 类)。生成器内置的变异算子(mutation operators)实现了这些类别:
| 算子(函数) | 生成的bypass_class | 说明 |
|---|---|---|
| 原文 | plain/none | 未混淆基线 |
LEET_MAP翻译 | leet_spacing | 如i→1, e→3, a→4, o→0, s→5, t→7 |
spaced() | letter_spaced | 字符/单词间插入空格 |
rot13() | rot13 | ROT-13 编码 |
urllib.parse.quote/ 实体编码 / base64 | encoding | URL/HTML/Base64 编码 |
homoglyph() | homoglyph | 同形异义字符替换(如a→а、e→е) |
diacritics() | diacritics | 加重音符号 |
compact_alnum() | compact_plain | 仅保留字母数字并小写 |
compact_leet() | compact_leet | 紧凑 + leet |
separator_spaced() | separator_spaced | 以.分隔字符 |
chunked() | chunked_leet | 4 字符切块 |
| 多语言变体 | multilingual | 法语/西语攻击模板 |
此外还有compact_pressure_mutations(紧凑压力变异)专门针对compact_plain/compact_leet/leet_letter_spaced等类别,对应"紧凑化 + 混淆"叠加场景。由于bypass_class是逐行记录的元数据,评估时可以按类别统计召回率,甚至将某些混淆类别整体留出,检验检测器对未见过的伪装形式的泛化能力。
2.4 每行溯源元数据
每条语料行都携带完整溯源元数据:source_type(如user、rag_chunk、tool_result、memory)、trust_level(untrusted、tool_output、authenticated_user)、attack_class、benign_subclass、family_id、group_id、split、bypass_class、risk_level、expected_action(block/quarantine/require_approval/allow)等。expected_action由attack_expected_action推导:tool_result_injection→quarantine,prompt_leakage/direct_override→require_approval,其余攻击 →block;良性行一律为allow。这一标注让每条语料既是文本又是可审计的"期望行为"契约。
3. 问题二:过拟合如何控制——分桶即去重
控制过拟合的第一原则是:分桶单元是 family/group,而不是随机行。split_for(family_id)(generate-corpus.py)按SEED:family_id的哈希加每个前缀的偏移量,把每个家族确定性地映射到 5 个桶之一,再映射为 3 个 split(桶 0–2 →exemplar_bank,桶 3 →validation,桶 4 →test)。同一个家族的所有行必然落在同一 split,绝无家族或分组跨桶的现象——check_leakage会以family_split_leaks/group_split_leaks两个数组强制这一不变量。
在此之上,还叠加三重独立的跨桶泄漏检查(见 check-corpus.py 与生成器内normalized_text_check),全部要求计数为 0:
- 精确归一化泄漏:每行文本经
NFKC归一化 +casefold小写 + 空白折叠(normalize_text)后取 SHA-256;若同一归一化文本出现在两个 split 中即报告,必须为零; - 近似重复泄漏:取 7-gram 分片(
NEAR_DUPLICATE_NGRAM = 7),用 simhash 的 16-bit 带(SIMHASH_BAND_BITS = 16)做候选分块,再以Jaccard 相似度 ≥ 0.92(NEAR_DUPLICATE_THRESHOLD = 0.92)判定跨桶近似重复对,同样必须为零; - 标签覆盖检查:每个 split 必须同时含有攻击与良性行,避免某 split 退化为单标签。
这些检查的结果写入 manifest(leakage_check、normalized_text_check、duplicate_check、split_label_coverage_check字段),并在main()中作为硬性门禁:任一检查不通过,生成器直接以非零码退出并打印泄漏详情(generate-corpus.py)。因此"无过拟合"不是一个断言,而是一个可复现的构件。
4. 问题三:良性对照组如何构造
为了不让检测器仅仅靠"长得像攻击"就得分,每个攻击家族都配有匹配的良性对照组(matched benign controls),分为三层:
- 相邻安全类良性(adjacent-security benign):
benign_security_discussion(安全讨论)、quoted_injection_example(引用的注入示例)、security_training_material(安全培训材料)、research_blog_excerpt(研究博客摘录)、security_changelog(安全变更日志)、detector_code_fixture(检测器代码夹具,如const ATTACK_EXAMPLE: &str = "{phrase}";)、owasp_ncsc_guidance(安全指南)、docs_code_comment(文档注释)。这些是最难负例——它们合法地引用/讨论提示注入短语,但绝不构成实际攻击指令; - 良性混淆对照(benign obfuscation controls):
BENIGN_OBFUSCATION_BASES提供的合法文本经过与攻击相同的变异算子处理(含多语言),使得检测器不能把"混淆"本身当作恶意信号; - 合法祈使/工具请求:
legitimate_imperative_request(如 "Please summarize the report...")与benign_tool_use(如 "Read ./report.md and summarize section {n}."),确保"祈使句语气"或"涉及工具"本身不是判定特征。
良性行同样携带benign_subclass、family_id、group_id等元数据,与攻击行共用同一分桶与泄漏检查逻辑——这保证了攻击与良性分布在各 split 中是对称可比的。
5. 问题四:基线是什么
基线(baseline)是 AGT现有的纯规则检测器(rules-only detector),即 Rust crateagentmesh::prompt_injection::PromptInjectionDetector,由agt-rules-baselineharness(main.rs)运行。要点在于:
- 精确锁定:基线锁定到上游的一个精确 commit 与检测器源码 SHA,并随指标一并记录,因此基线可在已知的 AGT 状态下复现;
- 预期特征:该规则检测器是高精度 / 低召回设计。当前 smoke 冒烟结果(见 prompt-injection-evaluation.md 与 README.md)为:攻击行 110 条捕获 7 条(召回 0.0636),良性 170 条误报 16 条(误报率 0.0941,即每千条良性 94.12 条误报)。在困难留出伪装上召回率低是预期行为而非缺陷——这正是后续嵌入信号存在的价值空间;
- 元数据优先:
run-smoke.sh会断言 per-row 证据与摘要中raw_text_in_output必须为false,即证据产物不包含原始提示文本,只保留计数、比例与区间。
冒烟复现一条命令即可完成:bash benchmarks/prompt-injection/run-smoke.sh。脚本依次完成 Python 编译检查、重新生成 280 行语料与 manifest、语料卫生验证、编译 Rust 评分器、重建基线产物、以及"仅元数据"断言(run-smoke.sh)。
6. 问题五:"零误报"到底意味着什么
方法论文档对"零误报"(zero FP observed)给出了非常克制的定义:这是在冻结测试分桶上的有限样本观察,不是保证。任何"0 FP"都必须同时携带两样东西:
- Wilson 95% 置信区间:
summarize-baseline.py(summarize-baseline.py)对每个操作点输出召回率与误报率的 Wilson 区间(含 estimate / lower / upper)。在样本量有限时,"观察到 0 个误报"的真实区间上限远高于 0; - 基础率(base-rate)精度修正:脚本按
1 攻击 : 100 良性与1 : 1000两种现实攻击稀有度计算 base-rate precision。因为即使在低绝对误报率下,当攻击极其罕见时精度也会崩塌——这是"零 FP 观察"必须附带基础率警示的根本原因。
此外,任何阈值只在 validation 分桶上拟合,并在打分 test 分桶之前冻结(manifest 中记录为tau_policy: fit on validation only, freeze before final test)。这三条共同构成了"零 FP"这句话的完整语境。
7. 问题六:可选嵌入信号的生产路径
方法论文档将 PR2(嵌入检测器本身)明确定义为本方法论文档之外、被其门控的范围(Out of scope)。对于嵌入信号的生产路径,文档给出严格增量且保守的原则:
- 仅作证据(evidence only):嵌入只产生可审计的得分/边界(score/margin),用于喂给评审或路由,绝不单独硬阻断(never hard-block alone);
- 默认关闭:必须位于显式 flag / 配置项之后,默认不生效;
- 治理元数据决定动作:嵌入负责把当前规则漏掉的语义相似案例浮出水面,但最终动作由策略/IFC 决定;
- 无托管推理要求:本地、可审计运行即可。
这一框架是刻意设计的:嵌入不取代规则。可评审的结论是——AGT 规则基线高精度/低召回,而一个保守的嵌入操作点能够在"本语料上零误报"的前提下捕获规则漏掉的部分攻击,这足以支撑一个评审/路由信号,而非默认阻断。方法论文档还明确列出了反例(anti-exemplar)措辞:任何"嵌入取代规则"或"生产就绪 / 零误报保证"的表述都是禁止的。
8. 验证计划:每个数字都必须能在生成器里被 grep 到
票据与文档共同给出四步验证方案(Validation plan),保证方法论的可审计性:
| 检查项 | 命令 | 预期结果 |
|---|---|---|
| 生成器常量与文档一致 | grep -E "SEED\|NEAR_DUPLICATE\|SPLITS\|ALLOWED_BYPASS" benchmarks/prompt-injection/harness/generate-corpus.py | 与文档引用的值一致(SEED=1337、NEAR_DUPLICATE_THRESHOLD=0.92、NEAR_DUPLICATE_NGRAM=7、5 桶分桶、profile 上限、家族与绕过类别集合) |
| 语料可复现且零泄漏 | python3 benchmarks/prompt-injection/harness/generate-corpus.py --profile smoke,再运行 check-corpus.py 复核 | 确定性输出,跨分桶泄漏 = 0 |
| 无运行时变更 | git diff --stat origin/main..HEAD | 仅 2 个文档文件变更 |
| 链接有效 | 人工核对 evaluation 文档 → methodology 文档的交叉链接 | 链接可解析 |
方法论的完整复现命令序列(prompt-injection-methodology.md):
# 确定性重新生成一个 profile 并复核泄漏 = 0 python3 benchmarks/prompt-injection/harness/generate-corpus.py --profile smoke python3 benchmarks/prompt-injection/harness/check-corpus.py \ benchmarks/prompt-injection/corpus/injection-smoke.jsonl # 重跑 AGT 规则基线 + 汇总(Wilson 区间 + 基础率精度) benchmarks/prompt-injection/run-smoke.shcheck-corpus.py的校验逻辑远超简单的格式检查:它验证每行 17 个必需字段、id 唯一性、split 与expected_action枚举合法性、良性行动作必须为allow、攻击行benign_subclass必须为not_applicable,并将 manifest 中的row_count、output_sha256(支持 LF 归一化模式)、leakage_check、normalized_text_check、duplicate_check、split_label_coverage_check与逐行重算结果逐一比对。任何不一致都会以ERROR:前缀输出并以退出码 1 结束,全部通过则打印prompt-injection-corpus-check: PASS。
9. 从源码结构看:为什么这套方法论值得直接复用
通读 generate-corpus.py 与 check-corpus.py 的源码结构可以发现,这套夹具的设计哲学高度自洽:
- 生成与校验分离:生成器负责产出,校验器负责证明,
run-smoke.sh把两者串成端到端门禁,且所有中间产物(per-row 证据)落到系统临时目录,仓库内只提交摘要型元数据(manifest、check 汇总),从机制上避免原始提示文本被误提交; - 一切皆可溯源:
generator_id、family_id、group_id、Trace摘要、生成器自身 SHA-256(generator_sha256)被写入 manifest,任何一行语料都可以回推到模板、变异算子与索引; - 评估口径被标准化:Wilson 区间、FP/1k、基础率精度已在
summarize-baseline.py中统一实现,且 manifest 同时声明implemented_metrics与planned_metrics(ROC-AUC、PR-AUC、bootstrap CI、unsafe_action_success、critical_allow、leak_allow等),为后续评估臂(rules_only已实现;gate_alone、embeddings_only、gate_plus_embeddings规划中)预留了清晰的扩展点。
这套"确定性生成 + 家族级分桶 + 三重泄漏门禁 + 元数据-only 基线 + 带区间/基础率的口径报告"的组合,构成了 agent-governance-toolkit 中任何检测器实验的低风险起点:它让"规则在哪里漏、良性文本在哪里被误报"变得可审计、可回归、可评审,也为未来默认关闭的嵌入信号提供了一个不越界、不宣称过度保证的落地范式。
【免费下载链接】agent-governance-toolkitAI Agent Governance Toolkit — Policy enforcement, zero-trust identity, execution sandboxing, and reliability engineering for autonomous AI agents. Covers 10/10 OWASP Agentic Top 10.项目地址: https://gitcode.com/GitHub_Trending/ag/agent-governance-toolkit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考