AI 学习笔记(三十三):LLM 例外债老化清理、执行级治理指标与策略自动化加固最小实践

上一篇我们把例外债预算闸门、跨季度整改 SLA 和治理 ROI 串起来了。

那一层解决的是治理动作能不能被拉起来。

再往前走,真正折磨平台团队的往往不是模型设计,而是执行层的三件琐事:

  1. 旧例外一直留在系统里,谁都知道它该关,但没人真的去关
  2. 仪表盘看着很热闹,到了周会还是回答不了“这周到底减掉了什么债”
  3. 自动化策略脚本越堆越多,某天规则写错、数据缺失或者 owner 变更,整条治理链就开始抖

如果这一层不补,预算、SLA、ROI 都会慢慢失真。

这篇继续往下补执行面,目标很简单:

  1. 把“老化中的例外”识别出来
  2. 把“执行有没有推进”变成可追的指标
  3. 把策略自动化从能跑,补到更稳地跑

1. 预算和 SLA 跑通了,为什么还是会失焦

预算告诉你这季还能欠多少债。

SLA 告诉你多久该给整改动作。

ROI 告诉你这套治理值不值得继续投人。

执行层要回答的却是另一组问题:

  1. 哪些例外已经进入“长期停滞”
  2. 哪些整改项名义上没超期,实际上已经没有推进
  3. 哪些规则明明在自动执行,但结果已经不再可信

很多团队会在这里出现错觉:

  1. expired_count 不高,就以为债在收敛
  2. warning/frozen 有在报警,就以为预算闸门生效了
  3. 每周自动发报表,就以为治理链很稳

真正要看的,是执行层有没有把存量例外往下推。

如果没有,那就是系统在“保持忙碌”,不是在“持续减债”。

2. 先把“老化”定义成可以自动判定的对象

老化不是单一时间字段。

只盯 expires_at,会漏掉很多真实风险:

  1. 证据很久没更新,但续期时间被手工往后推了
  2. owner 还在,但整改里程碑已经三周没动
  3. 例外没过期,可是业务早就下线,债项还躺在账上

我更推荐把老化拆成四个维度:

  1. evidence_stale_days
    距离最近一次证据更新过去了几天
  2. execution_idle_days
    距离最近一次整改动作过去了几天
  3. carry_over_cycles
    已经跨了几个治理周期
  4. service_alive
    这条例外对应的服务、仓库、环境还在不在

这样系统才分得清三类完全不同的问题:

  1. 真正在整改,但节奏慢
  2. 名义上存活,实际已经停滞
  3. 业务都没了,债项却还在

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

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
type RiskBand = 'green' | 'yellow' | 'orange' | 'red';

interface ExceptionRecord {
id: string;
team: string;
band: RiskBand;
lastEvidenceAt: string;
lastExecutionAt: string;
carryOverCycles: number;
serviceAlive: boolean;
remediationStatus: 'open' | 'in_progress' | 'blocked' | 'done';
}

interface AgingSnapshot {
staleEvidenceDays: number;
idleExecutionDays: number;
agingBand: 'fresh' | 'watch' | 'stale' | 'zombie';
shouldEscalate: boolean;
shouldAutoClose: boolean;
}

function diffDays(fromIso: string, now = new Date()): number {
const start = new Date(fromIso).getTime();
return Math.max(0, Math.floor((now.getTime() - start) / (24 * 60 * 60 * 1000)));
}

function evaluateAging(item: ExceptionRecord, now = new Date()): AgingSnapshot {
const staleEvidenceDays = diffDays(item.lastEvidenceAt, now);
const idleExecutionDays = diffDays(item.lastExecutionAt, now);

const shouldAutoClose =
!item.serviceAlive ||
(item.remediationStatus === 'done' && staleEvidenceDays >= 14);

const shouldEscalate =
item.band !== 'green' &&
(idleExecutionDays >= 14 || item.carryOverCycles >= 2);

let agingBand: AgingSnapshot['agingBand'] = 'fresh';

if (shouldAutoClose) {
agingBand = 'zombie';
} else if (idleExecutionDays >= 21 || staleEvidenceDays >= 30) {
agingBand = 'stale';
} else if (idleExecutionDays >= 7 || staleEvidenceDays >= 14) {
agingBand = 'watch';
}

return {
staleEvidenceDays,
idleExecutionDays,
agingBand,
shouldEscalate,
shouldAutoClose,
};
}

这段逻辑不追求完美,它要先解决一个现实问题:

例外债要能被系统识别成“还在推进”“已经停住”“应该关单”。

3. 执行级治理指标,要盯能推动动作的那几项

很多治理报表的毛病,是把结果指标和执行指标混在一起。

结果指标当然还要看:

  1. active_exceptions
  2. debt_points
  3. orange_red_items
  4. over_budget_days

执行层更该追加这几项:

  1. stale_exception_ratio
    进入 stale/zombie 的债项占比
  2. weekly_remediation_velocity
    每周真正推进到下一状态的整改项数量
  3. auto_close_ratio
    自动关单占全部关单的比例
  4. reopen_after_close_ratio
    关单后又重新打开的比例
  5. policy_override_frequency
    每周手工 override 规则的次数
  6. owner_missing_ratio
    找不到有效 owner 的债项占比

这些指标的价值不在展示,而在让你一眼看到执行卡点落在哪一层:

  1. stale_exception_ratio 高,说明存量债压着不动
  2. weekly_remediation_velocity 低,说明整改链没有真正往前走
  3. policy_override_frequency 高,说明自动化规则已经开始不可信

我很少建议一上来做很复杂的治理看板。

第一版只要能按团队输出下面这张表,就够用了:

team stale_ratio weekly_velocity auto_close_ratio overrides owner_missing_ratio
payments 0.38 2 0.11 6 0.00
search 0.12 7 0.29 1 0.00
growth 0.44 1 0.08 4 0.18

这张表一出来,周会上讨论的重心会从“风险高不高”变成“哪一队真的没在动”。

4. 把老化清理接成自动化链,不靠人工翻表

老化清理如果还靠人一条条翻,执行成本会很快盖过治理收益。

更稳的做法是把动作拆成四档:

  1. watch
    自动 comment,提醒 owner 补证据或更新进度
  2. escalate
    发给 team owner / platform owner,进周会清单
  3. freeze
    对高风险且长期停滞的债项收紧续期与新增审批
  4. auto_close
    业务下线或整改已完成且稳定一段时间后自动关单

一个最小执行器可以像这样:

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
interface CleanupAction {
action: 'watch' | 'escalate' | 'freeze' | 'auto_close' | 'noop';
reason: string;
}

function nextCleanupAction(
item: ExceptionRecord,
aging: AgingSnapshot
): CleanupAction {
if (aging.shouldAutoClose) {
return {
action: 'auto_close',
reason: 'service-retired-or-remediation-finished',
};
}

if (
(item.band === 'orange' || item.band === 'red') &&
aging.idleExecutionDays >= 21
) {
return {
action: 'freeze',
reason: 'high-risk-item-idle-too-long',
};
}

if (aging.shouldEscalate) {
return {
action: 'escalate',
reason: 'carry-over-or-idle-execution',
};
}

if (aging.agingBand === 'watch') {
return {
action: 'watch',
reason: 'evidence-or-execution-needs-refresh',
};
}

return {
action: 'noop',
reason: 'healthy-enough',
};
}

动作分层以后,自动化链条会清楚很多:

  1. 每天跑 aging scan
  2. 先把 watch 自动 comment 掉
  3. escalatefreeze 聚到 team 级摘要
  4. auto_close 走一次可回退的关单流程

执行面最怕“一上来就自动删”。
只要先做成“自动建议 + 明确回退”,团队接受度会高很多。

5. Policy automation hardening,核心不是多写规则,是先补防抖层

策略自动化跑久了,通常不是规则不够,而是缺少防抖层。

最常见的脆弱点有五种:

  1. 上游字段缺失,结果把一批债项误判成低风险
  2. owner 离职或团队改组,升级链路断掉
  3. 新服务接入时没补元数据,系统把它全判成例外
  4. 规则刚上线就直接写生产状态,回滚困难
  5. 手工 override 越来越多,自动化和真实流程开始分叉

补强时,我优先加下面四层:

  1. rule_version
    每次策略执行都记录规则版本
  2. dry_run
    新规则先出建议,不直接写状态
  3. fallback_owner
    owner 缺失时自动升级到 team owner 或 platform queue
  4. circuit_breaker
    单次异常波动过大时暂停自动写回

一个够用的防抖入口可以这样写:

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
interface PolicyDecision {
action: 'write' | 'review' | 'halt';
reason: string;
}

function evaluatePolicyWriteGuard(input: {
changedItems: number;
totalItems: number;
ownerMissingRatio: number;
dryRun: boolean;
}): PolicyDecision {
if (input.dryRun) {
return { action: 'review', reason: 'dry-run-enabled' };
}

if (input.ownerMissingRatio > 0.05) {
return { action: 'halt', reason: 'too-many-items-without-owner' };
}

if (input.changedItems > Math.max(20, Math.floor(input.totalItems * 0.25))) {
return { action: 'review', reason: 'change-spike-detected' };
}

return { action: 'write', reason: 'safe-to-apply' };
}

这类保护逻辑的意义很朴素:

让自动化在不确定时退回人工 review,而不是带着错误把系统状态改坏。

6. 一条够用的执行面治理流水线

如果你准备把这一层真正接起来,我建议产出固定三类文件:

  1. exception_aging_snapshot.json
  2. exception_execution_metrics.md
  3. policy_hardening_audit.md

每日 / 每周 / 每月的节奏可以这样分:

  1. 每日
    重算 aging、发 watch 提醒、生成 auto-close 建议
  2. 每周
    汇总 stale 项、升级链路、冻结候选、team velocity
  3. 每月
    做 policy drift review,复盘 override 和 halt 事件

这三层连起来以后,治理系统才不只是“有一堆规则”,而是真能持续减债。

7. 一周最小落地顺序

如果你现在已经有预算、SLA、ROI,但执行面还比较散,我建议按这个顺序补:

  1. Day 1
    给现有例外数据补 lastEvidenceAtlastExecutionAtserviceAlive
  2. Day 2
    跑第一版 aging scan,把 watch/stale/zombie 分层打出来
  3. Day 3
    接 team 级执行指标,只先出 stale_ratioweekly_velocityoverride_frequency
  4. Day 4
    auto_closefreeze 接 review gate,不直接写生产状态
  5. Day 5
    为策略执行补 rule_versiondry_runcircuit_breaker
  6. Day 6-7
    拉一次月度回看,确认哪些规则该转正式、哪些还要继续 shadow

这个顺序的重点,是先把“识别”和“防抖”补好,再扩大自动化写入面。

总结

例外治理走到这一阶段,关键点已经不只是预算收口,而是执行层能不能持续把旧债往下推。

真正该补的是三件事:

  1. 老化识别
  2. 执行级指标
  3. 策略自动化加固

这三层接起来之后,治理周会谈的就不会再是“为什么又有一批旧例外没人动”,而会变成“哪些债项该升、该关、该冻,系统已经先帮你分好了”。

如果你现在只把系统做到预算和 SLA,我最建议的下一步不是再发明更复杂的风险权重,而是先把 aging cleanup 和 policy hardening 接进去。

本文永久链接: https://www.mulianju.com/learning-notes/ai-learning-notes-llm-exception-aging-cleanup-execution-metrics-policy-hardening/