你在给一个 AI 代码生成平台做架构:每天 5000 个 LLM 补丁进流水线,人类工程师是最后一道闸。你把「明显能自动化的」都交给了 AI——补丁、单测草稿、changelog——留给人的是最难自动化的那一小撮:判断这段流畅的代码到底对不对。上线三个月指标很好看:AI 采纳率 82%、人均审查从 12 分钟降到 3 分钟。然后一个静默 bug 溜过终审进了生产:AI 把 balance -= amount 写成 balance += amount,注释、命名、测试全都自洽,reviewer 3 分钟扫过点了 approve。
这不是 reviewer 不认真,是 Lisanne Bainbridge 1983 年《Ironies of Automation》的处方在 LLM 时代变成了最难一条:你自动化了简单的 95%,把人留在监控席——可人正因不再动手而技能退化,而 LLM 的错误不像传统软件那样大声崩溃,而是「错得流畅」、不主动自曝。监控一个安静的、几乎总是对的系统,恰是人类最不擅长的任务。
约束:吞吐 5000/天、每个终审预算 < 5 分钟、真 bug 底率约 3%、漏检率压到生产事故预算内。设计目标是固定人力下最大化「有效抓取率」,而非让 AI 少犯错(它一定会犯)。
graph LR
G["AI 生成器
LLM 补丁/agent"]
V["失效可见性层
结构化断言 / 自检 / diff 高亮"]
O["独立 oracle
编译·测试·参照路径"]
T["分诊层
按 风险 × 未验证度 排序"]
H["终审席
人类最后一道闸"]
G --> V
V --> O
O --> T
T --> H
H -->|校准反馈 + 注入已知错例| G
职责:失效可见性层要求 AI 输出的不只是补丁,还有可被机器核验的结构化断言(「不改变对外契约」「余额单调递减」);独立 oracle(承 Day 52 差分正确性 oracle)用与生成路径无关的手段——编译、跑测试、跟参照实现比对——去证伪断言,把「静默错结果」变成「被标红的断言未通过」;分诊层(承 Day 51)按风险与残余不确定性排序,只把值得看的推给终审;终审席是 slow-loop 最后闸,靠注入错例保持手感。关键:可见性和 oracle 在人之前,不是在人之后。
【原理】传统软件的失效响亮:空指针抛异常、类型不匹配编译不过、断言失败进程崩溃——错误自带信号,"fail fast" 是几十年攒下的哲学。LLM 相反:语法永远合法、命名永远合理、解释永远自洽,它把「不知道」和「知道」渲染成同一种流畅的自信。人脑对流畅性有根深蒂固的信任偏差(fluency = truth heuristic),于是最危险的不是 AI 犯错,而是它自信且流畅地犯错。叠加 Bainbridge 悖论:终审人因长期只点 approve 而技能退化,恰好在最需要他的那 3% 上最弱。
【原理】核心动作:把 AI 输出从「自然语言 + 代码」升级为「代码 + 一组可独立核验的断言」。断言必须机器可判定(能编译、能跑、能 diff),而非「我认为对」的自然语言自评。再用一条与生成路径独立的 oracle 去证伪它——关键在独立:让同一个 LLM 自评,失效是相关的(correlated failure),生成错了自评往往同样错,等于没查(承 Day 51)。可见性 = 让错误在到达人眼前就已被标红。
sequenceDiagram
participant AI as LLM 生成器
participant SC as 自检(同模型)
participant OR as 独立 oracle
participant H as 终审席
AI->>SC: "我检查过了,没问题"
Note over SC: 相关失效:自评与生成同源同错
AI->>OR: 补丁 + 结构化断言
OR->>OR: 编译 / 跑测试 / 参照路径比对
OR-->>H: 断言#3 未通过 ⚠️ 红色高亮
Note over H: 只看被标红的 1 处
核验成本骤降
# pseudo-code:让 AI 输出可核验断言,独立 oracle 证伪
patch, claims = llm_generate(task)
# claims = [
# Assertion(kind="tests_pass", spec="pytest tests/billing"),
# Assertion(kind="invariant", spec="balance monotonic non-increasing"),
# Assertion(kind="no_api_change",spec="public signatures unchanged"),
# ]
flags = []
for c in claims:
verdict = independent_oracle.check(c, patch) # 编译/测试/AST diff/参照跑
if verdict.status != PASS:
flags.append(highlight(c, verdict.evidence)) # 定位到具体行 + 反例
# 只有带 flag 的、或高风险且断言覆盖不足的,才进人类队列
route_to_human(patch, flags, coverage=assertion_coverage(claims, patch))
【原理】直觉是「让 AI 多解释、人就能更好判断」——错。Vasconcelos 等 (CSCW 2023) 用成本-收益框架证明:人是否真去核验,取决于核验成本 vs 采纳收益的权衡;解释只有真正降低了「核验这个输出对不对」的成本时才减少过度依赖,若只是又一段流畅叙述,反而提高流畅性信任、加重过度依赖。Zhang 等 (FAT* 2020) 补上另一半:置信度/解释能否改善判断,取决于人能否据此校准信任、区分该信与不该信。所以目标不是「多给信息」,而是给终审席一条比自己重做便宜得多、且直接指向对错的核验路径。
# 核验成本的直观模型:终审席的理性行为
# 人会核验 ⟺ C_verify < benefit_of_catching_error
# ⟺ C_verify < base_rate × cost_of_miss
# 降低漏检有两条杠杆:
# 1) 抬右边:把高后果项排到前面(分诊按 风险 排序)
# 2) 压左边:C_verify ↓ ← 失效可见性层的全部意义
# 反直觉:解释若只加长阅读,C_verify ↑,理性的人反而更少核验
【原理】把终审席当可调系统,其有效抓取率由四个参数决定,缺一个都塌:
| 参数 | 含义 | 调节手段 | 不管它的后果 |
|---|---|---|---|
| 底率 (base rate) | 真错误频率 | 分诊排序、高风险前置 | 过低 → 长期只见对的,警惕性崩塌(Day 51) |
| 核验成本 | 核对一个输出多贵 | oracle 标红、diff 定位、反例 | 过高 → 理性的人直接采纳(Vasconcelos) |
| 练习剂量 | 保持判断力的手感 | 注入错例、轮岗动手、校准题 | 为零 → 技能退化,关键时刻抓不住(Bainbridge) |
| 失效可见性 | 错误自曝的程度 | 结构化断言、独立 oracle、高亮 | 为零 → 错得流畅全部溜过 |
练习剂量最反直觉、最常被砍:一个几乎总是对的系统会让人失去练习机会,于是要主动注入已知错例(seeded faults / calibration items),像混沌工程给人类注入故障——既维持警惕性,又量出终审席的真实抓取率。呼应 Day 44 与 Day 51。
演进方向:(1) 断言覆盖率驱动——把「哪些属性有独立 oracle 覆盖、哪些只能靠人」做成指标,优先给高后果模块补 oracle;(2) 分级终审——低风险高覆盖走轻量抽检,高后果低覆盖走双人复核(bulkhead,Day 23);(3) 校准闭环——用注入错例的抓取率反哺分诊阈值,抓取率下滑就自动收紧;(4) 可见性下沉到生成端——AI 生成时即产出可核验断言与自证据。瓶颈通常不在 AI 准确率,而在oracle 覆盖面与终审席注意力预算——这两者才是要花钱扩的地方。
面试追问:① 怎么量一个「人类终审席」当前的漏检率?(注入错例测抓取率)② 底率从 3% 降到 0.3%,设计要改哪?(可见性与练习剂量加码,纯靠人更不可靠)③ 为什么让 AI 多写解释有时更危险?④ 独立 oracle 覆盖不到语义意图时剩下怎么办?⑤ 这套设计和 Day 41「把人移出快回路」矛盾吗?(不——快回路止血靠自动化,慢回路正确性终审保住人并给他可见性)
这是 Day 51 基率谬误在人机协同的直接后果。底率越低,连续「对的」样本越长,警惕性衰减(vigilance decrement)越严重——人监控极稀有信号本就差,几百个 approve 之后碰到第一个真错,心智已默认「都是对的」;同时真错变少 = 手感更差。所以底率下降同时恶化了可见性依赖、警惕性和练习剂量三条。正确做法:把省下的确定性预算投到失效可见性(更多 oracle 标红)和练习剂量(注入错例,把「人感知到的底率」抬回可工作区间,像 TSA 的 TIP)。反直觉结论:你要人为地让终审席「多看到错」,哪怕那些错是你埋的。
Vasconcelos 的成本-收益框架:人是否真去核验,取决于「核验成本 vs 采纳收益」。解释若降低了核验成本(如「改了 X 行、可能影响 Y 契约、这里是反例测试」),过度依赖下降。但若只是又一段流畅自洽的叙述,它做两件坏事:(1) 没降核验成本(读它还花时间);(2) 抬高流畅性信任(fluency heuristic)。净效果是理性的人核验更少、漏检上升。判据很干脆:一条辅助信息若不能让「核验对错」比「自己重做」更便宜,它就是在制造过度依赖。可执行反例 > diff 高亮 > 结构化断言 > 自然语言 rationale。
独立性是 oracle 有效的前提。若生成器和检查器是同一模型(或同族、同数据、同 prompt),错误高度相关:模型生成时把 += 当成 -=,自检时同样的语义盲点会让它确认「对的」。数量上:设单次错误率 p,两次独立则漏检率 ≈ p²(3% → 0.09%);但相关系数接近 1 时漏检率 ≈ p(几乎没改善,还烧一倍算力制造「已核验」假象)。这正是 Day 51「Argus 消融证明器 0/20 vs LLM 自任裁判 20/20」的机理。所以 oracle 必须走独立路径:编译器、真实测试、参照实现,或至少不同模型/信息源的交叉验证。独立性决定 oracle 是真查还是自我安慰。
不矛盾,它们管两个回路。快回路(止血):故障时毫秒级的自动检测、熔断、回滚——人太慢,必须移出交给自动化(Day 41 Knight Capital 教训)。慢回路(正确性终审):判断一个 AI 补丁的语义意图对不对,不需要毫秒级,需要判断力和可见性——这里人是最后一道价值闸,要保住并给他弹药。混淆两者会犯双向错误:把慢回路判断塞进快回路(人来不及),或把快回路止血交给人(Bainbridge:人连建立心智模型的时间都没有)。正确架构是快回路全自动 + 慢回路人在环且高可见性。判据:瓶颈是速度还是正确性判断?速度归自动化,判断留人并降其核验成本。
用有效抓取率的分解判断:≈ (进入人类队列的真错比例) × (人对队列内真错的抓取率)。若队列里真错太少(底率被稀释)→ 投分诊,按「风险 × 未验证度」把高信号前置。若真错进了队列人却没抓住(可见性差、核验成本高)→ 投 oracle 和 diff 高亮。注入错例的 A/B 就能量出是哪种:埋一批已知错例,看它们(a)有没有进人类队列(分诊问题),(b)进了有没有被抓(可见性/成本问题),先补漏在前面的那一环。早期常两个都缺,但 oracle 边际收益更陡——它同时降核验成本、又反哺分诊,一份投入两处受益。