你是平台团队 leader,要为一次核心系统迁移立项:估算 18 个月 · $20M · 跨 3 团队 60 人,对 VP 承诺交付日期和预算。你翻了公司过去 40 个同类项目:中位数项目基本按预算完成,均值看着也只超一点。于是按「均值 + 10% buffer」立预算——这正是多数项目暴雷的起点。
因为 IT 成本超支不是正态,而是幂律(power-law)肥尾。Flyvbjerg 用 1.6 万个项目的库证明:IT 超支均值比中位数高约 73 个百分点——中位项目大致在预算内,均值被极端项目拉高;六分之一是黑天鹅、平均超支 200%;超支 >50% 的那 18% 项目平均超支 447%。不是估算不准,是分布形状决定灾难会周期性发生。
约束:模型要能对上级显式声明假设与尾部敞口、有可触发的止损/回滚点;成功定义不能是「所有维度全中」的连乘门——那会把正常波动也报成失败(下详)。
graph TD
E["项目估算
历史参照类"] --> Q{"分布是
正态还是肥尾?"}
Q -->|"正态思维 ❌"| N1["盯均值 + 方差"]
N1 --> N2["固定 10% buffer"]
N2 --> N3["尾部裸奔
黑天鹅=项目死亡"]
Q -->|"肥尾思维 ✅"| F1["参照类预测
取分布 P80 分位"]
F1 --> F2["尾部定预留金
+ 分阶段承诺"]
F1 --> F3["设止损线
Kill Line"]
F2 --> M["尾部指标监控
燃尽/里程碑滑移"]
F3 --> M
M -->|"触线"| K["止损: 砍范围/停/转向"]
M -->|"正常"| C["继续 + 下一阶段再承诺"]
classDef bad fill:#2a1530,stroke:#ff7ab6,color:#e8eef5
classDef good fill:#0e2030,stroke:#5eead4,color:#e8eef5
classDef mid fill:#1a2530,stroke:#64c8ff,color:#e8eef5
class N1,N2,N3 bad
class F1,F2,F3,K,C good
class E,Q,M mid
正态分支把风险压在一个被尾部污染的均值上;肥尾分支承认尾部存在,用预留 + 止损 + 分阶段把「敞口」限成「可控损失」
三个组件:参照类预测提供分布而非点估(不问「这项目要多久」,问「这类项目历史分布长什么样」);尾部预留 + 止损线把无界敞口截成有界损失;分阶段承诺 + 尾部指标监控把一次 all-in 赌注拆成可中止的期权序列。
原理:正态下均值 ± 2σ 覆盖 95%,尾部指数级衰减,极端事件几乎不可能。幂律不同:P(超支 > x) ∝ x^(-α),尾巴按多项式衰减,慢得多。α ≤ 2 时方差发散、α ≤ 1 时均值发散——样本算出的「均值」不收敛,加一个新极端样本就跳一大截。IT 超支均值高中位 73pp,正是这种指纹:典型项目没事,均值被尾部拽高。对肥尾量「平均超支多少」几乎无决策价值。
法则:用分位数立计划,用尾部敞口定预留和止损;永远别用样本均值给肥尾量做承诺。
# fat tails: sample mean drifts, don't commit on it (pseudo-code)
overruns = load_reference_class("platform-migration") # historical overruns
overruns.mean() # jumps with each new extreme — unstable, don't use
p50 = quantile(overruns, 0.50) # median: typical project ~= 0.05
p80 = quantile(overruns, 0.80) # anchor the plan here
p95 = quantile(overruns, 0.95) # may be > 1.0 (doubles) — the tail
tail = [x for x in overruns if x > p80] # tail expected loss (CVaR-like)
cvar_80 = sum(tail) / len(tail) # size reserve & kill line on this, not mean()
原理:尾部无法从分布里消除,就用工程手段把「无界敞口」截成「有界损失」。三件武器:①尾部定预留——contingency 不按「均值 × 10%」,按参照类 P80/P95 分位定,覆盖大多数尾部情形;②止损线(kill line)——预先声明「烧到 X% 预算 / 滑期 Y 月 / 里程碑 Z 未达」就强制评审砍范围、转向或停,把沉没成本谬误变成机械规则;③分阶段承诺——把 all-in 拆成几个 gate,每个只承诺到下一 gate、用新信息重定价,本质是实物期权:花小钱买「继续或退出」的权利。
# reference-class forecasting + kill line (pseudo-code)
def plan_with_tail(ref_class, base_estimate):
dist = load_reference_class(ref_class) # outside view: peer distribution
uplift = quantile(dist, 0.80) # P80, not the mean
budget = base_estimate * (1 + uplift) # tail-sized reserve
kill_line = { # pre-declared mechanical stop
"spend": 0.90 * budget, # burn 90% -> forced review
"slip_mo": 3, # slip > 3 months -> trigger
"milestone": "M2 missed by month 9",
}
return staged_commit(budget, gates=[3, 6, 9], kill_line=kill_line)
# each gate re-priced on latest burn; commit only to next gate — option, not all-in
原理:CHAOS 1994 说 IT 项目只有 16.2% 成功;Flyvbjerg 说只有 约 0.5%「完整交付」(on time + on budget + 拿到收益)。听着像行业崩了——但这两个数字的低,很大程度是成功定义造出来的:它们是连乘(conjunctive)门——准时且不超预算且功能全且拿到收益,全中才算成功。若每维独立达标率 80%,四维连乘只剩 0.8⁴ ≈ 41%;维度越多越苛,「成功率」机械趋零,哪怕每维都还行。这与 Day 51 同构:报告级 vs 判定级口径——你测「全维度完美率」,却当「项目失败率」去吓自己或做决策。
关键:报「成功率」必须声明成功定义。16.2%、0.5% 不是「多数项目一无是处」,而是「完美完整交付很稀有」——不同命题,混用即陷阱。
# how a conjunctive gate mechanically deflates "success rate"
dims = {"on_time":0.8, "on_budget":0.75, "full_scope":0.85, "benefits":0.7}
conjunctive = prod(dims.values()) # ~= 0.36 -- "all-hit" rate
# but 0.36 != "only 36% aren't failures": most are challenged (partial), not impaired (dead)
# decide on: impaired vs challenged vs perfect rate — don't collapse into one number
原理:项目风险和系统容量是同一道题。容量规划里你不按均值 QPS/延迟供容量——均值利用率 70% 的系统在流量尾部照样被打爆,因为负载和延迟都重尾;你按 P99/P999 供容量、留 headroom、设自动降级限流(Day 27/41)。项目风险是同一纪律换战场:不按均值超支立预算而按尾部分位立;不假设一路顺而预置止损和分阶段(= 系统的熔断和降级)。共同错误是「用均值代表分布」;共同解药是「盯尾部、留缓冲、备退路」。资深架构师对 P99 的直觉可直接迁移到项目、投资的肥尾判断上。
# same discipline: capacity vs project
# capacity: provision by the tail
capacity = p99_load * (1 + headroom) # not mean_load
autoscale_trigger = 0.80 * capacity # trip -> auto scale (≈ project kill review)
# project: budget by the tail
budget = p80_overrun_uplift * base # not mean_overrun
kill_review = 0.90 * budget # trip -> forced review (≈ system breaker)
# identical shape: size by tail + trip action + keep an exit
小样本估不准尾部形状,但仍能防御:
要点:小样本下机制(分阶段 + 止损)比精确估计更保命——预测不了尾部,但能限制它的伤害。
止损失效的根因是沉没成本谬误 + 决策者利益绑定,要靠机制不靠意志:
与系统熔断器一样:有效不因意志坚定,而因它自动断、需显式动作才重合。止损也要「机械触发 + 显式覆盖」。
分散只在尾部不相关时有效;一旦尾部相关,多个项目同时爆,组合反而放大——2008 正是把相关违约当独立违约定价。
即 Day 51/52 的共享盲区:oracle 共享同一 bug,「相乘降误报」退化成不降。解药一致:显式打破共模依赖,别假设独立。
这是肥尾管理最难处——诚实的尾部预留在竞争立项时是劣势(Flyvbjerg 说的「战略性虚报」制度成因:谁报得低谁获批)。破法在改激励流程,不在算得更准:
核心:技术上对的尾部预留,要靠流程设计才能在组织政治里存活。
框架是把两边成本折到同一量纲比:尾部事件期望损失 vs 缓冲持有成本——本质是 newsvendor / 保险定价。
所以:可承受的尾部按边际成本=边际收益定;会让你出局的尾部不惜代价避开。关键系统 headroom 远超「成本最优」,买的是生存不是效率。