从“会诊断”到“能验证”:AI FaultLab 的修复验证闭环设计

前面几个版本里,AI FaultLab 已经把故障模拟、Metrics、Trace、规则诊断、Runbook RAG 和 Diagnosis Agent 串了起来。

但做到这里之后,我越来越觉得,仅仅输出一份"看起来合理"的诊断报告还不够。

比如 Agent 告诉我:

Retry Storm 的问题来自重试放大,建议限制重试次数并增加 jitter。

这句话本身并不难生成。

真正难回答的是:

这个建议真的有效吗?

很多 AI 运维、故障诊断类项目最后都会停在这里:

复制代码
Fault
  ↓
Metrics / Trace
  ↓
RAG
  ↓
LLM
  ↓
Diagnosis Report
  ↓
"建议你增加消费者"
"建议你增加互斥锁"
"建议你限制重试"

至于建议执行之后系统会发生什么,没有后续验证。

所以在 AI FaultLab v0.15.0 里,我没有继续加新的故障场景,也没有急着上 ReAct、Multi-Agent,而是沿着另外一条线继续往下做:

复制代码
Diagnosis
    ↓
Structured Remediation Plan
    ↓
Counterfactual Replay
    ↓
Before / After Metrics
    ↓
Remediation Validation

目标很明确:

不只让 Agent 给出修复建议,还要让系统自己验证这条建议在受控故障环境里到底有没有效果。


一、先解决一个问题:自然语言建议没法执行

最初 Diagnosis Agent 输出的建议本质上还是自然语言:

复制代码
Enable retry limit.
Add retry jitter.
Enable fallback.
Use mutex protection for hot-key rebuild.

这种结果适合人看,但机器很难继续处理。

所以 v0.15.0 第一件事,就是把 suggestion 变成一个稳定的结构化协议。

例如 RETRY_STORM:

复制代码
{
  "scenarioCode": "RETRY_STORM",
  "status": "PROPOSED",
  "actions": [
    {
      "actionType": "ENABLE_RETRY_LIMIT",
      "parameterPatch": {
        "enableRetryLimit": true
      }
    },
    {
      "actionType": "ENABLE_RETRY_JITTER",
      "parameterPatch": {
        "enableJitter": true
      }
    }
  ],
  "expectedEffects": [
    {
      "metricName": "downstream.retry.amplification.factor",
      "direction": "DECREASE"
    }
  ]
}

这里最核心的字段不是 description,而是:

复制代码
parameterPatch
expectedEffects

一个描述:

准备修改什么。

另一个描述:

修改之后,预期哪些指标应该发生什么变化。

这样 RemediationPlan 才真正具备后续执行和验证的可能。


二、为什么 Remediation Plan 第一版没有交给 LLM 自由生成

这里我刻意没有增加新的 LLM 调用。

目前的规划规则是 deterministic mapping。

例如:

复制代码
CACHE_BREAKDOWN
→ enableMutex = true

DB_CONNECTION_POOL_EXHAUSTION
→ enableFastRelease = true

DOWNSTREAM_TIMEOUT
→ enableFallback = true

RETRY_STORM
→ enableRetryLimit = true
→ enableJitter = true

原因很简单。

如果这一阶段直接让模型输出任意:

复制代码
{
  "parameterPatch": {
    "xxx": "xxx"
  }
}

后面会立即遇到两个问题。

第一,模型可能生成根本不存在的参数。

第二,更危险的是它可能直接修改故障条件。

比如一个 RETRY_STORM:

复制代码
{
  "failureRatio": 0.7,
  "enableRetryLimit": false
}

如果所谓的"修复方案"是:

复制代码
{
  "failureRatio": 0.1
}

指标当然会变好。

但这不是修复。

这是把实验难度调低了。

因此这里做了一层明确的 Remediation Policy。

以 RETRY_STORM 为例,目前只允许:

复制代码
enableRetryLimit
enableJitter
retryBackoffMs

而:

复制代码
requestCount
concurrency
failureRatio
scenarioCode
experimentId

都不能被 RemediationPlan 修改。


三、Counterfactual Replay:真正有意思的部分开始了

有了结构化 RemediationPlan 以后,下一步就是重新执行实验。

我给这一阶段的定义是:

Counterfactual Remediation Replay。

它不是 Production Auto Fix,也不是 Self-Healing。

它做的事情更克制:

在同一个故障模型、同一组实验条件下,只修改修复参数,再执行一次实验。

例如原始 RETRY_STORM:

复制代码
{
  "requestCount": 100,
  "concurrency": 20,
  "failureRatio": 0.7,
  "maxRetries": 3,
  "retryBackoffMs": 20,
  "enableRetryLimit": false,
  "enableJitter": false
}

Agent 给出的 patch:

复制代码
{
  "enableRetryLimit": true,
  "enableJitter": true
}

Replay 以后必须是:

复制代码
{
  "requestCount": 100,
  "concurrency": 20,
  "failureRatio": 0.7,
  "maxRetries": 3,
  "retryBackoffMs": 20,
  "enableRetryLimit": true,
  "enableJitter": true
}

这里最重要的不是"重新跑了一遍"。

而是:

复制代码
Original Conditions
        =
Replay Conditions
        -
Remediation Variables

我把这个约束叫做:

Counterfactual Invariant。


四、为了支持 Replay,实验参数必须真正持久化

做到这里时暴露了一个之前并不明显的问题。

原来的 fault_experiment 只需要记录实验本身,所以并没有完整持久化启动参数。

但 Replay 要回答:

这个实验当时到底是怎么跑的?

如果原始参数没存下来,就没办法构造可信的对照实验。

所以 fault_experiment 增加了两个字段:

复制代码
params_json
source_experiment_id

params_json 保存启动实验时的原始参数。

普通实验:

复制代码
source_experiment_id = null

Replay 实验:

复制代码
source_experiment_id = originalExperimentId

这样 Original 和 Replay 之间就形成了明确关系:

复制代码
exp_original
     ↑
     │ source_experiment_id
     │
exp_replay

旧数据如果没有 params_json,系统不会尝试猜测原始参数,而是直接拒绝:

复制代码
ORIGINAL_EXPERIMENT_PARAMS_UNAVAILABLE

我比较认可这种处理。

无法重现,就不要假装能够重现。


五、Replay 不能维护两套实验执行逻辑

还有一个实现上的问题。

最简单的写法当然是:

复制代码
ExperimentService
RemediationReplayService

然后在 RemediationReplayService 里面重新复制一份:

复制代码
创建 experiment
初始化 Trace
找到 FaultScenario
执行 Scenario
写 Metrics
更新状态

但这样很快就会出现两套逻辑漂移。

所以最后把普通启动和 Replay 都收敛到同一个内部执行路径:

复制代码
Normal Start ─────┐
                  ├── executeExperiment(...)
Remediation Replay┘

ReplayService 只负责:

复制代码
加载 Original
↓
恢复 Params
↓
校验 Patch
↓
Clone Params
↓
Apply Patch
↓
创建 Replay Experiment
↓
交给统一执行流程

至于具体 FaultScenario 怎么执行、Metrics 怎么记录、Trace 怎么建立,继续走原有链路。


六、为什么 Python 校验过了,Java 还要再校验一次

RemediationPlan 在 Python Agent 侧已经有 Policy 了。

理论上参数已经经过校验。

但真正执行 Replay 的是 Java Backend。

所以 Backend 不能直接认为:

Python 发过来的肯定合法。

最终做成了两层:

复制代码
Diagnosis Agent
      ↓
Python Remediation Policy
      ↓
Structured RemediationPlan
      ↓
Java RemediationReplayPolicy
      ↓
Controlled Replay

Java 侧目前允许的参数包括:

复制代码
CACHE_BREAKDOWN
- enableMutex
- enableLogicalExpire

DB_CONNECTION_POOL_EXHAUSTION
- enableFastRelease

DOWNSTREAM_TIMEOUT
- enableFallback

RETRY_STORM
- enableRetryLimit
- enableJitter
- retryBackoffMs

像 failureRatio 这种故障条件,即使 Agent 真传过来了,Backend 仍然会拒绝。

这个设计本质上和常规后端开发是一样的:

不要把 AI 当成可信调用方。


七、真正的闭环:Before / After Validation

Replay 做完以后,系统现在已经有两个 Experiment:

复制代码
Original Experiment
Replay Experiment

而两个实验都有独立:

复制代码
Metrics
Trace
experimentId

于是第三阶段开始真正比较结果。

接口设计成:

复制代码
GET /api/experiments/{replayExperimentId}/remediation-validation

不需要再传 originalExperimentId。

因为 Replay 本身已经通过:

复制代码
source_experiment_id

知道自己来自哪个 Original。

完整流程大概是:

复制代码
replayExperimentId
       ↓
load replay experiment
       ↓
source_experiment_id
       ↓
load original experiment
       ↓
restore both params
       ↓
derive actual patch
       ↓
verify invariant
       ↓
load before / after metrics
       ↓
compare
       ↓
generate validation report

八、Validation 不接受 Agent 提交"评分标准"

这里还有一个很容易踩的坑。

RemediationPlan 里已经有:

复制代码
expectedEffects

例如:

复制代码
downstream.retry.amplification.factor
DECREASE

那 Validation 能不能直接使用 Agent 提交的 expectedEffects?

我最后选择了:

不能。

因为这样 Agent 相当于既是考生,又负责出题。

比如真实修复应该让:

复制代码
retry count ↓

如果 Replay 以后 retry count 反而上升,客户端完全可以重新提交:

复制代码
retry count INCREASE

然后告诉系统:

看,验证成功了。

所以 Java Backend 又维护了一层:

复制代码
RemediationValidationPolicy

它根据:

复制代码
scenarioCode
+
original params
+
replay params
+
实际发生的 parameter diff

自行确定需要检查什么指标。

客户端不能指定 Validation 规则。


九、Applied Patch 也是服务器自己算出来的

类似地,Validation 也不信任调用方重新提交:

复制代码
{
  "parameterPatch": {
    "enableRetryLimit": true
  }
}

因为数据库里真正跑的东西才是事实。

所以 Applied Patch 直接来自:

复制代码
diff(originalParams, replayParams)

例如:

复制代码
original.enableRetryLimit = false
replay.enableRetryLimit   = true

最终推导:

复制代码
{
  "enableRetryLimit": true
}

如果此时发现:

复制代码
failureRatio:
0.7 -> 0.3

Validation 不会继续算"修复是否成功"。

而是直接判断:

复制代码
COUNTERFACTUAL_INVARIANT_VIOLATION

因为这两个实验已经失去可比性。


十、Metrics 才是验证的主证据

现在 Validation 主要依赖真实 fault_metric 数据。

比如 RETRY_STORM 当前会关注:

复制代码
downstream.retry.count
downstream.retry.amplification.factor
downstream.total.call.count
downstream.retry.exhausted.count
api.avg.latency.ms

一个 Metric Comparison 大概包含:

复制代码
{
  "metricName": "downstream.retry.amplification.factor",
  "beforeValue": 2.8,
  "afterValue": 1.4,
  "absoluteChange": -1.4,
  "changePercent": -50.0,
  "expectedDirection": "DECREASE",
  "matchedExpectation": true
}

方向判断第一版非常简单:

复制代码
INCREASE:
after > before

DECREASE:
after < before

STABLE:
abs(after - before) <= tolerance

我没有在这一版引入所谓统计显著性。

因为现在 FaultLab 本身就是 deterministic simulation。

这一阶段真正要验证的是:

修复方案是否让指标沿预期方向变化。

而不是:

这个变化是否能代表真实生产环境里的统计因果关系。

这是两个完全不同的问题。


十一、一个细节:before = 0 怎么算变化率

这类比较代码还有一个很实际的问题。

例如:

复制代码
before = 0
after  = 10

公式:

复制代码
(after - before) / before

会直接除零。

所以现在的策略是:

复制代码
changePercent = null

但:

复制代码
expectedDirection = INCREASE
matchedExpectation = true

方向判断和百分比计算分开。

这样既不会产生:

复制代码
Infinity
NaN

也不会因为 baseline 是 0 就丢掉一个明显有效的比较结果。


十二、四种 Validation 状态

最终没有简单设计成:

复制代码
SUCCESS
FAILED

因为真实情况没那么二元。

目前状态是:

VERIFIED

所有 required expected effects 都满足。

复制代码
3 / 3 matched

PARTIALLY_VERIFIED

部分满足、部分不满足。

复制代码
2 / 3 matched

NOT_VERIFIED

数据完整,可以比较,但所有关键指标都没有按预期变化。

INCONCLUSIVE

数据不足,无法可靠判断。

例如:

复制代码
required metric missing

这里我觉得 INCONCLUSIVE 很重要。

缺数据不应该被解释成失败,更不能被解释成成功。


十三、为什么 Trace 不参与最终 VERIFIED 判断

Replay 本身已经有完整 Trace。

所以 Validation 也会比较:

复制代码
span count
error span count
total duration
operation counts

例如 Retry Storm 可以观察:

复制代码
retry.attempt

Downstream Timeout 可以观察:

复制代码
fallback.execute

但第一版里 Trace 只作为:

Supporting Evidence

而不是:

Primary Validation Evidence

也就是说:

复制代码
Metrics
→ 决定 VERIFIED / PARTIALLY_VERIFIED / NOT_VERIFIED

Trace
→ 帮助解释为什么变成这样

否则很容易陷入另一个问题:

一个 span 少了,到底意味着修复成功,还是埋点路径变了?

所以目前没有让 Trace 直接左右 Validation Status。


十四、为什么没有新增 remediation_validation 表

Validation Report 现在不持久化。

因为所有事实数据本来就已经存在:

复制代码
Original Experiment
Replay Experiment
Original Params
Replay Params
Metrics
Trace

而 Validation 又是 deterministic 的。

所以:

复制代码
GET remediation-validation

直接现算即可。

这样避免再维护一份:

复制代码
Derived State

也避免出现:

复制代码
Metrics 已经变化
但 Validation Report 还是旧版本

的问题。

后面如果真的需要审计历史,再考虑快照持久化。

但现在没有必要。


十五、最终得到的不是"自动修复",而是"可验证修复"

v0.15.0 做完以后,我更愿意把这套东西描述成:

复制代码
Fault Injection
    ↓
Observability
    ↓
Diagnosis
    ↓
Remediation Planning
    ↓
Counterfactual Replay
    ↓
Remediation Validation

它和所谓"AI 自动修复"最大的区别在于:

Agent 没有权限直接改生产系统。

它只能提出:

复制代码
Candidate Remediation

系统会把这个方案放到受控实验环境里执行。

然后再根据实际 Before / After 数据告诉你:

复制代码
VERIFIED
PARTIALLY_VERIFIED
NOT_VERIFIED
INCONCLUSIVE

这也是我目前觉得 AI FaultLab 最有辨识度的一块。


十六、目前的边界

这套设计现在能证明的是:

在 FaultLab 当前的确定性故障模型和相同实验条件下,某个修复参数是否产生了预期方向的变化。

它不能证明:

复制代码
真实生产系统一定有效
真实流量下一定有效
具有统计显著性
建立了严格因果关系

它也不是:

复制代码
Chaos Engineering Platform
Production Self-Healing System
Automatic Code Repair System

这些边界我觉得反而应该明确写出来。

做工程系统,最怕的不是功能少,而是把能力说得比实际大。


十七、v0.15.0 之后,我怎么看这套设计

从代码量上看,这个版本增加的并不是特别夸张。

Python 侧核心增加的是:

复制代码
RemediationPlan
Remediation Policy
RemediationPlanningTool

Java 侧主要是:

复制代码
RemediationReplayPolicy
RemediationReplayService
RemediationValidationPolicy
RemediationValidationService
Metric Comparison
Trace Comparison

但它改变了整个项目的主线。

以前的终点是:

复制代码
AI Report

现在的终点变成了:

复制代码
Evidence-backed Validation

这两者的差别其实很大。

前者解决的是:

AI 能不能给出一个像样的答案?

后者开始回答:

AI 给出的建议,能不能被实验系统验证?

目前 Java Backend 最终测试为:

复制代码
189 tests
0 failures
0 errors

Remediation Validation 也没有再引入额外 LLM 判断。

整个验证链路仍然是 deterministic 的。


最后

如果让我用一句话概括 v0.15.0,我会写:

AI FaultLab 不再把 LLM 生成的修复建议当作终点,而是将建议转成受约束的结构化参数,在相同故障条件下执行 Counterfactual Replay,并通过真实 Metrics 与 Trace 对修复效果进行可解释验证。

对我来说,这比再加一个 Agent、再套一个框架更有意思。

因为从这一版开始,AI FaultLab 真正开始处理 AI 系统里一个很实际的问题:

模型说得对不对,不应该只让模型自己回答。

相关推荐
m4Rk_1 小时前
【论文阅读】Agent 记忆机制(81):EMR——用情景记忆避免 Agent 在多步推理中反复绕圈
论文阅读·人工智能·学习·开源·github
Zldaisy3d1 小时前
中科院力学所完成太空增减材制造失重飞行试验
人工智能·制造
帝王铠1 小时前
【AI】一些AI时代的想法闲聊
人工智能
szxinmai主板定制专家1 小时前
RK3588+FPGA异构架构|高速数据采集+边缘AI落地应用全解析
人工智能·嵌入式硬件·fpga开发·架构·zynq
李福春2 小时前
降SpringAI阿里第1掌-亢龙有悔-识势选型
人工智能·架构·腾讯云架构师同盟
李航19832 小时前
给自己的图形引擎,配上了AI渲染,做设计真是太方便了
人工智能·python·计算机视觉·ai·ai编程
m0_466525292 小时前
数字认证参加第十四届用户体验大会,分享标准建设思路
大数据·人工智能·科技
康实训2 小时前
2026数字化AI智慧实训建设方案
大数据·人工智能·实训室·实训室建设
染指11102 小时前
128.Agent-LangChain核心组件-中间件-调用模型的时候
人工智能·windows·中间件·langchain·agent