AI 学习笔记(三十四):LLM 例外策略债退役机制与季度控制证据自动化最小实践

上一篇我们把 aging cleanup、执行级指标和策略自动化加固接起来了。

那一步解决的是“旧债有没有被识别出来”和“执行面有没有开始动”。

再往前走,平台团队很快会撞上另一堵墙:

  1. 例外项明明已经修完了,系统里还是关不掉
  2. 季度审查一到,大家开始翻截图、翻工单、翻群消息补证据
  3. 一批看起来已经退役的债,过两周又以另一个名字重新回来

这类问题不在检测层,也不在预算层。

它落在治理系统里最容易被拖延的一段:

退役机制和控制证据。

这篇就只补这一段,目标很具体:

  1. 把“什么时候可以退役”定义成可自动判定的状态
  2. 把季度控制证据做成能自动生成的 evidence pack
  3. 把退役、复开和季度审查接成一条能持续跑的最小闭环

1. 老化清理做完了,为什么债还是退不掉

很多团队到这一步会有一种错觉:

  1. stale 项降下来了
  2. owner 都补齐了
  3. 周报里也能看到 velocity

看上去系统已经在收债。

真正卡人的,是收口阶段。

因为“老化中的债”不等于“可以正式退役的债”。

退役至少要同时回答四个问题:

  1. 对应控制是不是已经恢复
  2. 恢复之后有没有稳定跑过一个观察窗口
  3. 证据是不是足够让季度审查直接复核
  4. 这条债关掉以后,会不会因为 owner、规则或系统漂移很快复开

如果这四个问题没有结构化定义,团队迟早会回到人工判断:

  1. 会议里口头说“应该可以关了”
  2. 审计来了再临时补材料
  3. 几周后发现控制又掉了,只能重新开债

所以这里更值得投入的,是给退役补一套状态机,不要继续靠“多看几天”拖时间。

2. 把退役定义成状态机,不要停留在主观判断

我更推荐把例外债的生命周期拆成五个状态:

  1. active
    仍在生效,风险接受还成立
  2. candidate
    控制已经恢复,进入退役候选
  3. grace
    观察窗口内持续稳定,准备正式退役
  4. retired
    已关账,进入季度证据归档
  5. reopen
    控制重新失效,或证据不足,需要恢复治理

状态名字没那么重要,关键是每个状态的准入条件要固定。

一个够用的最小判定器可以先写成这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
type DebtState = 'active' | 'candidate' | 'grace' | 'retired' | 'reopen';

interface ExceptionDebtItem {
id: string;
team: string;
policyId: string;
service: string;
controlPassRate: number;
evidenceFreshDays: number;
quietDays: number;
reopenCount: number;
ownerConfirmed: boolean;
rollbackReady: boolean;
lastOverrideDays?: number;
}

interface RetirementDecision {
nextState: DebtState;
reason: string;
shouldCreateEvidencePack: boolean;
}

function evaluateRetirement(item: ExceptionDebtItem): RetirementDecision {
if (!item.ownerConfirmed) {
return {
nextState: 'active',
reason: 'owner-not-confirmed',
shouldCreateEvidencePack: false
};
}

if (item.controlPassRate < 0.98) {
return {
nextState: 'active',
reason: 'control-not-stable',
shouldCreateEvidencePack: false
};
}

if (item.evidenceFreshDays > 14) {
return {
nextState: 'active',
reason: 'evidence-too-old',
shouldCreateEvidencePack: false
};
}

if (!item.rollbackReady) {
return {
nextState: 'candidate',
reason: 'waiting-for-rollback-plan',
shouldCreateEvidencePack: false
};
}

if ((item.lastOverrideDays || 999) < 7) {
return {
nextState: 'candidate',
reason: 'override-too-recent',
shouldCreateEvidencePack: false
};
}

if (item.quietDays < 14) {
return {
nextState: 'grace',
reason: 'observing-post-fix-window',
shouldCreateEvidencePack: false
};
}

return {
nextState: 'retired',
reason: item.reopenCount > 0 ? 'retired-after-reopen-history' : 'retired-cleanly',
shouldCreateEvidencePack: true
};
}

这段逻辑里我故意保留了几个很土、但很有用的门槛:

  1. controlPassRate
    没恢复到足够稳定,别急着退
  2. evidenceFreshDays
    证据太旧,季度审查时一定会翻车
  3. rollbackReady
    没有回退说明,关账以后出了回归会很被动
  4. lastOverrideDays
    刚刚还在人工 override,说明系统还不稳

退役系统的关键在于稳稳关账,别让它变成下一轮拍脑袋复开。

3. 季度控制证据别靠截图,做成固定 evidence pack

团队越往后走,季度审查的真实成本越高。

因为你需要的不只是“这条债关了”,而是能回答下面这些追问:

  1. 为什么能关
  2. 关之前看了哪些证据
  3. 关之后谁确认过
  4. 同季度还复开了哪些项
  5. 哪些控制虽然没关账,但正在收敛

如果这些信息分散在工单、群聊、报表和仓库日志里,审查成本会越来越像一次现场取证。

更稳的做法,是每个季度固定生成一套 evidence pack。

我通常会让它至少包含这几部分:

  1. manifest.json
    记录季度、生成时间、策略版本、数据快照范围
  2. retired_items.csv
    记录本季度正式退役的例外项
  3. reopened_items.csv
    记录本季度复开的项和复开原因
  4. control_evidence_summary.md
    说明通过率、owner 完整度、override 趋势、样本链接
  5. review_notes.md
    记录季度审查时的人工备注和保留意见

数据结构可以先收成下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
interface RetiredItemEvidence {
id: string;
team: string;
policyId: string;
retiredAt: string;
quietDays: number;
controlPassRate: number;
evidenceLinks: string[];
}

interface QuarterlyEvidencePack {
quarter: string;
generatedAt: string;
policyVersion: string;
retiredItems: RetiredItemEvidence[];
reopenedItems: Array<{
id: string;
reopenedAt: string;
reason: string;
}>;
controlSummary: {
passRate: number;
overrideFrequency: number;
ownerCoverage: number;
evidenceFreshnessP95: number;
};
}

function buildQuarterlyEvidencePack(
quarter: string,
policyVersion: string,
retiredItems: RetiredItemEvidence[],
reopenedItems: QuarterlyEvidencePack['reopenedItems'],
controlSummary: QuarterlyEvidencePack['controlSummary']
): QuarterlyEvidencePack {
return {
quarter,
generatedAt: new Date().toISOString(),
policyVersion,
retiredItems,
reopenedItems,
controlSummary
};
}

这个 pack 真正的价值,不在展示层。

它让你把季度审查从“重新找证据”变成“复核系统已经整理好的证据”。

一旦审查对象变成 pack,本季有没有真的减少债、哪些控制最容易复开、哪个团队最常缺证据,这些问题就都能落到一份固定产物里。

4. 退役和季度证据,最好走同一条自动化流水线

我不建议把“退役判定”和“季度归档”拆成两套完全不同的系统。

更稳的做法,是共用同一批基础数据:

  1. 例外项状态表
  2. 控制执行结果
  3. owner / approver 元数据
  4. override / freeze / reopen 历史
  5. 审查样本链接

流水线可以先拆成三层:

1) 每日层

每日只做轻量计算:

  1. 重算 candidate / grace / retired / reopen
  2. 给新进入 candidate 的项发提醒
  3. 给触发 reopen 的项发升级通知

2) 每周层

每周只做队列整理:

  1. 生成 retirement_review_queue.md
  2. 汇总本周新增退役候选
  3. 给 owner 和 reviewer 分配待确认项

3) 每季层

季度层才做证据打包:

  1. 冻结该季度最终状态
  2. 输出 evidence pack
  3. 生成审查摘要和抽样链接

如果你现在已经有自动化策略写回链,建议再补一个最小保护:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
interface EvidenceWriteGuardInput {
retiredCount: number;
reopenedCount: number;
missingEvidenceRatio: number;
dryRun: boolean;
}

function evaluateEvidenceWriteGuard(input: EvidenceWriteGuardInput) {
if (input.dryRun) {
return { action: 'review', reason: 'dry-run-enabled' };
}

if (input.missingEvidenceRatio > 0.02) {
return { action: 'halt', reason: 'too-many-items-without-evidence' };
}

if (input.reopenedCount > Math.max(3, Math.floor(input.retiredCount * 0.3))) {
return { action: 'review', reason: 'reopen-ratio-too-high' };
}

return { action: 'write', reason: 'safe-to-publish-quarterly-pack' };
}

原因很简单:

季度 pack 一旦被默认当成正式证据,错误写入的代价会比日常报表大得多。

宁可先卡住 review,也别把半残数据写进审查产物。

5. 退役闭环里最容易漏掉的三件事

1) 只退控制,不退上下游依赖

很多债项表面看已经完成整改,实际上只是主策略恢复了。

它依赖的:

  1. feature flag
  2. 白名单
  3. fallback 配置
  4. 临时审批流程

还留在生产里。

这种情况最容易在下个季度复开。

所以退役前最好多问一句:

临时补丁有没有一起清掉。

2) 证据只有结果,没有过程

季度审查时,光有“通过了”还不够。

你还得能解释:

  1. 什么时候恢复
  2. 谁确认
  3. 样本怎么抽
  4. 观察窗口多长

所以 evidence pack 里最好同时放结果和过程,不要只留最终状态。

3) 退役动作没有 reopen 规则

很多系统会认真定义“怎么关”,却没定义“什么情况下必须重开”。

我一般会把 reopen 条件写死成几条:

  1. 连续两个周期控制失败
  2. 关键 owner 为空
  3. 新 override 在观察窗口内再次出现
  4. 审查样本无法复核

这样一来,复开就会变成规则动作,而不是情绪动作。

6. 一周最小落地顺序

如果你们现在已经有 aging cleanup 和执行指标,我建议下一周这样补:

  1. Day 1
    给例外项补 candidate / grace / retired / reopen 四个状态位
  2. Day 2
    固化退役门槛,尤其是 quietDayscontrolPassRaterollbackReady
  3. Day 3
    产出第一版 retirement_review_queue.md
  4. Day 4
    落第一版 manifest.jsoncontrol_evidence_summary.md
  5. Day 5
    给 evidence pack 加 write guard 和 dry-run
  6. Day 6-7
    跑一次模拟季度审查,看 reviewer 还缺什么证据

这个顺序的重点,是先让“退役可判定”,再让“季度可复核”。

别一开始就做很重的审计平台。

把状态机和 evidence pack 做出来,很多治理摩擦会先降下来。

总结

例外债治理走到这一段,重点已经落在怎么稳稳关掉旧债,并在季度里拿得出证据。

更值得投入的三件事是:

  1. 退役状态机
  2. evidence pack
  3. reopen 规则

这三层接起来以后,治理系统才算从“持续识别问题”走到“持续完成关账”。

如果你现在已经能看见 aging、velocity 和 override,我最建议的下一步,就是把退役机制和季度控制证据自动化补上。

本文永久链接: https://www.mulianju.com/learning-notes/ai-learning-notes-llm-exception-retirement-quarterly-control-evidence-automation/