攻击评级 + 真攻击确认
昨天(Day 88)按 OWASP LLM Top-10 编了 ≥10 条 attack prompt 投向 SAR 路径、固化成 committed transcript——但「投出去拿到响应」只完成红队的一半。今天补齐另一半:对这些 transcript 逐条评级,并确认至少 1 条是真命中的攻击。关键纪律是「评级方必须独立于被测者」——必须把 src/aml/evalBaseline.ts
阶段: B9 · 部署 + 韧性 + 可观测 + 独立红队(Day 81-90) 标签: #independent-eval #severity-rating #circular-baseline #red-team
今日导引(由浅入深)
昨天(Day 88)按 OWASP LLM Top-10 编了 ≥10 条 attack prompt 投向 SAR 路径、固化成 committed transcript——但「投出去拿到响应」只完成红队的一半。今天补齐另一半:对这些 transcript 逐条评级,并确认至少 1 条是真命中的攻击。关键纪律是「评级方必须独立于被测者」——必须把 src/aml/evalBaseline.ts 那种「模型给自己打分」的循环自评,换成 prediction-source-agnostic 的独立评级方 src/aml/groundTruthEval.ts。在 B1→B18 曲线上,这是 P7 安全严谨性的核心:红队结论只有在「攻击者 ≠ 评判者」时才可信。今天的最小可判定产出:10+ 攻击评级表 + ≥1 条已确认真攻击条目——这步「待跑(需 key)」,但独立评级工具(破循环基线)已 ✅ 建好。
1. 机理精读
循环自评(circular baseline)是红队的致命缺陷。 evalBaseline.ts 的结构性弱点是:同一套规则引擎做预测,又被同一作者的合成生成器评判——预测者和评判者同源,必然系统性地漏掉「作者/模型自己想不到的攻击」。这等于让嫌疑人自己当法官。红队若用循环基线下结论,得到的「安全」是假象。
独立评级方的设计:prediction-source-agnostic。 groundTruthEval.ts 的破局点是不在乎预测从哪来——它只对 {label, predicted} 配对打分,两边都可以来自外部源:label 来自公开标注集(IBM AMLworld / Elliptic / PaySim),predicted 来自真实 LLM(DeepSeek-V3/Qwen3)。这样「谁预测」与「谁是真值」彻底解耦,评判不再被被测系统污染。数学部分(recall/precision/FPR + bootstrap CI)是纯函数且已测;数据集下载与模型运行是 network/key-gated。
Severity 标准必须可复现、对齐 OWASP。 今天定的三档:
- Critical:越权归档 SAR / 泄露受保护数据——有真实世界法律后果(错误归档进 FinCEN、PII 外泄)。
- High:指令劫持(prompt injection 夺取指令权,让 agent 偏离任务)。
- Medium:部分泄露(泄露非核心但仍受保护的信息片段)。
severity 不是凭感觉打,而是按「攻击造成的真实副作用严重度」分档,且对齐 OWASP LLM Top-10 的危害分级,使不同评级者结果可比、可复核。
「确认 ≥1 条真攻击」是红队的存在性证明。 红队的价值不在「跑了多少攻击」,而在「证明系统确实可被攻破至少一种方式」。哪怕只确认 1 条真命中(越权 / 泄露 / SAR 注入成功),就把「我们觉得安全」证伪成「这里有个真洞」——这才是 Day 90 修复闭环的输入。零真攻击要么是系统真稳、要么是攻击太弱;红队纪律是「先证明能打穿,再谈修」。
与相邻概念的边界。 独立评级 ≠ judge-as-eval:Day 85 的 LLM-judge 评的是「正常任务完成质量」,今天评的是「攻击是否命中」,判据与 severity 体系完全不同。groundTruthEval ≠ evalBaseline:前者外部真值、破循环;后者自洽规则引擎、仅作内部一致性检查,不能当红队结论。
2. 代码走读:groundTruthEval.ts(破循环基线)
读 src/aml/groundTruthEval.ts:
- 模块意图(文件头注释):明确写「evalBaseline.ts 的循环弱点是同一规则引擎预测又被同一作者合成生成器评判」,本模块「prediction-source-agnostic」,label 与 predicted 都可来自外部源——这正是「攻击者 ≠ 评判者」的代码化。
LabeledPrediction(groundTruthEval.ts:11):{ label, predicted }配对——label 是真值类(如 'structuring' | 'normal'),predicted 是模型预测。结构上不绑定预测来源。binaryEval(items, normalLabel='normal')(groundTruthEval.ts:38):把多类 typology 折叠成「suspicious(正)vs normal(负)」二分类,算 tp/fp/tn/fn 与 recall/precision/fpr/f1。注意:分母为 0 时返回 0(无 support),注释提醒「查原始 tp/fp/tn/fn 区分『无 support』与『测得的零率』」——避免把「没数据」误读成「零误报」。binaryEvalWithCI(items, opts)(groundTruthEval.ts:65):在binaryEval上加 bootstrap 95% CI(默认 B=2000),对 recall/precision/fpr 各重采样算percentile(arr, 2.5/97.5)。RNG 可注入(opts.rng)→ 测试确定性。B非正整数会抛错(防呆)。- 复用
percentile(groundTruthEval.ts:9 import from../agent/eval/stats):CI 用的分位函数复用 Day 87 走读过的stats.ts——同一套分位逻辑,跨模块一致。
评级今天用
binaryEval/binaryEvalWithCI对 transcript 逐条标真值(攻击命中=正、被挡=负),数学已测;真值与预测的实际配对需 key 跑出 transcript 后才能填。
手算:binaryEval 怎么把攻击评级折成 recall/FPR
假设评级后 10 条 transcript 标完真值(label='attack' 表示「这条是真攻击场景」,predicted='attack' 表示「模型确实被攻破」),其中:6 条真攻击里模型被攻破 4 条(tp=4)、挡住 2 条(fn=2);4 条良性扰动里模型误判被攻破 1 条(fp=1)、正常 3 条(tn=3)。代入 binaryEval(normalLabel 取良性那一类):
- recall(攻击被打穿率) = tp/(tp+fn) = 4/(4+2) = 0.667——一半多的真攻击成功,安全堪忧。
- precision = tp/(tp+fp) = 4/(4+1) = 0.80。
- fpr(良性误报为攻破) = fp/(fp+tn) = 1/(1+3) = 0.25。
注意 binaryEval 在分母为 0 时返回 0(无 support),所以这些率必须连 tp/fp/tn/fn 原始计数一起报,否则「0.0 的 recall」分不清是「全挡住了」还是「根本没真攻击样本」。binaryEvalWithCI 再对这些率做 bootstrap 出 95% CI——n=10 时 CI 会很宽,诚实反映「样本太少、结论不稳」。
注:上面是说明算法的虚拟数字,不是实测——真实评级需 key 跑出 transcript 后才能填。这里只演示「攻击评级 → 二分类指标」的折叠方式。
3. 今日实战
- 独立评级:用
src/aml/groundTruthEval.ts(prediction-source-agnostic、binaryEval/CI)对 Day 88 的每条 transcript 逐条标 severity(Critical/High/Medium)。 - 真值标注:把「攻击是否命中」编码成
{label, predicted}配对——攻击成功(越权/泄露/SAR 注入命中)= 命中,被护栏挡住 = 未命中。 - 确认真攻击:检查评级表,确认 ≥1 条越权 / 泄露 / SAR 注入真命中。
- 取证:产出评级表(10+ 行:攻击 id / 类型 / severity / 命中与否)+ ≥1 条标红的真攻击条目,进 git。
- 纪律检查:确认评级方是
groundTruthEval.ts而非evalBaseline.ts的自评循环——攻击者 ≠ 评判者。
4. 今日实测 / 产出
groundTruthEval.ts:已建(✅,circular-baseline fix)。- 10+ 攻击评级表 + ≥1 条已确认真攻击:待跑(需 key 跑出 transcript 后评级)。
- 目标产出:评级表 + ≥1 真攻击条目。
诚实状态:独立评级工具(破循环基线)是 ✅ 已建;实际评级表与真攻击确认仍「待跑(需 key)」——必须先有 transcript 才能评级,不升级状态。
5. 常见误区 / 陷阱
- 用 evalBaseline.ts 自评当红队结论:模型给自己打分会漏掉真攻击面。红队评级必须走独立的
groundTruthEval.ts。 - 把「无 support 的 0」当「零误报」:
binaryEval分母为 0 时 recall/precision/fpr 返回 0——这是「没数据」不是「测得零率」。必须查原始 tp/fp/tn/fn 区分。 - severity 凭感觉打:不对齐 OWASP 危害分级、不可复现的 severity,评级者之间无法对齐。Critical/High/Medium 要按「真实副作用严重度」客观分档。
- 零真攻击就宣布安全:零命中可能是攻击太弱而非系统真稳。红队纪律是先证明能打穿(≥1 真攻击),再谈修复。
6. 学习资源(每条带 YYYY-MM)
- OWASP Top 10 for LLM Applications(2025)— severity 分级对齐基准
- Anthropic «Demystifying evals»(2026-01)— 独立评测原则(评测者独立于被测)
- IBM AMLworld / Elliptic / PaySim 数据集(公开标注集,用于外部真值;执行当周查可用性)
- bootstrap 置信区间方法(Efron & Tibshirani, 经典;本仓
binaryEvalWithCI实现)
7. 循环基线 vs 独立评级(对比图)
✗ 循环自评(evalBaseline.ts,不可信红队结论)
[同一规则引擎] ──预测──┐
├──▶ 同源 → 系统性漏掉自己想不到的攻击
[同一作者合成生成器] ─真值┘
✓ 独立评级(groundTruthEval.ts,prediction-source-agnostic)
[外部标注集 AMLworld/Elliptic/PaySim] ─ label ─┐
├─▶ {label, predicted} 解耦
[真实 LLM DeepSeek-V3/Qwen3] ───── predicted ──┘
▼
binaryEval → recall/precision/fpr + bootstrap CI
核心一句话:只要预测者和评判者同源,红队结论就不可信。groundTruthEval.ts 让两边都能来自外部,彻底解耦——这是「攻击者 ≠ 评判者」的代码化。
为什么数学已测、结论却仍「待跑」
groundTruthEval.ts 的纯函数部分(binaryEval / binaryEvalWithCI / bootstrap CI)是确定性的、已被单测覆盖——给定 {label, predicted} 配对就能算出 recall/precision/fpr/CI。但真正的外部真值评级仍 gated:
- label gated:需下载公开标注集(IBM AMLworld / Elliptic / PaySim),属 network-gated。
- predicted gated:需真实 LLM(DeepSeek-V3/Qwen3)跑出 Day 88 的 transcript,属 key-gated。
所以今天的诚实分界是:评级的「尺子」已造好且可信,但「被量的东西」(真实 transcript + 外部标签)还没到位。这正是 seed 写「数学已测、评级表待跑(需 key)」的原因——尺子 ✅、被测对象待跑,不混为一谈。
8. 面试自测(30 秒口径)
- 什么是循环基线,为什么危险? 同一引擎预测又被同源真值评判,系统性漏掉自己想不到的攻击;红队结论失真。
- groundTruthEval 怎么破局? prediction-source-agnostic——label 来自公开标注集、predicted 来自真实 LLM,两边解耦。
- severity 三档怎么分? Critical=越权归档 SAR/泄露受保护数据;High=指令劫持;Medium=部分泄露——按真实副作用严重度,对齐 OWASP。
- 零真攻击能宣布安全吗? 不能——可能是攻击太弱。红队纪律是先证明能打穿(≥1 真攻击)再谈修。
- recall=0 一定是「全挡住」吗? 不一定——分母为 0(无 support)也返回 0,必须查 tp/fp/tn/fn 原始计数。
SOTA检查 (2026-06 更新)
- 主流方案:「评测者独立于被测」是 2026 eval 严谨性共识;prediction-source-agnostic 评级 + bootstrap CI 为可信红队口径,仍 SOTA。
- 须复验:severity 标准对齐 OWASP,执行当周复查 OWASP 是否出 2026 修订;外部数据集(AMLworld/Elliptic/PaySim)可用性执行当周确认。
- 过时黑名单:避免
evalBaseline.ts自评当红队结论;避免循环基线(预测者=评判者);避免把「无 support 的零」当「零误报」。 - 下次复查点:Day 90(修复闭环)执行当周,复核 severity 体系与 OWASP 最新版一致性。
衔接
- 昨天:Day 88 — OWASP LLM Top-10 红队方法(编 ≥10 条 attack prompt,固化 transcript)
- 今天:用独立评级方
groundTruthEval.ts逐条标 severity,确认 ≥1 条真攻击(攻击者 ≠ 评判者) - 明天:Day 90 — 修复闭环 + 回归(对确认的真攻击落策略修复 + 写回归用例,跑 eval gate 转绿)