> ## Content Index
> Fetch the complete content index at: https://www.hubwiz.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# AI 测试与 bug 同谋：变异测试与 LLM 评委校准
- URL: https://www.hubwiz.com/blog/ai-tests-agree-with-bug-mutation-judge-calibration/
- Published: 2026-10-16T00:23:17.000Z
- Updated: 2026-10-16T00:24:30.000Z
- Description: 测试与实现出自同一个 prompt，会一起错：88.00 的巧合、覆盖率证明不了 oracle、变异测试与 κ 0.80 评委校准。一份 12 条清单。
- Author: admin
- Tags: AI 测试, 变异测试, LLM 评测, 工程实践

**一句话结论**：一个 AI 实现的折扣公式把折扣算错了位置（税后减而不是税前减），AI 生成的测试却**通过了**——因为测试和实现出自同一个 prompt、同一份仓库上下文、同一种理解，连错都错得一样。本文编译 2026 年 10 月的四组材料：会同意 bug 的 AI 测试与它的替代方案（@johnnylemonny，10-15）、用 StrykerJS 做变异测试的完整教程（@remojansen，10-14）、LLM 评委的 κ 0.80 校准方法（@faishalwahiduddin，10-15），以及把整栈自托管评测按**"每个解决的任务"**而不是 token 计费的实测（@dailycontext，10-14）。四组材料指向同一句话：**检查通过只是证据，不是权威；证据本身也要被验证。**

**披露**：四篇源文均来自 dev.to（2026-10-13 \~ 10-15）。@remojansen 为 StrykerJS 生态作者（文中推广该工具，教程内容可独立复现）；@faishalwahiduddin 的方法来自其 AutoKon 生产环境，文中明确说明未披露数据集规模、提示词与逐轮分数，按"方法"引用；@dailycontext 文为其团队自托管评测，未点名具体模型与硬件型号；@johnnylemonny 文中引用的 Meta 数据（22,126 个生成测试）来自其列出的公开来源。

---

## 一、同一个 bug 的两份证词：测试为什么会同意实现

先把结论摆出来：**AI 写测试不是问题，"用相关输出当独立证据"才是问题。**

### 88.00 的巧合

需求是这样的：

> 对订单小计先打 20% 折扣，再对折后金额加税。

正确算法：

```plaintext
subtotal = 100.00
discount = 20.00
taxable  = 80.00
tax      = 8.00
total    = 88.00

```

Agent 把顺序理解反了——**先加税、再减折扣**：

```javascript
export function calculateTotal(subtotal, taxRate, discountRate) {
  const tax = subtotal * taxRate;
  const discount = subtotal * discountRate;
  return subtotal + tax - discount;   // 折扣在税后减，错了
}

```

在 `(100, 0.1, 0.2)` 这组输入下，两个公式**碰巧都返回 88.00**。于是生成的测试自然通过：

```javascript
import { describe, expect, it } from "vitest";
import { calculateTotal } from "./billing.js";

describe("calculateTotal", () => {
  it("applies a discount and tax", () => {
    expect(calculateTotal(100, 0.1, 0.2)).toBe(88);
  });
});

```

这个测试看起来相当合理：有具体的期望值、有业务含义的用例名。**但它无法区分两种实现**。一旦需求里出现固定折扣、免税品类、按辖区分段取整、不同税率的商品，共享的错误假设就会变成生产环境的账单 bug。

### 覆盖率不是 oracle

代码覆盖率只回答这几个问题：这一行执行了吗？这个分支走过了吗？这个函数被调用了吗？

它**不回答**：

- 期望值本身对吗？
- 测试是否编码了产品需求？
- 换一个"合理的错误实现"，这个测试会失败吗？
- 系统是否守住了某条业务不变量？

一份生成的测试套件可以做到 **100% 行覆盖**，同时只是把实现的当前行为**原样断言回去**。最典型的写法：

```javascript
const result = calculateTotal(order);
expect(result.tax).toBe(result.taxableAmount * order.taxRate);
expect(result.total).toBe(result.subtotal + result.tax - result.discount);

```

测试重新推导了实现里的同一个公式——公式错了，两边一起错。**测试需要一个 oracle：一个独立于实现、让人相信期望值正确的理由。**

### 相关失败：同源上下文会复制错误

当一个 Agent 在同一个会话里写实现和测试，两份产物会共享：

- 同一份有歧义的需求；
- 同一份不完整的仓库上下文；
- 同一个错误的领域假设；
- 同一个被忽略的边界；
- 同一种按命名猜测的解释；
- 同一个过时的示例。

**在同一个对话里重新生成测试，不会带来独立性**——模型还看得见自己之前的推理和实现。换个模型也不自动解决：如果两个模型收到同样含糊的提示、又都从同一份实现推导期望值，它们可能收敛到同一个"诱人的错误"上。

> 目标不是换一个生成器，而是换一个**事实来源**。

### 五种危险测试模式

1. **拿实现断言实现**：`expect(formatPrice(input)).toBe(formatPrice(input))` 是极端例子，更常见的是间接版本——测试和生产路径调用同一个 helper、parser、mapper 或公式。
2. **快照未知行为**：`expect(calculateInvoice(order)).toMatchSnapshot()` 第一次快照记录的是"实现当时吐出了什么"。批准快照只证明有人接受了输出，不证明输出符合需求；快照擅长**检测变化**，不擅长**建立初始正确性**。
3. **照抄私有实现细节**：`expect(cache.internalEntries.size).toBe(1)` 确认的是结构而非可观察行为——用户可能仍在读旧数据，而一次安全重构却会让它失败。
4. **只测 prompt 里的那个例子**：需求给了一个示例，Agent 往往就写一条 happy path——而那个例子可能恰恰区分不出两种解释。
5. **把失败 mock 掉**：`paymentGateway.charge = vi.fn().mockResolvedValue({ status: "paid" })` 证明的是一个永远瞬间成功的依赖。它对超时、重复响应、结果不确定、远端已扣款后重试——**一个字都没说**。

一条可以立刻用的审查问题：

> **这个期望值是从哪来的？**

如果答案是"从实现来的"、"从 Agent 之前的输出来的"、"从我们没看过的快照来的"，那么对关键行为来说，这个测试**不够独立**。

---

## 二、给测试一个独立的事实来源

### 从示例开始，不如从不变量开始

示例验证的是若干点；不变量描述的是**跨大量输入都必须成立的性质**。以折扣计算为例：

- 折扣变大，税前金额不能变大；
- 0% 折扣不改变任何东西；
- 100% 折扣不产生应税金额；
- 总额不能为负；
- 调换商品顺序，总额不变；
- 取整发生在业务规则定义的那一个边界上。

属性测试（property-based test）可以把这些规则压到生成输入上。例如用 `fast-check` \+ `vitest` 验证"折扣增加不会让总额增加"：

```javascript
import fc from "fast-check";
import { expect, it } from "vitest";
import { calculateTotal } from "./billing.js";

it("never increases the total when the discount increases", () => {
  fc.assert(
    fc.property(
      fc.double({ min: 0, max: 100_000, noNaN: true }),
      fc.double({ min: 0, max: 0.3, noNaN: true }),
      fc.double({ min: 0, max: 1, noNaN: true }),
      fc.double({ min: 0, max: 1, noNaN: true }),
      (subtotal, taxRate, firstDiscount, secondDiscount) => {
        const lower = Math.min(firstDiscount, secondDiscount);
        const higher = Math.max(firstDiscount, secondDiscount);
        expect(calculateTotal(subtotal, taxRate, higher))
          .toBeLessThanOrEqual(calculateTotal(subtotal, taxRate, lower));
      }
    )
  );
});

```

这仍然不能证明全部领域规则，但它让**一个方便的示例**很难藏住一条被破坏的关系。

### 从一个独立来源推导验收测试

最强的验收测试来自**先于实现存在**的东西：

- 产品验收标准；
- API 契约；
- 监管规则；
- 协议规范；
- 此前已验证的行为；
- 领域专家批准的生产数据样例；
- 另一个实现的兼容性 fixtures。

在让 Agent 写实现**之前**，先写一张决策表：

| 用例      | 小计     | 折扣  | 税率 | 折扣额   | 应税     | 税    | 总计         |
| ------- | ------ | --- | -- | ----- | ------ | ---- | ---------- |
| 税前百分比折扣 | 125.00 | 20% | 8% | 25.00 | 100.00 | 8.00 | **108.00** |

再把它变成测试：

```javascript
it("taxes the amount after the percentage discount", () => {
  expect(calculateTotal(125, 0.08, 0.2)).toBe(108);
});

```

注意这里**故意用了不整的数**：125、8%、20%。目的就是让"碰巧一致的公式"分道扬镳——错误实现会算出 114 或别的数字，而不是 108。

### 让测试去打架：变异测试与差分校验

- **变异测试**：故意小改生产代码（`>=` 改成 `>`、`+` 改成 `-`、`&&` 改成 `||`、`return true` 改成 `return false`），看测试会不会失败。对授权、账单、重试、幂等、限额这类"一个字符就能出事"的逻辑尤其值得做。
- **Meta 的 JiT catching tests**（2026）：不再只生成"在提交代码上能通过"的测试，而是设计成**在变更合入前抓回归**的测试。在一项 22,126 个生成测试的评估里，change-aware 方法提升了候选抓取生成的效果，并报告抓到了确证的严重故障。核心思想很实用：**生成的测试应该主动尝试证伪这次变更，而不是给它写文档。**
- **差分校验（differential testing）**：同一批输入同时跑两个独立实现，比较输出。适合重写、迁移、优化。参考实现不必快、不必优雅，但必须在被比较的行为上**可信**。注意：如果旧行为里有已知 bug，要显式编码这些例外——否则差分校验会像快照一样**把缺陷固化下来**。

### 让工作流制造"摩擦"

更安全的 AI 辅助流程，会在实现与验证之间制造摩擦：

1. **先抽契约**：输入输出、不变量、边界条件、错误行为、安全约束、能区分不同解释的示例。
2. **再生成实现**：可以把契约给 Agent，但不让它的实现成为期望值的来源。
3. **用全新上下文生成对抗性测试**：给另一个 Agent/会话提供契约、代码 diff、公开接口、已知失败类别，让它**找反例**而不是提高覆盖率。提示词可以是：

```plaintext
扮演一个对抗性测试工程师。给定需求和代码 diff：
1. 列出可能被误解的解读；
2. 构造能区分它们的输入；
3. 找出边界条件与不变量；
4. 为每一种合理的错误实现写出会失败的测试；
5. 不要从被测实现推导期望值。

```

1. **做有针对性的变异测试**：只变异关键决策，别在每次提交时变异整个仓库。
2. **审查 oracle**：评审少花时间问"测试可读吗"，多花时间问——这个期望值为什么对？哪种错误实现会被它拒绝？它依赖生产 helper 吗？恰好落在边界上会怎样？还有哪条需求没被覆盖？
3. **保留合并控制**：绿色 PR 仍然需要分支保护、必需检查与人工审查。GitHub 明确要求其编码 Agent 生成的草稿 PR 先经人工审查，并在生成的变更周围叠加安全扫描与分支限制。这不是仪式，而是承认：**生成的代码 + 生成的测试是证据，不是权威。**

### 一个限流器的例子

Agent 加了限流函数：

```javascript
export function isAllowed(requestCount, limit) {
  return requestCount <= limit;
}

```

它同时生成了两条测试：`isAllowed(3, 5) === true`、`isAllowed(6, 5) === false`，都通过，覆盖率可能完整。但真正决定语义的问题是：**`limit` 是"允许的第 5 个请求"，还是"已经消耗掉的请求数"？第 5 个请求到底放不放行？** 两条测试恰好躲开了那个唯一重要的边界。要补的区分用例是 `isAllowed(5, 5)`——返回 `true` 还是 `false` 取决于契约，**而契约不能由实现自己决定**。

---

## 三、让测试主动反抗：变异测试实操

@remojansen 用同一个"满 £100 免运费"的例子把变异测试从概念讲到了 CI。

```typescript
export function calculateShipping(orderTotal: number): number {
  return orderTotal >= 100 ? 0 : 10;
}

```

配套测试只覆盖了 £50 与 £150。现在有人把 `>=` 误改成 `>`：**一个刚好 £100 的订单会开始收运费**。重跑测试——**全绿**。测试执行了代码，却没能力区分正确与错误实现。

### 怎么跑起来

以 TypeScript + Vitest + **StrykerJS** 为例：

```bash
mkdir mutation-testing-demo && cd mutation-testing-demo
npm init -y
npm install --save-dev typescript vitest
npx vitest run          # 先确认全绿
npx stryker init        # 按提示选择 TypeScript / Vitest
npx stryker run         # 变异并逐个跑测试

```

配置里要明确变异范围——**只变异生产代码，不要变异测试文件**：

```javascript
mutate: ['src/**/*.ts', '!src/**/*.test.ts'],

```

### 报告怎么看

| 结果                    | 含义                        |
| --------------------- | ------------------------- |
| **Killed（杀死）**        | 至少一条测试因变异失败——测试检测到了变化     |
| **Survived（存活）**      | 测试仍全绿——**测试套件没有保护这条行为**   |
| **No coverage**       | 变异代码根本没被执行                |
| **Timeout**           | 规定时间内没拿到正常结果，不等于测试发现了变异   |
| **Equivalent mutant** | 变异不改变可观察行为，不存在能区分它的有意义的测试 |

**变异分数 = 被杀死的变异 / 有效变异 × 100%。** 它是信号，不是普适质量指标：两个项目可以同分而风险完全不同——支付授权里一个存活的变异，比格式化工具里一个存活的变异重要得多。修测试也不是为了提高分数，而是因为**需求明确规定了边界行为**。补上 `expect(calculateShipping(100)).toBe(0)` 之后，`>=` → `>` 这个变异被杀死了。

### 接进 CI 的三个阶段

1. **只报告、不拦合并**：先在少量重要模块上跑，看看耗时、噪音与存活变异长什么样；
2. **门禁关键代码**：对权限、定价、校验、状态迁移等区域设置更强的要求；
3. **跟踪长期回归**：用定时运行与历史报告看整体薄弱点（Stryker 的增量模式可复用历史结果）。

两个容易踩的坑：**"只变异变更文件"不等于"只跑新测试"**——相关的存量测试也要参与验证；也**不要把全仓库变异分数设成合并门禁**——一个小 PR 不该为遗留测试套件里的所有弱点负责。

### 让 Agent 自己去读存活变异——但别让它刷分

可以把变异报告和需求一起回喂给 Agent：它判断这个变异是否暴露了真实测试缺口，补一条测试，或解释这个变异为何无意义。这就形成了一个"不只是实现、连证据一起改进"的回路。

但有个关键警告：**不要让 Agent 盲目优化变异分数。** 它可能加一条编码了错误假设的断言让变异失败，甚至改生产代码去迁就现有测试。正确行为必须来自显式需求、领域规则或其他可信来源——**不是变异报告本身**。Agent 可以提修复，最终验证要在 CI 里、针对修订后的提交独立重跑。

### 瑞士奶酪模型：五层验证

没有哪一种技术能抓住所有缺陷，所以要像瑞士奶酪一样把多层不完美的防线叠起来——缺陷穿过一层时，还有下一层接住：

| 层             | 抓什么                       |
| ------------- | ------------------------- |
| 1\. 类型与静态分析   | 不兼容接口、非法类型、特定类别的编程错误      |
| 2\. 单元与集成测试   | 已规定的行为、交互、组件集成            |
| 3\. **变异测试**  | 测试本身是否有能力检测选定变更           |
| 4\. 契约与架构检查   | 边界、不变量、集成假设               |
| 5\. 独立审查与生产反馈 | 被误解的需求、更大的设计风险、自动化检查漏掉的失败 |

这些层是互补的，不是独立的——变异测试依赖测试套件，而两者可能基于同一个被误解的需求。但当代码生成开始规模化（"代码变便宜时，验证变贵"），变异测试能便宜地回答一个关键问题：**我们的测试能不能检测出合理的缺陷？** 而且它可以自动化、随变更反复执行。

---

## 四、评委也要被考：LLM-as-judge 的 κ 校准

第三组材料把同一个问题带到了 LLM 评测。@faishalwahiduddin 在一家建筑平台（AutoKon）用 AI 审核工地照片后才放款：Claude Opus Vision + Pinecone 检索生成照片描述，另一条 LLM-as-judge 管道（Arize AX）对描述的**依据性（groundedness）**与**完整性（completeness）**打分。**只有当评委与人工复核的一致度达到 κ ≥ 0.80，结果才被允许计入付款判断。** 评测放在版本控制仓库里，用 phoenix-evals + GitHub Actions 在 CI 里跑。

### 为什么评委需要校准

生成模型写描述，评委模型给描述打分——这看起来让你能给**每一个**输出打分，而不是看手选的样本。但问题一说出口就很明显：**评委也是模型，在与人对比之前，你根本不知道它有多好。**

校准时什么意思：**测量评委与认真的人工评审在多大比例上一致，调整到足够高，然后把它保持住。** 没有这一步，满屏的评委分数就是"没人核对过的数字"。

### 先定评分标准，再写评委提示词

大部分工作在这里。**如果两个人都对"好"无法达成一致，评委也不可能一致。** 对照片描述，作者把质量拆成两个彼此独立的维度：

- **依据性**：描述里的每一条声明，在照片里都看得见吗？照片没拍到东墙，却写"东墙抹灰完成"——即使碰巧是真的，也判失败。
- **完整性**：描述是否覆盖了该施工阶段真正重要的项目？"可以看到一堵墙"这种含糊但依据充分的描述，对付款决策依然没用。

几条帮助一致性的习惯：

- **先用二值标签**（pass / fail）——人对二值的分歧远小于 1\~5 分；只有二值确实丢掉了需要的信息，才升级到序数刻度；
- **一个维度一个评委提示词**——让一个提示词同时打两个分，一边的高分可能渗到另一边；
- **每条标准都写成"仅凭图片+描述就能回答"的问题**——如果评审需要外部知识，评委也需要，要么写进提示词，要么删掉这条标准；
- **收录 pass / fail 的范例，尤其是边界案例**——边界正是评分者分歧最多的地方；
- **把图给评委**——纯文本评委只能检查描述"听起来像不像真的"；视觉评委才能把文字对到像素上。

### 人工标注集怎么建

1. **按覆盖面抽样**：不同光照、角度、施工阶段、模糊照片、以及生成器已知会吃力的场景；
2. **超额采样失败案例**：如果 95% 的描述没问题，随机抽样只会给你极少失败样本，**κ 会变得不稳定**；
3. **两个人不看彼此标签、独立按同一份标准标注**；
4. **先测人与人一致度**——这就是实际天花板。如果人与人也只有 0.70，评委对其中任一人达到 0.80 更可能是巧合而非胜利，**说明标准本身要改**；
5. **把分歧裁决成唯一金标签**，并**每当分歧暴露歧义就更新标准措辞**；
6. **切分校准集与留出集**：前者用来迭代，后者只在最后确认时碰。

### 为什么用 kappa 而不是准确率

准确率会奖励评委"在容易的多数类上点头"。Cohen's kappa 扣掉了随机也会有的那部分一致：

```plaintext
κ = (p_o − p_e) / (1 − p_e)

```

`p_o` 是观察到的一致率，`p_e` 是当两个评分者按各自的标签分布随机标注时预期的一致率。**在不平衡数据上，二者的差距是决定性的。** 文章给出一个可复现的玩具例子：2,020 个样本里，人工是 18 个 pass + 2 个 fail。

| 评委   | 行为               | 准确率      | κ        |
| ---- | ---------------- | -------- | -------- |
| 懒惰评委 | 全部判 pass         | **0.90** | **0.00** |
| 较好评委 | 抓到 2 个真失败、误拒 1 个 | **0.95** | **0.77** |

懒惰评委有 90% 的准确率，κ 却是零；较好评委 95% 准确率，**仍不到 0.80 的门槛**。按 Landis & Koch 的常用刻度，0.61\~0.80 是"实质一致"，0.81\~1.00 是"几乎完美"——0.80 正好卡在分界线上。所以在这个场景里，**准确率是漂亮话，kappa 才是实话**。（这些是讲解用的玩具标签，不是 AutoKon 的真实数据。）

### 校准循环与七个坑

循环是：在校准集上跑评委 → **分维度各自计算 kappa**（合并分数会掩盖哪个维度弱）→ 逐条读分歧、看混淆矩阵和真实照片（是模糊图上过严？是长描述上过松？）→ **一次只改一个东西**（标准措辞、范例、对不确定情况的指示、或评委模型）→ 重跑重算 → 校准确认 0.80 后到留出集确认（掉得多说明你把提示词调到了眼前这批例子上）→ **冻结评委**：提示词、模型版本、标准全部进版本控制，任何一项变化都用 CI 重跑一致度检查。

七个坑：**对校准集过拟合**（留出集就是为它准备的）；**共享盲区**（评委和生成器看到完全相同的上下文时，会以同样方式失败——给评委原始图片并要求对照检查能减少它）；**冗长偏好**（评委倾向给更长的描述更高完整性分——few-shot 里要放"短而完整"与"长而不完整"）；**静默漂移**（模型版本或提示词的微小改动都会移动一致度——**把评委当代码对待**）；**低失败率**（失败样本极少时 κ 在多次运行间大幅摆动——超额采样失败、并公开每个分数背后的样本量）；**人工标签漂移**（评审自己的标准会随时间漂移——刷新标签时重测人与人一致度）；**唯 kappa 论**（kappa 只是与人的一致度，评分标准问了什么，仍要有领域专家把关）。

### 评委坐在哪里

在 AutoKon，AI 检查只是**五角色审批流**（现场工人、工地经理、项目经理、财务、业主）的一个输入，付款前还要两轮照片证据（Opname 与 BASTP）。**校准过的评委让 AI 的描述变得可测量；承担责任的仍然是人**——任何涉及钱的系统，作者都会这么设计。

---

## 五、再上一层：整栈评测的盲区

前三组材料都在讲"某个检查怎么被校准"。@dailycontext 的实测把问题放大到了**整栈自托管评测**：他们在真实软件工程任务上，把一批开放权重模型配上能正常服务它的硬件，再套不同的 Agent harness，测"任务解决数、耗时、并发服务人数"。三个反直觉的发现：

### 能力按硬件台阶定价，不是线性定价

直觉是"模型越好，运行成本成比例上升"。实测不是：**质量在整个开放权重谱系上逐渐提升，但硬件成本是跳变的**——因为关键变量是"权重能不能装进你已有机器"的内存。跨过那条线，你付的不是"多几十亿参数"，而是**下一台机器**。所以有的模型对它给的东西定价极差，有的则是便宜货，而哪个是哪个**跟排行榜位置关系不大**：他们集合里一个中等模型的服务成本是更小模型的 **4 倍**，应用性能只提升约 **2%**；一个大得多的模型只比下面一档贵一点点，却多解决了不少任务。有用的问题不是"哪个模型最好"，而是**"哪个模型刚好落在某一档硬件里，按每个解决的任务计"——不是按 token 计**。

### 并发是没人做预算的变量

在别人的 API 后面，并发是别人的问题；自托管时，它成为**约束本身**：每个用户带一段上下文，每段上下文都要装进内存，**延迟会在硬件真正跑满之前很久就变得不可接受**。一台机器能舒服地承载多少开发者，在不同配置间差异巨大，而且**方向和规格表暗示的相反**——最大最强的配置并发服务的人数最少。多数自托管的商业论证就死在这里：他们测试的较弱配置的盈亏平衡利用率，**远高于企业真实达到的利用率**；而真实部署的报告利用率很低，运营良好的集群也没有戏剧性好转。**如果你的方案需要接近持续饱和，它不成立。**

### harness 决定账单，却几乎不影响成绩

三个 harness 在相同硬件、相同推理设置下：解决率差异只有一两个任务；但**成本**差异巨大——同模型、同硬件、同任务数，**墙钟时间能差 2 倍**。租 GPU 时，墙钟时间就是成本本身。更刺的一点：实验中一个 harness 本来是明显赢家，**下一次软件版本发布就让性能崩塌**——罪魁祸首是 prefix caching 处理方式的一处小改动，缓存彻底失效，**GPU 租用成本暴涨 5 倍**。

> 选开发者想用的 harness，然后**给它装仪表**——一次点版本更新的成本移动，可能比换模型更大。

结论不是"自托管是否更便宜"（这样问没有答案），而是：**你的真实利用率是多少，以及有什么东西是你无论多贵都不能放到别人 API 上的**——不许出楼的数据、没人能限流你的技术栈、不会被中途改价的合同。这些理由经得起与电子表格的接触；**只靠便宜，通常经不起。**

---

## 六、把盲区写进流程

把四组材料合并成一张可执行的清单。

**给测试（oracle 层）**

- \[ \] 每个期望值都能追溯到规格、fixture、参考实现或人工审核过的计算——**不能来自被测实现**；
- \[ \] 测试不得调用生产 helper 来计算自己的期望值；
- \[ \] 边界值有显式测试（`>=` 的两侧各一个点）；
- \[ \] 至少有一个用例能区分需求的两种合理解释；
- \[ \] 重要行为尽量写成不变量（折扣不减总额、调序不变总额）；
- \[ \] 快照在批准前被人工看过含义；
- \[ \] mock 覆盖失败、延迟、重试、结果不确定；
- \[ \] 生成的测试尝试**证伪**变更，而不是确认它；
- \[ \] 关键逻辑跑过有针对性的变异测试；
- \[ \] 重写/迁移与可信实现做过差分校验，且已知缺陷被显式编码；
- \[ \] 评审看的是 oracle，不只是覆盖率；
- \[ \] Agent 创建的 PR 仍受必需检查与人工审查约束。

**给评委（校准层）**

- \[ \] 评分标准先于评委提示词写好，维度独立、二值优先；
- \[ \] 人工标注集按覆盖面抽样、超额采样失败；
- \[ \] 先测人与人的一致度，把它当天花板；
- \[ \] 用 kappa（或加权 kappa），在留出集上确认；
- \[ \] 提示词、模型版本、标准冻结在版本控制里，变更即重跑一致度；
- \[ \] 评委是审批流的**输入**，不是决策者。

**给整栈（系统层）**

- \[ \] 成本按**每个解决的任务**衡量，而不是每个 token；
- \[ \] 把真实并发利用率量出来，再谈自托管盈亏；
- \[ \] harness 与缓存行为纳入监控——一次点更新可能让成本 5 倍。

**一眼结论**：错误的链条是——**被误解的需求 → 错误的实现 → 与之一致的测试 → 全绿的构建**。切断它的方法不是"更努力地相信绿灯"，而是不断问同一句话：**这条证据的来源独立吗？** 测试要能对实现说"不"，评委要能对描述说"不"，评测要能对排行榜说"不"。

---

## 相关阅读

- [Agent 说"做完了"，证据呢：三道交付验证门](https://www.hubwiz.com/blog/agent-delivery-verification-gates/)
- [Agent 审计日志：证人即嫌疑人，怎么让谎言留下痕迹](https://www.hubwiz.com/blog/agent-audit-logs-witness-suspect/)
- [基准分数为什么不可复现？UK AISI 与 EvalEval 用共享规范补评测报告的缺口](https://www.hubwiz.com/blog/uk-aisi-evaleval-reproducible-benchmarks/)
- [专题：Agent / MCP / 自动化完全指南](https://www.hubwiz.com/blog/agent-stack/)
- [专题：AI 基建 / 评测 / 安全完全指南](https://www.hubwiz.com/blog/ai-infra-stack/)

## 本系列另两篇（三站相关系列 · 验证盲区）

- [水密不等于能打印：AI 3D 资产的验收清单](https://bimant.com/blog/watertight-not-printable-ai-3d-asset-acceptance/?ref=hubwiz.com)（同样的"检查通过≠正确"落到 3D 资产：水密的网格可能法线全反、225 个壳体藏在浮雕里、软件默认 K 因子不是物理事实）
- [20 笔交易证明不了 60% 胜率：样本、日志与凭证](https://defiplot.com/blog/trading-sample-size-log-receipts-verification/?ref=hubwiz.com)（落到交易与链上：置信区间、审计日志里的"谁"、评分的地基只有 0.14%）

## 来源

- @johnnylemonny, *AI-Generated Tests Can Agree With the Bug*（dev.to，2026-10-15；引用 Meta JiT catching tests（22,126 个生成测试评估）与 GitHub Copilot 云 Agent 的人工审查要求）：https://dev.to/johnnylemonny/ai-generated-tests-can-agree-with-the-bug-2ao8
- @remojansen, *Mutation Testing with TypeScript: How to Verify Your Tests in the Age of AI Coding Agents*（dev.to，2026-10-14；作者为 StrykerJS 生态参与者，教程可在本地复现）：https://dev.to/remojansen/mutation-testing-with-typescript-how-to-verify-your-tests-in-the-age-of-ai-coding-agents-neh
- @faishalwahiduddin, *Calibrating an LLM-as-Judge for a Vision Check to κ 0.80*（dev.to，2026-10-15；方法来自其 AutoKon 生产环境，作者明确未公开数据集/提示词细节，κ=0.77/0.90 输出为讲解用玩具数据）：https://dev.to/faishalwahiduddin/calibrating-an-llm-as-judge-for-a-vision-check-to-k-080-2h50
- @dailycontext, *The Model Is the Easy Part*（dev.to，2026-10-14；自托管开放权重模型的整栈评测，未点名具体模型与硬件型号）：https://dev.to/dailycontext/the-model-is-the-easy-part-19gh

**本文由 汇智网 · Software 2.0 编译整理，转载请注明出处。**

> **这是「AI 基建 / 评测 / 安全」专题的一部分。**完整地图见：[AI 基建 / 评测 / 安全完全指南](https://www.hubwiz.com/blog/ai-infra-stack/)