# 测试 Agent Core 设计

**一句话定位：** 这不是"一套写死的测试流程",而是一台**双层反馈机**,内环把单个测试任务收敛到事实,外环把跨项目的经验复利成先验。核心是**状态 + 策略**,不是流程。

## 1. 目标与非目标

**目标**

- 测试人员用自然语言下达测试意图,Agent 自行完成测试。
- 人员离线后,任务可无人值守持续运行并最终收敛。
- 面对不同类型的软件/项目/测试目标,**不预设单一方法**,而是由 Agent 主动摸索出正确的测试方向。
- 每个项目沉淀的经验可供后续项目复用与修正,形成正反馈闭环。

**继承的成熟框架**

- **MAPE-K**:Monitor–Analyze–Plan–Execute over shared Knowledge —— 本设计的骨架。
- **OODA**:观察→定向→决策→行动 —— 强调"定向(Orient)"即"找方向",多数 Agent 在此偷懒。
- **CBR(案例推理)+ 主动学习**:参考索引 = case base;"找方向"= 选信息增益最大的假设。

## 2. 核心洞察

### 2.1 核心是"状态 + 策略",不是"流程"

如果核心是一个提示词模板或固定步骤,那么一旦换项目类型就得改核心——这仍然是把方法写死了。
正确的核心是**一组会演化的状态 + 一个转移函数**:

```
Core = (TargetModel, HypothesisBoard, EvidenceLedger, Budget) + Transition
```

方法不是写死的,而是**从目标模型推导出来的**:

- **摸索(Recon)** = 填充并细化 TargetModel。
- **实施(Execute)** = 让 harness 去验证假设。
- **反馈(Feedback)** = 用证据更新模型与假设后验。

### 2.2 方向选择必须有可计算的打分函数

否则大模型会挑"好玩的/好做的",而不是"该做的"。

```
priority(h) = 预期信息增益(h) × 风险覆盖(h) ÷ 成本(h)
```

这是整个设计里唯一不能省去的硬约束。

### 2.3 两种反馈的极性不能放反

| 环   | 范围         | 极性                | 作用                         | 若放反的后果                                       |
| --- | ---------- | ----------------- | -------------------------- | -------------------------------------------- |
| 内环  | 单任务(分钟~小时) | **负反馈 / 收敛**      | 误差信号把系统推向不动点(可复现缺陷、被验证的假设) | 错误被放大,Agent 一路"论证"自己对(reward hacking / 确认偏误) |
| 外环  | 跨任务 / 跨项目  | **正反馈 / 放大(带阻尼)** | 有效策略被强化复用,知识复利             | 纯正向放大 → 坏先验被反复强化 → **索引投毒**                  |

- 内外环的"负反馈"含义不同:内环的负反馈是**误差信号**(预测被证伪);外环的负反馈是**证据门控的衰减**(置信度下调)。
- 外环的正反馈必须**带阻尼**,否则复利会变成固化成见。

### 2.4 负结果不是没用,而是被用错了地方

**负结果(失败方案 + 失败条件)属于知识层,它的角色是"过滤器"而非"阻尼器"。**

- 作为过滤器:它**收缩动作空间**——"在这个架构形态下,这条路走不通",直接排除未来假设。
- 它**不缩小知识**:索引里记录失败,是为了让下一个项目少走弯路,而不是让系统对自己失去信心。
- 落到 schema 上:每条 case 必须同时存**成功策略**与**失败方案及原因**,否则索引会产生幸存者偏差。

---

## 3. 架构:双层反馈环

```
┌─ 外环 · 跨任务/跨项目 —— 正反馈:知识复利(带阻尼) ──────────────┐
│                                                                │
│  ① 运行记录 ──▶ ② 模式提取 ──▶ ③ 参考索引 Case Base            │
│      ▲             │  (负结果=过滤器)      │(阻尼阀:证据门控衰减)│
│      │             ▼                      ▼                    │
│      │        ┌─ 内环 · 单任务 —— 负反馈:收敛 ─┐              │
│      │        │  ① 目标模型&假设看板 ──▶ ② 排序&执行 │           │
│      │        │        ▲                    │        │           │
│      │        │        │      误差信号      ▼        │           │
│      │        │  ④ 更新后验&收敛判定 ◀── ③ 证据/预言 │           │
│      │        └───────────┬────────────────┘                   │
│      │                    │(复用先验→假设种子)                  │
│      └──────────── ④ 检索先验 ◀───────────────────────────────┘
└────────────────────────────────────────────────────────────────┘
```

- **内环**:单任务收敛循环,负反馈驱动,终点是"可复现的缺陷 + 被验证/证伪的假设"。
- **外环**:跨项目知识复利,正反馈驱动,终点是"可复用、带适用条件、带置信度"的 case base。
- **复用通道**:外环先验注入内环的 recon,作为假设种子(缩短冷启动)。

详见 `feedback-loops.png`。

## 4. 核心状态模型(Schema 草案)

> 原则:**这是 v1 的全部"核心"**。schema 必须从真实运行里长出来,不要预先设计过重。

### 4.1 TargetModel(目标模型)

```jsonc
{
  "target": { "kind": "web-api | web-ui | mobile | cli | lib | data-pipeline", "entrypoints": [] },
  "stack": { "lang": [], "frameworks": [], "build": "", "runtime": "" },
  "architecture": { "shape": "monolith | service | distributed", "boundaries": [] },
  "qualityGoals": [ { "attr": "functional | performance | security | compat | reliability",
                      "priority": 1, "rationale": "" } ],
  "constraints": { "env": "", "data": "", "time": "", "access": "", "blastRadius": "" },
  "observability": { "logs": [], "metrics": [], "traces": [], "testHooks": [] },
  "unknowns": [ { "question": "", "cheapProbe": "" } ]
}
```

### 4.2 HypothesisBoard(假设看板)

```jsonc
{
  "hypotheses": [
    {
      "id": "H1",
      "claim": "分页参数 order 在负数时未做校验",
      "goalAttr": "functional",
      "risk": 0.7,            // 影响
      "infoGain": 0.9,        // 预期信息增益
      "cost": 1.0,            // 成本
      "score": 0.63,          // priority 函数输出
      "status": "open | probing | confirmed | refuted",
      "oracle": "expected 400, observed 200",
      "evidence": ["E3"],
      "provenance": "recon | prior:CB-12 | user"
    }
  ]
}
```

### 4.3 EvidenceLedger(证据账本)

```jsonc
{
  "evidence": [
    {
      "id": "E3",
      "type": "command | http | log | metric | trace | diff",
      "reproducible": true,
      "minimalRepro": "curl -X POST .../items?order=-1",
      "observed": "...",
      "confidence": 0.85,
      "costSpent": { "steps": 3, "seconds": 42, "tokens": 8200 }
    }
  ]
}
```

### 4.4 Budget(预算 / 停止条件)

```jsonc
{
  "budget": { "maxSteps": 200, "maxSeconds": 7200, "maxCost": 5.0, "maxBlastRadius": "test-env-only" },
  "definitionOfDone": [
    "每个 high-risk goalAttr 至少有 1 条 confirmed 或 refuted 假设",
    "无 open 假设的 score > 0.5",
    "连续 N 步无新证据(漂移看门狗)"
  ],
  "exploreExploit": { "exploreRatio": 0.3 }   // 防止过早收敛到已知区
}
```

### 4.5 CaseBaseEntry(参考索引条目)

```jsonc
{
  "id": "CB-12",
  "structuralFeatures": {
    "kind": "web-api", "architecture": "service",
    "goalAttr": "functional", "constraint": ["no-auth-on-test-env"]
  },
  "applicability": "REST + 分页 + 无 schema 校验 的写接口",   // 关键:没有它就等于靠玄学复用
  "strategy": "对每个写接口做参数边界 + 类型混淆探测",
  "adaptationPoints": ["分页参数名不同需先枚举"],
  "outcome": { "found": 2, "falsePositives": 0, "cost": "低" },
  "negativeResults": [ { "tried": "对读接口做同样探测", "reason": "读接口有 schema 校验,无收益" } ],
  "confidence": 0.8,
  "provenance": "project-A/2026-10",
  "decay": { "lastValidated": "2026-10", "halfLifeDays": 180 }
}
```

## 5. 内环:单任务收敛循环

### 5.1 循环步骤(MAPE-K 实例化)

1. **Recon(摸索)**:扫描仓库/接口/文档/运行日志,填充 TargetModel,列出 `unknowns`,并为每个 `unknown` 选一个"最便宜的探测"。
2. **Hypothesize**:把 unknowns 与先验(来自 case base)转成候选假设,写入 HypothesisBoard。
3. **Prioritize**:用 `priority(h)` 打分排序,取 top-K。
4. **Execute**:harness 调用确定性工具(读文件 / 执行命令 / 调 HTTP / 解析输出)去验证最高分假设。
5. **Record**:把结果写入 EvidenceLedger(含最小化复现与成本)。
6. **Update**:更新假设后验(`confirmed/refuted`),修正 TargetModel(新发现也可能**推翻前期方向**)。
7. **Decide**:检查 Definition of Done 与预算;未达则回到 2,达到则产出报告 + case base 记录。

### 5.2 关键点

- **误差信号 = 预测被证伪 / 证据与模型冲突**,这是内环唯一的驱动力,保证收敛。
- **Orchestrator(编排)** 与 **Workers(执行)** 分离:编排持有全局状态,worker 是无状态、可并行、可丢弃的执行单元。这让"长时运行"变得可恢复。
- **工具必须确定性**:LLM 负责"决策",工具负责"事实"。所有事实来自工具,不来自模型记忆。

### 5.3 伪代码

```python
state = load_checkpoint() or init_state(goal_nl, target)
while not done(state) and within_budget(state):
    targets = recon(state) if state.needs_recon else []
    state.model.update(targets)
    state.board.extend(hypothesize(state, prior=casebase.retrieve(state.model)))
    h = argmax(state.board.open, key=priority)          # 增益 × 风险 ÷ 成本
    result = harness.execute(h.probe)                   # 确定性工具
    state.ledger.append(record(result, minimal_repro(result)))
    update_posterior(state, h, result)                  # 负反馈:证伪 / 确认
    checkpoint(state)                                    # 可恢复
report = synthesize(state)
casebase.upsert(extract_pattern(state))                  # 外环:正反馈
```

---

## 6. 外环:跨项目知识复利

### 6.1 外环职责

- **模式提取**:从 EvidenceLedger 中抽象出"结构特征 → 策略 → 结果"的可复用模式。
- **索引维护**:写入 case base,并持续修订置信度。
- **先验注入**:为下一个项目的 recon 提供假设种子。

### 6.2 正反馈的阻尼机制(防索引投毒)

- **证据门控**:只有当同一模式被**独立复现**(不同项目/不同环境)达到阈值时,置信度才上调。
- **衰减**:长时间未被验证的模式,按 `halfLifeDays` 下调置信度。
- **反例优先**:一个明确的反例(失败条件)对置信度的下调幅度,必须大于一次成功的上调幅度——不对称才安全。
- **来源标注**:用户确认 \> 自动确证 \> 单次观察。

### 6.3 检索必须按结构特征

- 用**架构形态 / 技术栈 / 目标质量属性 / 约束 / 风险轮廓**做检索键,而不是项目名或关键词。
- **没有 "applicability(适用条件)" 的索引 = 靠玄学复用先验**,这是同类工具最常见的翻车点。

## 7. 失败模式与对策

| 失败模式                  | 成因                    | 对策                               |
| --------------------- | --------------------- | -------------------------------- |
| **Oracle 问题**         | Agent 判断不了"真缺陷 vs 误报" | 多重预言三角验证 + 最小化复现 + 置信度分级;必要时人工兜底 |
| 确认偏误 / reward hacking | 内环误用正反馈               | 内环严格用负反馈;假设必须"可证伪",证据必须来自工具      |
| 探索坍缩                  | 外环误用负反馈 / 无探索预算       | 外环用带阻尼的正反馈;固定探索比例                |
| 先验投毒                  | 纯正反馈放大坏先验             | 证据门控 + 衰减 + 反例优先                 |
| 假设抖动不收敛               | 打分函数不稳定 / 目标不清        | 稳定 priority 函数;DoD 明确;漂移看门狗      |
| 把环境噪声当信号              | flaky 环境 / 不可复现       | 幂等与快照;重复运行判定;隔离不稳定用例             |
| 成本无界                  | 缺预算约束                 | 步数/时间/成本三重上限,超限即归档并上报            |

## 8. 关键取舍与开放问题

- **收敛 vs 探索**:DoD 太严会过早停止,太松会无限探索。需用数据调优,而非拍脑袋。
- **索引粒度**:太细无法复用,太粗无法适用。建议以"结构特征 + 适用条件"为单位。
- **负结果的成本**:记录失败方案需要额外结构化工作,但正是它让索引不产生幸存者偏差。
- **预言的可信度**:自动化预言的置信度必须显式建模,否则"confirmed"会变成噪声。
- **何时必须人工**:高危动作、真缺陷确认、方向性大改——应设计为"默认入队",而非默认阻断。

---

## 结语

- **核心是状态 + 策略,不是流程。**
- **内环求收敛(负反馈),外环求复利(带阻尼的正反馈)。**
- **负结果在知识层是过滤器:它修剪动作空间,不缩小知识。**
- 唯一不可省的硬约束:**方向选择必须有可计算的打分函数**,否则"让大模型自己找方向"会退化成"让大模型自己找借口"。