好解释:在答案出现之前,让判断经得起现实#
从 David Deutsch 的 hard-to-vary 出发,学习怎样提出、比较和修订解释,并在仍然不确定时,采取与证据相称的行动。
V20 · 课程式连续阅读版
本册讲清道理,并用三个完整案例演示;可以直接复制使用的工作卡、记录模板、主持脚本和决策备忘,见 好解释:工作手册-V20。
如何把这本书当成一门课#
这本书写给需要在答案出现之前作出判断的人:主持事故复盘的工程负责人,为增长数据争论的产品和运营团队,决定一条风控规则该不该上线的风险人员,以及任何要在会议上审查别人解释的人。书里的例子大多来自软件、增长和风控,因为这些领域反馈快、记录全,适合展示方法;另有几段历史和个人生活的例子,用来说明同样的结构在别处也成立。
第一次读,不必记住所有名词,先抓住两条线索。
一条是五个动作:定题、立敌、摊牌、试探、入账。它们构成一个可以重复的循环;和循环并行的是决策,每到一个决定的最晚时间,或者某种损失变得承受不起时,就做一次。这条线索回答“下一步做什么”。
另一条是环境,用两个问题判断:系统能封闭到什么程度;参与者会不会调整做法,是否针对我们。它回答“这一次能期待多强的解释,行动该偏向精确修复,还是偏向稳健、可撤回”。
| 学习方式 | 建议路径 | 学完应留下什么 |
|---|---|---|
| 第一次通读 | 第一至四章 → 第五至十章 → 任选一个完整案例 | 能用自己的话讲清 hard-to-vary,并判断一个问题更接近哪种环境 |
| 课程式学习 | 每次一章,先做章末练习再看参考思路,然后到工作手册做对应练习 | 一份用自己的真实问题写成的案例记录 |
| 团队共学 | 先读第四章,再分头读三个案例,最后一起读第十四章 | 一张“环境 × 解释做到哪一步 × 行动偏好”的对照表 |
| 遇到问题时查阅 | 从全书地图或术语表进入 | 一个明确的下一步 |
按课程学,可以用六周:
| 周 | 内容 | 本周练习 |
|---|---|---|
| 1 | 序、第一至三章 | 对最近听到的三个“因为”各做一次变体测试 |
| 2 | 第四、五章 | 给一个真实问题判断环境,并把它写成一个可以出错的问题 |
| 3 | 第六、七章 | 为自己最相信的解释写一个强敌,再写一张差异化预期表 |
| 4 | 第八至十章 | 为同一个问题写一张决策表、一个探针和一条账本记录 |
| 5 | 第十一至十三章 | 读案例时,每出现一条新观察,先自己更新判断,再往下读 |
| 6 | 第十四、十五章与结语 | 结课任务:完成一份完整的案例记录(见工作手册第九部分) |
第一至十章的结构相同:开头说明本章要回答什么、读完应能做什么;结尾是本章要点和一道练习。练习的参考思路默认折叠,先自己写,再展开对照。参考思路只是一种写法,不是标准答案;拿它来检查的是,你的答案有没有给判断增加新的约束。
书里的英文词和术语,只在它能压缩一个已经弄懂的问题时才有用。读到一个词,如果说不出它会改变哪项观察、哪条判断或哪个动作,就回到例子里去,不要去背定义。
序:事故中最危险的一句话#
09:57,一项新功能从 5% 灰度放到全量,也就是从只对 5% 的用户开放,改为对所有用户开放。五分钟后,结账接口的中位延迟只从 230 毫秒升到 260 毫秒,最慢 1% 的请求却从 1.25 秒拖到将近 12 秒。值班负责人在 10:09 关闭了新功能,七分钟后延迟恢复正常。
复盘会上有人说:“已经很清楚了,新功能就是根因。”
这句话听上去合理,大概率也没有说错。问题在于,它把三个判断压成了一个:新功能参与了这次事故;我们知道它通过哪条链路造成了事故;我们知道改哪里,系统就能安全地恢复全量。
关掉功能以后延迟恢复,足以支持第一个判断,却支持不了后两个。新功能可能让缓存键的数量突然膨胀,可能把某个连接池打满,也可能只是在当天秒杀带来的流量上又加了一份负载。这几条机制可以同时成立,“关掉就好了”这一项观察,没法把它们分开。第十一章会完整地走一遍这场事故,这里先说它暴露的两种常见误判。
第一种,是把一项有限的证据扩写成一个完整的故事。第二种,是把解释、证据、决策和权限混在一起:谁的解释讲得最完整,谁就拿到了下一步的行动权;没有人再问这个解释得到了什么证据的支持,也没有人问行动的规模有没有超出证据覆盖的范围。
这本书讨论的,就是怎样把这几样东西重新分开。
我们从 David Deutsch 所说的 hard-to-vary 开始:一个好解释,在继续解释它要解释的东西时,很难被任意改写。然后往前再走三步:怎样让竞争解释真正构成竞争;怎样判断一项证据究竟区分了什么;以及怎样在仍然不确定的时候,采取与风险相称的行动。
这套做法不保证你得到正确的答案。它做的是纠错:让错误有机会暴露;新证据出现时,清楚该改判断的哪一部分;行动的规模,不超过我们已经知道的东西。
医疗、法律、金融、员工权益、隐私、安全调查和生产事故,都有各自的专业标准、授权链和应急程序。出现即时危险时,先止损、升级并保全证据;涉及人或生产系统的干预,先取得相应的授权。本书帮助你审查假设,不替代专业判断、合规要求或事故指挥权。
全书地图:五个动作,一条决策线,两个环境问题#
这本书最后只要求你记住五个动作。
| 动作 | 它防止什么 | 它留下什么 |
|---|---|---|
| 定题 | 讨论中途换题,把不同的现象混成一个问题 | 一个写清对象、时间、对照、形态和适用范围的解释对象 |
| 立敌 | 只给自己的解释补证据,给对手只留一句口号 | 至少一个和主解释同样具体、一旦成立会改变下一步的竞争解释 |
| 摊牌 | 只罗列双方都能解释的事实 | 每个解释对方向、时序、边界和中间过程的不同要求 |
| 试探 | 用大项目冒充学习,让解释避开现实的检验 | 一个安全、有限、能减少关键不确定性的观察或动作 |
| 入账 | 结果出来后改写记忆,把所有结局都说成早有预料 | 事前判断、实际结果、局部更新、有效期和下一次复核的时间 |
五个动作连起来是一句话:先把题目写清楚、固定下来,再给自己的解释找一个强敌;让双方对现实作出不同的预期,用最小的代价获得反馈,最后把结果写回原来的判断。入账以后,回到立敌或定题,开始下一轮。
它们不必严格按顺序走,新证据可能迫使我们重新定题。它们的用处在于:每当判断发生变化,我们知道自己改的是问题、解释、证据、行动,还是权限。
这个顺序有更早的来源。T. C. Chamberlin 在 1890 年主张同时保留几个工作假设;John Platt 在 1964 年把进展快的科学研究概括为一个循环:列出几个备选假设,设计一个结果能排除其中一部分假设的实验,拿到明确的结果,再在剩下的假设上重复。Kepner 和 Tregoe 在 1965 年写给管理者的问题分析,要求先用“是”和“不是”的对照写清问题,和本书的定题相近。本书在这些方法之上补了两样东西:几个解释还分不出胜负时怎样行动;环境不同时,每一步能做到什么程度。
和五个动作并行的,是一条决策线。决策不占五个动作里的固定位置,它在两种时候发生:一个决定到了最晚时间;或者某种损失变得承受不起。每次决策,都用当时手上的判断,在三类动作之间选择:在几种解释下都合理的稳健动作,用来减少关键不确定性的信息动作,以及代价高、难撤回的承诺动作。第一次决策可能发生在定题之前:序里的值班负责人,在弄清机制之前就关掉了功能。一个问题也常常同时有几个时限不同的决定:第十二章的获客预算三周后就要定,协作引导的试验要将近四个月才出结果。决策选中了信息动作以后,由试探把它设计成一个具体的探针。第八章专门讲决策。
五个动作通常从一个已经出现的现象开始。有些决定前面没有现象可解释,例如要不要进入一个新市场。这时从这个决定依赖的判断开始:把它写成一句能在某个日期被证明是错的话,再按同样的五步走。第五章末尾有一个例子。
环境决定五个动作要做到什么程度。判断环境,分开问两个问题:
- 系统能封闭到什么程度? 边界能不能暂时固定,关键的状态能看到多少,能不能重放,或者近似地重建“如果当时不这样”。
- 参与者会不会调整做法? 基本不会;会适应,例如用户、客户和员工对变化作出反应;或者会针对我们调整,例如攻击者研究规则以后绕开它。
两个回答组合起来,常见的有四种环境:
| 环境 | 两个问题的回答 | 合理的解释目标 | 常见的行动偏好 |
|---|---|---|---|
| 相对可封闭 | 系统基本能封闭;参与者基本不调整 | 尽量重建这一次结果的具体生成路径 | 针对已经找到的机制修复,配套回归测试 |
| 开放适应 | 系统难以封闭;参与者会适应 | 在写明的范围内,找到一条经得起多种检验的机制 | 在几种解释下都合理的动作;可撤回、分阶段,并定期复核 |
| 对抗适应 | 系统难以封闭;有参与者针对我们调整 | 找到对手绕不开、或者改起来代价很高的约束 | 分层防御,缩短反馈,给规则标版本,同时控制对正常用户的误伤 |
| 混合 | 系统的部分能封闭;参与者的部分不能,他们会适应,或者在针对我们调整 | 分开写:系统内部的路径追求完整,参与者的做法只求机制获得支持 | 系统内部精确修复,外部稳健控制;规则标版本,定期复核 |
表格填满,不等于解释变好了。检验这五个动作有没有起作用,只看一件事:不利的信息出现以后,有没有地方让它改变判断、动作或权限。
三个贯穿全书的例子#
后面的章节会反复回到三个虚构案例。这里先交代现象,分析留到后面。
尾延迟事故。 就是序里那场事故。一家电商平台在结账页新增“预计送达日期”,由配送时效服务计算;这个服务在缓存没有命中时,要通过一个连接池去调用承运商的网关。功能从 5% 灰度放到全量后五分钟,结账接口的中位延迟几乎没变,最慢 1% 的请求却拖到将近 12 秒。关闭功能后延迟恢复。团队要回答:这个功能通过哪条链路造成了事故,要什么证据才能让它重新上线。第十一章完整展开。
注册与付费。 一家做项目任务看板的协作软件公司,把网站主入口从“预约演示”改成“免费开始使用”,价格、功能和销售政策都没动。十六周后,每周新注册从约 1,000 个涨到 1,650 个,注册后四十二天内完成首次付款的比例却从约 10% 降到 5%。增长、产品和销售三位负责人各有一套解释,而下季度的获客预算三周后就要定。第十二章完整展开。
协同欺诈。 一家数字商品平台连续十二天出现异常损失,未经授权交易造成的损失约为平时的三倍;可是单看每一笔交易、每一个账户,都很少有明显的异常。第十三章完整展开。
三个案例依次对应三种环境:事故发生在相对可封闭的系统里;增长问题处在开放的市场中;欺诈案例是混合的环境,既有可以检查的交易系统,也有针对规则调整做法的对手。读到第四部之前,只要记住三个现象的形态:中位数稳定、尾部暴涨;注册上涨、付费率下降;每个局部都正常,整体却在亏钱。
第一部 先看清“解释”在做什么#
第一章 讲通已经发生的事,还不够#
为什么“能把已经发生的结果讲通”还不够?
读完应能:
- 区分一个会随结果改变的故事,和一个受机制约束的解释;
- 用替换细节的办法,判断某个细节是否真的在起作用。
想象一个从没学过天文学的人,第一次看到太阳在白天慢慢变暗。有人告诉他,这是天狗在吞食太阳;另一个人说,有一个天体正从太阳前面经过,挡住了阳光。
只看眼前这一幕,两种说法都讲得通:太阳暗了,后来又亮了。两者的差别,要等新的事实出现时才看得出来。
天狗的故事几乎可以随意改。日食持续得久,是天狗胃口大;持续得短,是锣鼓把它吓跑了;有的地方看得到、有的地方看不到,是它只飞过某些地方。每多一个事实,故事都能补上一句,而故事的核心不用付出任何代价。吞食太阳的角色本身也能随意替换:中国民间说是天狗,印度神话说是被斩首的魔神罗睺,朝鲜半岛的传说说是火狗。换掉吞食者,故事“解释”日食的能力一点也没有减少。所以它没有解释任何东西:它的细节和现象之间没有联系,怎么换都行。
遮挡的解释不一样。只要认真接受“有一个天体从太阳前面经过”,就必须同时接受一组彼此牵连的约束:遮挡有方向和边界;不同地点看到的程度不同;开始和结束的先后顺序,要和那个天体的运动一致;影子的形状也不能随便变。改动其中一个关键细节,其他预期会跟着变;把挡住太阳的天体换成别的东西,就得重新交代它的大小、距离和轨道。
Deutsch 在《The Beginning of Infinity》(中译本《无穷的开始》)里,把这种差别概括为 hard-to-vary,可以译成“难以任意改动”。按他的说法,好解释是这样一种解释:它在继续解释它声称要解释的东西时,很难被改动。他用的例子是四季。古希腊人说,珀耳塞福涅每年有几个月要回到冥界,她的母亲、农业女神得墨忒耳因此悲伤,大地就进入冬天;把悲伤换成愤怒,或者换一位神、换一个情节,故事照样讲得通。地轴倾斜的解释却改不动:倾斜的角度、地球绕太阳的轨道、阳光照射的角度彼此牵连,换掉任何一环,就解释不了四季。
“难以任意改动”不等于“绝对不能改”。解释可以改,但要付代价:关键细节一变,解释要么失去原来的能力,要么背上新的、可以被批评的后果。
软件系统里也有同样的差别。
“接口变慢,是因为数据库有问题”,很容易变。把“数据库”换成“网络”“缓存”“锁竞争”或“代码质量”,这句话的作用几乎不受影响。它只是给现象换了个名字。
“新版本让缓存键的数量暴涨,没有命中缓存的请求进入共享的连接池排队,所以主要拖慢了尾部,而不是中位数”,就承担了多得多的约束。它预期缓存命中率会下降,连接等待会集中在没有命中的请求上,尾延迟会比中位数恶化得多。如果这些现象都没有出现,这条解释就要付出代价。第十一章会看到,这条解释里几乎每一个数字,都能用另一项独立的观察来核对。那就是“难以任意改动”在工程里的样子。
好解释不一定长,也不一定复杂。复杂的叙事同样可以塞满随意的细节,简短的解释也可能受到很强的约束。要看的是:句子里的每个细节有没有在起作用,它们是不是因为问题本身,才必须出现在那里。
上图左栏的每个部件都和相邻的部件咬合,换掉任何一个,整条解释都要重新交代。中栏是同一类结构遇到一项对不上的事实:部件彼此牵连,所以不能只把出错的那一个悄悄换掉,整条解释都要重新接受检查。现实能纠正它,正是因为它改不动。右栏的名词彼此不牵连,换掉哪个都没有损失,现实也就无从纠正它。
四个承重问题#
审查一个解释时,可以先问四件事。
它究竟在解释什么? 同一句话如果能同时“解释”增长下降、组织冲突和产品失败,多半还没有对准具体的问题。
哪些细节在承重? 换掉其中一个部件,其他结论会不会跟着变?如果任何名词都可以换,那个名词只是装饰。
这些细节从哪里来? 它们来自已有的知识、明确的机制或事前的记录,还是结果出来以后临时补上的?补丁不一定错,但每个补丁都应该写下修改的理由,以及它带来的新后果。
这个解释还预期了什么? 除了已经知道的结果,它对时间顺序、人群差异、边界条件、中间过程或反例有什么要求?一个只会复述结果的故事,很难被现实纠正。
这四个问题不是评分表。它们的用处,是把“听起来顺”变成“哪里可能错”。第三章会把第二个问题展开成一个在会议上就能做的测试。
随意的自由度#
好解释不一定最短,变量也不一定最少。“时代变了”“市场就是有周期”“人性如此”都很短,却几乎允许任何结果。它们的问题不在字数,而在说话的人保留了太多随意的自由度:结果无论怎样,都能临时挑一个说法把它解释过去。
反过来,一个包含很多变量的模型,也可能受到很强的约束。只要每个变量都有明确的角色、独立的来源、适用的边界和反事实的后果,它就不是一个可以随意调整的参数。
所以,奥卡姆剃刀在这里更准确的说法是:不要为了解释已经发生的结果,保留不受问题约束的自由度。“参数越少越好”只是它的粗略版本。
好解释有时还有 Deutsch 所说的 reach,可以译成“延伸力”:它原本为一个问题而提出,却不加改动就能解释别的问题。地轴倾斜的解释原本只为说明四季,却顺带说明了南北半球的季节为什么正好相反,热带为什么没有明显的四季,极地的夏天为什么会有午夜的太阳。提出它的人未必知道这三件事。判断一个解释有没有延伸力,要看它是否“不加改动”就能解释新问题:如果每换一个场景都要补一条新的假设,那只是把同一句口号用到更多的地方。没有约束的“普适”,通常只是模糊。
本章要点#
- 能讲通已经发生的结果,还不能说明一个解释好;要看它的关键细节能不能被免费替换。
- 判断解释的好坏,要看每个细节是否受问题约束;长短和复杂度说明不了什么。
- 一个解释如果不对新事实作出额外的预期,现实就很难纠正它。
“这个季度大客户的续约率下降,是因为宏观经济不好。”
- 把“宏观经济不好”换成两个不同的原因,比如“主要竞品降价”和“负责这批客户的客户经理离职”。已知事实里,有没有哪一项因此解释得更差?
- 为原解释补写一项它必须承担、而替代解释不容易承担的预期。
参考思路
如果手上只有“续约率下降”这一个数字,三种说法都讲得通,“宏观经济”这个词暂时只是装饰。要让它承重,得让它说出别的解释不会说的话。
- 宏观经济:下降集中在受经济下行影响大的行业;客户更多是减少席位、降低档位,而不是整体流失。
- 竞品降价:流失的客户在续约前拿到过竞品的报价;对价格敏感的小客户先走。
- 客户经理离职:下降集中在那几位经理负责的客户,而且和行业无关。
写完这三条,下一步去查什么就清楚了:按行业、客户规模和负责的客户经理,把续约结果分别拆开看。
第二章 hard-to-vary 只是第一道检查:解释、证据和行动要分开判断#
一个结构严密的解释,为什么仍然可能是错的?一个还不完整的解释,为什么有时仍然要求我们马上行动?
读完应能:
- 把解释的质量、证据的支持、行动的选择和执行的权限分开;
- 避免把“证据增加了”扩写成“机制已经找到”,或者“应该马上全量执行”。
回到序里的事故。关掉功能以后延迟恢复,说明新功能参与了事故,这是证据改变了判断。它仍然没有告诉我们,问题出在缓存键、连接池、重试还是总流量,这是解释还不完整。客户正在受影响,我们仍然有理由先把功能关掉,这是行动已经必要。
三句话可以同时成立:证据增加了,解释仍不完整,行动却不能等到完全理解之后。
一个结构严密的解释,仍然可能是错的。测量可能失真,我们可能漏掉了第三种解释,甚至整个问题都可能写错了。所以,hard-to-vary 只是第一道检查:它先排除那些无论发生什么都能圆回来的故事,却不能代替证据、证明或专业的方法。第五章的 N 射线是一个例子:一位受尊重的物理学家给出了细节精确、看起来很难随意改动的说法,它却错在测量上。
最容易发生的混淆,是把三件事当成一件事。
第一件是解释的质量:一个说法是否对准了它要解决的问题,关键细节是否受到约束。
第二件是证据的支持:现有的材料在什么假设下,增加或减少了我们对某条主张的信心。
第三件是行动的选择:考虑收益、损失、时机、能否撤回和谁有权决定,我们现在该做什么。
一个解释可以很好,却还没有足够的证据;一项试验可以有力地说明某个动作在特定条件下有效,却解释不了历史上的问题为什么发生;一个解释即使很可能是对的,也未必值得马上采取无法撤回的行动。
三层之上还有第四层:谁有权执行、停止、升级,谁负责保存记录。它不属于任何一种思想传统,却决定前三层能不能真正运转。
| 层次 | 核心问题 | 常见错误 |
|---|---|---|
| 解释 | 为什么会这样?哪些细节不能随意替换? | 把标签当机制,把完整的故事当真相 |
| 证据 | 这项观察更支持哪条主张?支持到什么范围? | 按文件数量投票,把相关当因果 |
| 决策 | 在当前的不确定性下,哪种动作的代价和收益更合适? | 把“更可信”直接翻译成“全量执行” |
| 治理 | 谁能执行、停止、升级和保存记录? | 让同一个人同时掌控证据、解释和停止权 |
本书后面的结构都建立在这张表上。第五至七章主要处理解释和证据,第八、九章处理决策,第十章和第五部处理治理。每一次讨论,都值得先问一句:我们现在改的是哪一层?
延伸:这几层借用了哪些思想传统
前三层可以借三种不同的思想传统来理解。Deutsch 和 Popper 强调批评与纠错:知识不因为来源权威就免于检验,而是在问题、猜想和批评中改进。贝叶斯式的证据观提醒我们,一项证据有多大的区分力,取决于不同的解释原本对它的预期差多少。决策理论和实物期权则说明,即使判断相同,行动也会因为损失不对称、反馈快慢和撤回的成本而不同。
这三种传统不是一套统一的理论。Deutsch 式的可错论认为,知识始终是猜想,只能通过批评来改进,不能被证据“证实”到某个程度;贝叶斯式的知识观则认为,一个主张的可信度可以随着证据的累积逐步提高。在比较手上几个具体解释的时候,两者的要求大体一致:一个什么结果都能容纳的解释,对每种结果的预期都差不多,任何观察都拉不开它和对手的距离;事先给出具体预言的解释,才可能在预言应验时胜出(见书末的技术旁注)。两者的分歧在于,能不能给一个解释本身打出“有几成是真的”的概率。本书的做法是分层使用:hard-to-vary 用来提出和批评解释,预期的差异用来判断一项观察的区分力,把握的数字只用来比较候选和选择行动,决策理论用来约束行动。这种组合是本书在实践上的扩展,不应被读成 Deutsch 本人的完整方法。
还有三组常被混用的概念,值得分开。
解释不等于预测。 一个黑箱模型可以准确地预测谁会流失,却没有告诉我们为什么流失。反过来,一个机制解释也可能暂时给不出精确的数值。预测看输出准不准;解释看结构是否对准了问题。两者有交集,但不能互相代替。
解释不等于因果识别。 因果识别,是用设计或假设,把一条因果关系和其他可能的解释分开。“协作引导能提高某类账户的付款率”,回答的是一次具体干预的局部效果;“历史付款率下降,是因为协作路径恶化了”,回答的是过去发生了什么。前者即使有随机试验支持,也不自动证明后者。第十二章会展示这个差别怎样决定一次试验能支持多大的行动。
解释不等于决策。 解释再好,也只能缩小不确定性,不能决定组织愿意承担多大的损失、谁有权承担,或者机会是不是马上就要错过。行动还要经过风险、价值和权限这三道检查。
本章要点#
- hard-to-vary 用来提出和批评解释,它本身不是证明。
- 解释、证据、决策和治理回答不同的问题,不能互相代替。
- 行动可以先于完整的理解,但行动的范围,要受风险、可撤回性和权限的约束。
一家为小商户提供短期融资的公司,上线了一条自动审批规则。两周后,人工审核量下降了 40%,坏账率暂时没有变化。产品负责人提议把规则推广到所有商户。
- 把这件事写成四句话:解释判断、证据判断、行动判断、权限判断。
- 检查这四句话里,有没有哪一句偷偷借用了另一层还不成立的结论。
参考思路
- 解释:人工审核量下降,是因为规则把一部分申请直接放行了。这一点是清楚的,但它只说明规则在做什么,没有说明放行得对不对。
- 证据:坏账通常要几十天甚至几个月才会显现,两周“没有变化”几乎不含信息,既不能说明规则安全,也不能说明它危险。
- 行动:可以在当前范围内继续运行,同时设好坏账的早期信号(例如首期还款逾期)和停止条件;推广到所有商户是一个承诺动作,证据还不够。
- 权限:指标越界时,谁有权停掉规则?如果这个人就是提议推广的产品负责人,停止权应当交给风险团队。
最常见的偷换,是把第二句里的“暂时没变”当成“已经证明安全”,再直接推出第三句里的“全量推广”。
第三章 墙纸、承重件与工作解释#
怎样从一个“听起来像原因”的说法里,找出真正承重的部分,并把它改写成可以比较的工作解释?
读完应能:
- 对一个解释做部件、角色、时序和边界四种替换;
- 写出包含解释对象、结构、适用边界、可区分的后果和修订代价的工作解释。
hard-to-vary 最直接的用法,是做一次变体测试:解释的对象不变,替换解释里的一个部件,看看原来的解释会损失什么。
假设有人说:
激活率下降,是因为新用户主要是 Z 世代,他们没有耐心看完引导流程。
把“Z 世代没有耐心”换成“移动端的排版错乱”,故事仍然成立;再换成“引导文案的语言和用户不匹配”,还是能解释中途流失。三个完全不同的机制,都和同一项观察相容。
这时承重的,是一个位置上的事实:流失集中在引导流程的第三步,也就是要求用户授权访问日历、而用户还没有看到任何价值的那一步。“Z 世代没有耐心”只是贴在这个事实上的墙纸。
揭开墙纸以后,分析并没有结束。它提示我们:现有证据的分辨率不够。下一步该去看不同的设备、语言、年龄和页面位置上,流失分别是什么样子,不必继续争论年轻人有没有耐心。好的变体测试,会把讨论从“用哪个词”推向“去看什么新的观察”。
测试可以写得很朴素:
| 原来的部件 | 替换为 | 哪项已知事实因此解释得更差 | 判断 |
|---|---|---|---|
| Z 世代没有耐心 | 移动端的排版错乱 | 暂时没有 | 原部件不承重 |
| 授权发生在看到价值之前 | 授权发生在看到价值之后 | 解释不了流失为什么集中在第三步 | 原来的时序承重 |
判断主要看第三列。“解释力下降”不能只是一种感觉,必须指出替换后的版本在哪项现象上对不上。写不出对不上的地方,原来的部件就还没有证明自己应该在那里。
结论可以写成下面两种句子之一,而不是“换掉以后感觉不对”:
- 承重: 换掉 X 以后,事实 Y 就解释不了,所以 X 在当前的解释里起作用。
- 不承重: 换掉 X 以后,已知的事实都一样容易解释,所以 X 暂时只是墙纸。
变体测试不能马上证明某个机制。它能做的,是找出哪些词值得继续查,哪些词只是给未知的东西贴了一个标签。
复合解释也要接受替换#
现实中的问题,常常不止一个原因。“渠道、定位、销售和定价都有影响”,听起来成熟,却可能只是把更多名词堆在一起。复合解释除了逐个部件做变体测试,还要经受另外三种替换:
- 角色替换:这个因素是原因、中介、症状,还是放大器?
- 时序替换:它发生在结果之前,还是结果出现以后的反馈?
- 边界替换:换一个人群、负载、版本或环境,这个机制还成立吗?
复合解释不会因为包含的因素更多,就自动比简单的解释好。它必须比另一个同样认真的复合解释承担更多的约束;否则,“复杂”只会让随意的部分更难被发现。
从变体测试到工作解释#
现实问题很少一开始就有完整的理论。团队手上通常是一个工作解释:它足够具体,可以被批评和比较;又足够暂时,允许在新材料出现后重写。
一个成熟的工作解释,通常包含五个部分。
第一是解释对象:这一次要解释的,是哪一个现象、差异、规律或异常。
第二是结构。在因果问题里,它可能是一条机制链;在数学问题里,是前提和推导;在历史问题里,是当时能得到的信息、行动者的意图和各个来源之间的关系;在系统问题里,可能是激励、反馈和均衡。
第三是适用边界:这个解释针对哪些人群、时间、负载、版本和环境。没有边界的解释,往往只是还没有发现自己会在哪里失败。
第四是可区分的后果。它不一定是实验结果。数学解释可以接受反例的检验;历史解释要求和同期的材料、时间顺序相容;系统解释可以给出“参数改变以后,均衡往哪个方向移动”“受到扰动以后,系统会回到原状、停在新的状态,还是继续偏离”这样的后果。共同点是:关键的主张必须作出某种可以被批评的承诺。
第五是修订代价:解释改变时,写清改了哪条假设、为什么改、哪些旧结论因此失效、新版本多承担了什么。解释可以进步,但每一次改动都要留下记录。
“让解释可以输”是一句有用、但不够准确的话。现实中,输掉的通常是某一条因果关系、某一个边界假设或某一个幅度判断,很少是整套世界观。好的记录允许局部更新,不必每次都在“完全正确”和“彻底推翻”之间来回摆动。
本章要点#
- 变体测试不证明机制,它找出哪些词值得继续查。
- 复合解释要说明每个因素的角色、时序和边界,不能用“都有影响”逃避比较。
- 工作解释可以修订,但每次修订都要写明哪些旧结论失效。
“新版定价页的转化率下降,是因为价格锚点设错了:我们把最贵的方案挪到了最右边。”
- 分别做部件、角色、时序和边界替换,每一种都写出“哪项事实会因此解释得更差”。
- 把它压缩成五行:对象、结构、边界、可区分的后果、什么结果会迫使修订。
参考思路
- 部件替换:把“锚点设错”换成“新页面在手机上首屏看不到价格”。如果下降只出现在电脑端,替换后的版本解释得更差,锚点暂时保住;如果两端一起下降,两种说法都还站得住,需要更细的观察。
- 角色替换:锚点也可能只是放大器,原因是同期涨了价,而新的排列让涨价显得更刺眼。
- 时序替换:如果转化在新页面上线前一周就开始下降,锚点就不可能是起因。
- 边界替换:锚点效应对第一次看到价格的新访客应当更强,对续费的老用户几乎没有影响。
五行版本示例:
- 对象:新页面上线后两周,电脑端新访客从“定价页”到“开始试用”的转化,从 8% 降到 6%。
- 结构:最贵的方案挪到右侧以后,访客拿中间方案去和它比较的次数变少,更多人直接离开。
- 边界:新访客、电脑端、当前的价格。
- 可区分的后果:中间方案的点击占比下降;老用户的续费不受影响。
- 修订条件:如果只把最贵的方案挪回原位、其他都不变,转化没有回升,这个解释就要修订。
第二部 世界怎样限制解释#
第四章 环境决定解释能做到哪一步#
为什么软件调试中的解释常常能做到“重建完整的路径”,而商业、组织和欺诈问题更常只能得到有边界的机制判断?
读完应能:
- 用两个问题判断环境:系统能封闭到什么程度;参与者会不会调整做法,是否针对我们;
- 为不同的环境选择合理的解释目标,并说明为什么不是另外两种。
读完前三章,也许会有一种感觉:只要把解释写得足够具体,再不断做变体测试,最后总能像调试程序一样,找到那个承重的机制。
在软件工程里,这个期待常常是合理的。代码、配置、日志、调用链和版本记录,让我们有机会追查一个结果是怎样一步步产生的。可一旦问题进入商业、组织、市场、医疗、公共政策或欺诈调查,解释好像就开始失去边界:用户的意图读不到,竞争对手会改策略,政策会改变进入样本的人,今天成立的关系,明天也可能被环境改写。
这个差别是真的,但它不能简单理解为“软件的世界有限,物理的世界无限”。更有用的分界有两个:一是这个系统在多大程度上可以被封闭、观察和重复干预;二是系统里的参与者,会不会随着我们的观察和干预调整做法。
软件为什么是练习好解释的好地方#
软件系统并不简单:一个分布式系统的状态空间可以极大,网络和调度也可能带来难以复现的随机性。
软件的便利在认识上:它的生成机制大部分是人设计的,而且通常可以继续加装仪表来观察。
可以把一次运行的结果粗略地写成:
结果 = F(代码, 配置, 输入, 状态, 运行环境)
这不表示我们已经知道 F 的全部细节,也不表示相同的输入永远得到相同的结果。它只是说:结果背后有一套相对明确的状态转移结构,我们通常可以一步步接近它。有源代码和配置,可以查结果经过了哪些规则;有日志、链路追踪和性能剖析,可以把一部分隐藏的状态变成看得见的状态;可以重放请求、注入故障,主动制造能区分不同解释的证据;可以用功能开关、灰度和回滚,把干预限制在很小的范围里;还可以在相近的输入和版本下反复运行,逐步接近“如果当时不这样”的比较。
所以,软件调试里的解释常常能做到一种很强的形态,本书称为路径完整:给定这组输入、版本和状态,能说清结果经过了哪条执行路径,哪一个状态变化让后面的行为不同,以及改变其中一步时,哪些日志、队列、资源和输出应当随之改变。这样的解释,是一条能被日志、执行顺序和反事实共同约束的生成链。
分界不在软件和物理之间#
实验室里的物理实验,可能比生产中的软件更封闭。反过来,一个连着真实用户、第三方服务、市场流量、组织流程和攻击者的生产系统,也可能很快变成开放的系统。
所以更准确的区分,是两条连续的谱。下表前四行描述第一条,系统能封闭到什么程度;第五行描述第二条,参与者会不会适应:
| 维度 | 相对可封闭、可重复的系统 | 开放、会适应的系统 |
|---|---|---|
| 系统边界 | 主要的部件和接口大体可以列出 | 重要的原因可能不断从边界之外进来 |
| 生成机制 | 大量机制由设计产生,可以检查,或者继续加装仪表 | 只能观察到一部分,许多变量是理论上的构造 |
| 重复运行 | 可以重放、仿真或近似复现 | 历史情境通常无法完整重来 |
| 干预隔离 | 较容易限制范围、固定版本和回滚 | 干预会改变人群、激励和之后的环境 |
| 参与者 | 多数部件不会主动欺骗调查者 | 人、组织、市场或攻击者会学习和适应 |
| 解释目标 | 重建这一次结果的具体生成路径 | 在写明的范围内,找到能迁移到新情况的机制 |
“相对”两个字很重要。没有哪个现实的系统绝对封闭,也没有哪个开放的系统完全无法约束。一个单元测试可以非常接近封闭;一次跨区域的生产事故,可能同时受网络、供应商和用户重试的影响;一个商业问题整体上是开放的,却可以通过固定人群、时间窗口和流程,得到一小块相对稳定的环境;欺诈在两条谱上的位置不同:交易规则和决策路径可以检查,攻击者的资源、身份和策略却会主动变化。
判断的时候,分两组问。第一组问系统能封闭到什么程度:当前问题的边界有多稳定?关键的状态能看到多少?“如果当时不这样”能不能近似地重建?第二组只有一个问题:参与者会不会调整做法?如果会,还要分清他们只是在适应变化,还是在针对我们调整。两组分开回答。一个问题里,系统的部分和参与者的部分常常处在不同的位置,这就是混合的环境,要分开写目标。
下面是几个常见问题的大致位置。它们只是这一次任务的工作判断,不是永久的标签:
| 问题 | 边界能否固定 | 能否重放或受控比较 | 参与者会不会适应 | 大致位置 |
|---|---|---|---|---|
| 发布以后接口报错 | 大体能 | 能 | 基本不会 | 相对可封闭 |
| 调价以后新签客户数的变化 | 部分能 | 只能做局部试验 | 会(竞品会跟进,客户会等降价) | 开放适应 |
| 招聘一位高级经理是否成功 | 很难 | 几乎不能 | 会(本人和团队都会调整) | 开放适应,而且反馈很慢 |
| 与大客户的续约谈判 | 部分能 | 不能 | 会,而且会针对你的策略 | 对抗适应 |
| 盗刷与账户盗用 | 交易系统能,对手不能 | 可以回放历史交易 | 会主动绕开规则 | 混合:系统可封闭,对手在对抗 |
开放世界为什么能容纳更多故事#
开放世界里,变量更多只是一部分困难。更难处理的是,产生数据的机制本身会随时间和干预而改变。
在一个相对封闭的软件问题里,我们常把结果写成:
Y = F(代码, 配置, 输入, 状态)
在商业、组织或对抗的系统里,更接近现实的写法是:
Y_t = F_t(政策_t, 人群_t, 看不见的状态_t, 参与者的策略_t, 外部环境_t)
两个公式的主要区别,在于函数从 F 变成了 F_t:变化的不只是输入,产生结果的关系本身也可能在变。
价格变了以后,进入样本的人可能不一样了;指标成了绩效目标以后,员工会围着指标调整行为;推荐系统改变曝光以后,用户的偏好也会被它慢慢塑造;欺诈规则上线以后,攻击者不会保持原来的做法,好让我们继续验证。
所以,开放的系统同时有四种困难。
边界不完整。 我们不知道哪些变量该放进来。一次转化下降,可能同时和渠道、竞争对手、价格、销售响应、产品路径、季节和测量方式有关;我们列出的因素之外,总可能还有一个没识别出来的共同原因。
机制只能部分看见。 “信任下降”“购买意向降低”“团队动力变化”,不是一个可以直接读取的函数调用。它们通常要从行为、访谈、制度和结果中一起推断,而测量的方式本身,也可能依赖当前的解释。
反事实不能完整重来。 公司不能把同一个季度经历两遍,只在其中一次改价格;组织也不能把同一次冲突重演一遍,只换掉一个激励。即使做了随机试验,它通常也只说明某段时间、某类人群、某种执行方式下的局部效果。
系统会对观察和干预作出反应。 指标会改变行为,政策会改变选择,防御会改变攻击,公开的解释甚至会成为参与者下一步行动的依据。
结果是一种比“数据太少”更难处理的状态:几种机制可以长期和现有的事实相容,而且每一种都能在新事实出现以后继续加条件。如果这时仍然要求一次调查给出整个世界唯一的故事,结果往往并不更严格,反而让解释得到了更多事后调整的余地。
开放世界里,hard-to-vary 要求什么#
开放世界不会让 hard-to-vary 失效。它改变的是:我们要求哪一部分不能随意改动。
在软件调试中,我们常常要求一条具体的生成路径,经得起链路追踪、执行顺序和故障注入的检验。在开放世界里,更现实的要求是:机制、适用范围、预期会看到的现象,以及什么情况下解释失效,这四者之间的关系,不能在看到结果以后被免费改写。
可以用一个完整的句式来写:
在人群 P、时间窗口 T、制度与环境 R 下,机制 M 通过过程 K 产生现象 Y,并且应当观察到 S。一旦出现条件 C,这个解释必须重新评估。
本书把这称为有条件的 hard-to-vary。开放世界里的解释可以带条件,但条件不能在结果出来以后免费增加。一个边界要进入解释,至少要回答四个问题:它能不能被独立地识别?为什么在结果出来之前,就有理由认为它重要?它预期解释在哪里成立、在哪里不成立?它能不能约束下一批案例,而不只是保护上一轮的故事?
例如,“用户质量变差,导致转化下降”很容易变。任何下降都可以被重新命名为“质量下降”,而“质量”本身又可以在事后由结果来定义。
更受约束的版本是:
六月,在美国中小企业的付费搜索流量中,广告扩量改变了带来访问的搜索词,商业意向低的访问增加了。这个机制预期,下降首先出现在资格确认之前,而不是报价之后;恢复原来的否定关键词(让广告不在某些搜索词下展示的设置)以后,低意向访问的占比应该先下降,之后预约率才可能改善。这个判断不外推到大企业客户、自然流量或之后的定价版本。
它仍然没有解释整个市场,却已经不能随意移动了:人群不能在结果出来以后换成另一批;时间窗口不能为了保住结论而随意平移;机制发生的位置,不能从资格确认之前悄悄挪到报价之后;干预以后变化的先后顺序,不能随意颠倒;大企业客户和自然流量,不能在成功时算进来、失败时又被排除。
解释做到了哪一步,证据够不够支持这个动作#
不同的环境,允许解释达到不同的分辨率。如果所有问题都用软件调用链的标准来衡量,很多商业解释会过早地被判为“只是故事”;如果因为现实复杂就放弃对机制的要求,又会让任何叙事都得到豁免。
更好的做法,是分开问两个问题。
第一个问题:这个解释做到了哪一步?
| 状态 | 已经做到什么 | 仍然不能声称什么 | 常见场景 |
|---|---|---|---|
| 路径完整 | 能重建这一次结果的主要生成路径,并指出改变哪一步会让结果不同 | 不代表所有背景条件都已穷尽,也不保证下一个版本仍然一样 | 代码、协议、算法、部分生产事故 |
| 机制获得支持 | 一条机制受到时序、中间过程、跨环境比较或多种独立证据的共同约束 | 不能扩写成全部的历史成因,或者所有人群的规律 | 产品、商业、组织、医疗、欺诈 |
| 仍是候选 | 解释足够具体,可以拿来比较,但还没有经过有区分力的检验 | 不能作为承诺动作的依据 | 调查刚开始的时候 |
第二个问题:现有的证据,够不够支持某一个具体的动作? 本书把“够”称为决策充分。它总是针对一个写明了范围的动作:同一组证据,可以足够支持 5% 的灰度,却不够支持全量上线;可以足够支持暂停一类交易,却不够支持把这些交易背后的用户都认定为欺诈者。决策充分描述的是行动的资格,不是真理的等级;机制还没有被唯一识别时,它也可以成立。
两个问题分开问,能防住两种常见的越界:把“某个局部机制得到了支持”扩写成“我们已经解释了全部的历史”;或者把“这个动作值得试”扩写成“支持这个动作的故事已经被证明”。
在开放世界里怎样工作#
我们没法把整个商业世界变成一个单元测试,但可以在开放世界里制造一些足以学习的局部封闭:暂时固定一组边界,让竞争解释必须在同一块现实上作出预期。局部封闭不是宣称其他因素不存在。
后面几章会分别展开开放世界里的具体做法:
- 缩小解释对象,固定人群、时间窗口、制度和分析单位(第五章);
- 寻找换了时间、人群或测量来源以后仍然保持的结构(第七章);
- 几种解释分不出胜负时,寻找在每一种解释下都合理的动作(第八章);
- 设计探针时,考虑探针本身会改变被观察的对象(第九章);
- 给解释标上版本、有效期和复核条件(第十章)。
还有一件事,要在这里说清楚:开放世界里最危险的假设之一,是以为候选清单已经穷尽了现实。一份诚实的工作结构,会明确给这些东西留出位置:
当前的主解释
竞争解释
可以并存的机制
测量问题
没有观测到的共同原因
制度或环境的变化
参与者的适应行为
还没有解释的现象(残差)
“还有未知的原因”,不能成为拒绝判断的借口,但它应当限制行动的规模。解释覆盖得越少,动作越应该可以撤回;反馈越慢,承诺越应该分阶段;可能的损失越无法挽回,越不能只依赖一个解释。
五个动作怎样随环境调整#
接下来的定题、立敌、摊牌、试探、入账,不要求所有领域达到同一种证明强度。在两类环境里,它们处理的是同一组逻辑问题,产出却不同。
| 五个动作 | 相对可封闭、可重复的系统 | 开放、会适应的系统 |
|---|---|---|
| 定题 | 固定版本、请求、输入、状态和时间线 | 固定人群、时间、制度、环境、分析单位和观察窗口 |
| 立敌 | 比较代码路径、配置错误、资源瓶颈和依赖故障 | 同时保留测量、选择、外部冲击、反馈和策略适应 |
| 摊牌 | 用链路追踪、执行顺序和资源变化区分机制 | 用方向、时序、分层、中间过程和跨环境的稳定性区分机制 |
| 试探 | 重放、故障注入、基准测试、灰度 | 小范围试点、负对照、自然变化、过程追踪、多来源核对 |
| 入账 | 记录故障链、修复、回归测试和剩余风险 | 记录有边界的机制判断、残差、有效期和复核条件 |
所以,这五个动作并不要求商业问题最后给出一条像程序调用链那样完整的路径。在相对封闭的系统里,它们帮助我们接近一条具体的生成路径;在开放的世界里,它们帮助我们建立一个有边界的机制判断,并让行动在还没分出胜负的几种解释下都站得住。
开放的程度高,也不等于只能小步慢走。它改变的是举证的要求:大的动作,需要写清最坏的情形、停止权和监控;实在不能等的时候,也要如实记下,我们是在控制风险,而不是已经唯一地识别了机制。
本章要点#
- 判断环境分两个问题:系统能封闭到什么程度(边界能否固定、状态能否看见、干预能否重复);参与者会不会调整做法,是否针对我们。两部分处在不同的位置时,是混合的环境,要分开写目标。
- 开放世界里的 hard-to-vary 是有条件的:机制、范围、预期的现象和失效条件,不能在事后免费改写。
- 分开问两个问题:解释做到了哪一步;证据够不够支持这一个具体的动作。
对下面三个问题,分别判断环境,并选择本轮合理的解释目标:
- 财务报表里,某个客户本月的收入数字突然翻倍;
- 公司推行每周两天远程办公以后,员工离职率的变化;
- 一条新的交易监控规则上线以后,可疑交易报告下降了 30%。
参考思路
- 相对可封闭。数据管道和计算逻辑可以重跑,目标是路径完整:找到是哪一步让数字翻倍(重复入账、汇率、口径变更),修好,并加上回归检查。
- 开放适应。离职率同时受招聘市场的冷热、其他公司的政策影响;政策本身还会改变谁来应聘、谁选择留下。合理的目标,是在限定的部门和时间里,让“远程办公降低了某类员工的离职”这条机制得到支持。例如,通勤时间长的员工,离职率应当下降得更多。在决策上,证据足以支持再试行半年、并设一个复核点,不足以支持把它写进长期制度。
- 混合,而且有对手。规则和交易记录可以检查、可以回放,这一部分能封闭;被监控的一方会换做法,这一部分不能。要先查测量:报告下降,可能是规则更准了,也可能是对方换了做法绕开了规则,还可能是规则改变了某类交易的定义。目标是先排除测量问题,再让“规则有效”得到支持。在决策上,只够支持“保留规则,并加一项独立的抽检”,不够支持“撤掉其他的监控”。
第三部 五个动作和决策:把解释放到现实里检验#
第五章 定题:先把问题写到能够出错#
怎样把“系统有问题”“增长不好”这类大词,改写成所有人都能一起检验的解释对象?
读完应能:
- 用对象、时间、对照、形态和适用范围,固定一个问题;
- 把解释问题、分解问题和决策问题分开写;
- 没有异常可解释时,把决定依赖的判断写成一句可以出错的话。
很多会议表面上在争论答案,参与者回答的却是不同的问题。有人在解释总体转化率为什么下降,有人在解释高意向的客户为什么流失,还有人在解释收入确认为什么变慢。三个人可能都有道理,但三个解释之间并没有形成竞争。
一个能用来工作的解释对象,至少要交代四件事:对象是什么,变化发生在什么时候,与什么基准相比,变化呈现出什么形态。
“增长不好”几乎没有约束。“四月初更换注册入口以后的十六周内,每周注册从约 1,000 个增加到 1,650 个;在相同的四十二天观察窗口中,首次付款率从约 10% 降到 5%。直接访问和老客户推荐带来的注册基本稳定,下降集中在广告带来的注册”,就已经是一份可以工作的描述。它仍然可能被修改,但大家至少暂时在解释同一件事。
哲学里,把需要被解释的现象称为 explanandum,本书叫它解释对象。只要记住一个问题:这一次,究竟是哪一个变化、差异、规律或异常,需要我们给出解释?
贯穿案例:尾延迟事故怎样定题#
序里那个坏问题是:“新功能是不是根因?”它把证据判断、机制解释和恢复决策塞进了一句话。更好的写法,是拆成三句:
| 类型 | 问题 |
|---|---|
| 解释问题 | 为什么功能全量以后,结账接口最慢 1% 的请求从 1.25 秒升到将近 12 秒,中位数却只从 230 毫秒升到 260 毫秒? |
| 分解问题 | 变慢的请求,主要集中在哪些调用链、缓存状态、资源池和请求类型上? |
| 决策问题 | 功能保持关闭时,需要什么证据、护栏和授权,才允许一级一级地恢复? |
这样写,把四件事都固定了:对象是尾延迟;时间是全量以后;对照是全量之前,以及没有受影响的请求;形态是尾部暴涨、中位数稳定。
把三类问题分开#
商业和工程的场景里,最好把三类问题分别写出来。
解释问题问:为什么会出现这个现象?
分解问题问:差异主要落在哪些人群、时间或环节?它通常帮助定位,但不会自动给出每个原因各占多少。
决策问题问:在现有的证据下,必须选择什么动作、多大的规模、什么时机?
三者混在一起时,分层的数据很容易被写成原因,局部的实验也容易被夸大成历史的解释。
如果决策问题不止一个,还要分别写出每个决策的最晚时间。第十二章里,获客预算三周后就要定,而一项像样的产品试验,从批准到出结果要将近四个月。两个决策挂在同一个问题下面,时间线却完全不同。
仪表和世界要分开#
任何异常,都至少有两类候选的解释:世界变了,或者我们观察世界的方式变了。
所以,在讨论机制之前,先检查口径、埋点、采样、账单、队列定义和数据延迟。因为测量一旦失真,后面再精细的推理,也只是在解释仪表。
仪表不只是软件里的埋点。观察的人本身,也可能是仪表的一部分。
二十世纪初,柏林有一匹叫汉斯的马,看起来会做算术:主人出题,它用蹄子敲出答案。1907 年,心理学家 Oskar Pfungst 没有先争论马有没有智力,而是设计了一个只回答一个问题的检验:马能不能看见提问的人。马看得见时,56 题答对 50 题;看不见时,35 题只答对 2 题。提问的人在马敲到正确的数字时,会不自觉地放松身体,马读的是这个信号。现象是真的,要解释的对象却选错了:该解释的不是马的算术能力,而是提问的人和马之间的信号。
N 射线是另一个例子,而且出错的是一位受尊重的物理学家。1903 年,法国南锡大学的 Blondlot 宣布发现了一种新射线,还测出了它穿过铝制棱镜时的折射,法国有不少研究者随后也报告看到了。1904 年,美国物理学家 Robert Wood 到他的实验室参观,在暗室里悄悄取走了关键的棱镜,Blondlot 仍然报告看到同样的谱线。
这两个例子,补上了后面几章容易给人的一个错觉。第七章的 Snow 和第九章的 Semmelweis,都是当时的少数派后来被证明正确的故事;只读这类故事,容易以为细节具体、又和主流对立的解释更可能对。Blondlot 的说法同样具体,错在测量上。检查仪表的一个好办法,是让观察的人不知道条件:马看不见提问的人,Blondlot 不知道棱镜已经被取走。
但查仪表,也不能成为无限推迟讨论机制的理由。合理的做法,是按角色区分手上的材料:
| 材料的角色 | 例子 | 主要审查什么 |
|---|---|---|
| 观测记录 | 日志、账单、访谈原话、事件时间线 | 是否完整,时间戳是否可靠,口径是否稳定 |
| 方法假设 | 队列定义、抽样方法、追踪覆盖率 | 假设不成立时,结果会怎样被扭曲 |
| 暂用的背景知识 | 本轮不争论、已经有多方约束的知识 | 来源、适用范围、在什么情况下失效 |
| 候选解释 | 流量意向下降、共享资源竞争 | 和竞争解释并列比较 |
背景知识不是永远正确的事实,也不必等所有人都同意才能使用。它只是在本轮推理中暂时承担的角色。有人质疑它时,应当指出它具体会怎样失效;争议解决不了,就在两套背景假设下分别推演,看结论会不会变。
先认清问题的类型#
不是所有解释都适合用同一种工具。因果问题关心干预的路径,需要时间顺序、混杂检查、过程追踪或受控的设计;统计和测量问题,需要口径审计、分层重算和选择偏差的检查;数学问题靠推导和反例;历史问题靠同期的材料、来源批判和时间顺序;系统问题要看激励、反馈和稳定性;预测问题要看留出的数据、校准和漂移。
工具要服从问题。要求所有问题都做实验,和要求所有问题都画因果图一样,都是形式主义。
开放世界里,定题还要固定适用范围#
对一条软件请求,我们通常固定版本、输入、状态和时间线。对商业、组织、市场和对抗的问题,还要暂时固定人群、制度、环境、分析单位和观察窗口。分析单位,是推理中被当作一个对象来观察的单位:一笔交易,一个账户,一个团队,或者一组相互关联的账户。第十三章会看到,分析单位选错了,每个局部都可能正常,整体的机制却看不见。
固定这些东西,是为了防止一个解释靠更换适用的对象活下来;边界之外的因素仍然存在。如果一个解释在失败以后,从“全部客户”缩到“某一类客户”,或者从“这个季度”挪到“另一个时间窗口”,记录里必须写明:新加的边界有什么独立的依据,哪些旧结论因此失效,它对下一批观察提出了什么新的要求。
缩小解释对象,本身就是一种局部封闭。不要一开始就解释“为什么公司增长变慢了”,而是先问:
为什么过去六周,美国中小企业的新注册用户,在完成第一个项目之后、邀请第二位成员之前的流失增加了,而大企业客户和老渠道基本稳定?
每增加一个事前就能识别的边界,解释能随意移动的空间就少一些。但边界不是免责条款。如果新加的边界只能解释已经发生的失败,却不能对以后的观察提出要求,它只是一个更精致的补丁。
好解释从哪里来#
审查解释,容易造成一种错觉:好像候选的解释已经摆在桌上,我们只需要挑出最好的一个。真实的工作通常乱得多。人最先遇到的,往往只是一种不对劲:某条曲线拐了,一个流程突然变慢,一位客户的反应和过去不一样,或者一条长期有效的经验不灵了。
好解释很少直接从大词里产生。它通常这样形成:
异常 → 现象的细节 → 候选机制 → 最小反事实 → 能被现实纠正的结构
从异常开始#
假设一家公司上线 AI 工单分流三周后,客服团队的待处理工单从约 1,200 件涨到 1,900 件。“AI 不可靠”“团队不适应新工具”“用户的问题变复杂了”,都可以立刻成为故事,但它们来得太快了。
先把异常拆开:是新工单变多了,还是结案变慢了?哪些类型在增长?首次响应是不是更快了,最终解决却更慢了?被重新打开的工单,是不是集中在退款、权限或账单问题上?人工升级是在分流之前就增加了,还是在机器给出错误的回复之后才增加的?
形态一清楚,机制才开始出现:
- 分类错误,把复杂的工单送进了普通队列;
- 队列的优先级变了,少数高成本的工单长期没人处理;
- 自动回复缩短了首次响应的时间,却引来更多的追问;
- 升级规则太敏感,把大量本来可以解决的工单推给了高级客服;
- 仪表板上“待处理”的定义变了。
五条都是具体的生成过程,各自会留下不同的时序、队列形状和边界特征,所以可以用观察来区分;“AI 不可靠”这样的原因词,做不到这一点。
用最小反事实找承重的位置#
可以问:如果只能改一个地方,改哪里最可能让异常消失?
问这个问题,是为了逼着解释暴露自己的结构,并不需要马上去改。如果只修正分类,积压应该先在哪类工单上下降?如果只调整队列的顺序,首次响应和解决时长会怎样分化?如果问题只是口径,原始的工单状态是否仍然显示同样多的积压?
最小反事实,把“可能的原因很多”改写成“每个机制分别要求什么”。它是从直觉走到工作解释的一步。
在不同尺度之间来回看#
复杂的问题常常跨越几个尺度。AI 的一次分类结果改变了队列的顺序,队列的顺序改变了客服的注意力,注意力的分配改变了回复的质量,回复的质量又改变了用户的追问。只盯着某一层,容易把下游的症状当成上游的原因。
可以依次问:单个对象或单次请求上发生了什么?一批对象进入队列以后,分布和等待时间怎样变化?团队的激励、权限或资源,怎样改变了局部的行为?结果是否又反过来制造了更多的原因,形成反馈?
换尺度的目的,是找到真正把局部行为和整体形态连起来的那几条关系。
类比要能带来检查点#
类比能帮人发现结构,也能制造好听的空话。“销售漏斗像水管”“组织像生物体”“技术债像金融债务”都可能有用,前提是它们带来可以检查的新问题。
把系统比作排队网络,就要继续问到达率、服务率、优先级和拥塞;把技术债比作债务,就要说清本金、利息、再融资和违约分别对应什么。如果类比只让文字更生动,却没有带来边界、反例或新的观察,它就只是修辞。
探索刚开始时,不必要求每个想法都立刻 hard-to-vary。模糊的直觉、异常感和不完整的比喻,可以先作为材料留着。等候选的机制开始影响比较和行动时,再要求它们交代结构、边界和可区分的后果。如果收紧得太早,新的想法还没成形就会被淘汰;如果收紧得太晚,没有经过检验的故事会主导决定。第十五章会再回到这个平衡。
没有异常时,从决定依赖的判断开始#
前面的例子都从一个已经出现的现象开始。有些决定前面没有现象可解释,例如要不要进入一个新市场,要不要把一个团队拆成两个。这时没有现成的解释对象,可以换一个入口:把这个决定依赖的判断写成一句话,并写明它会在什么日期、被什么观察证明是错的。
例如,一家公司在考虑给已有的中小企业客户推出一项付费的自动对账功能。这个决定依赖的判断可以写成:
在每月交易超过 500 笔的客户里,至少两成会在一个月的试用结束后付费;如果到第十二周,付费的比例低于一成,这个判断就算错了。
写成这样以后,后面几章的动作照样适用。立敌,是写出最可能让这个判断落空的另一种情况,例如客户愿意用,付费的决定却在他们的外部会计手里;摊牌,是找出两种情况预期不同的早期信号,例如试用期里是客户本人还是会计在登录和导出数据;决策、试探和入账,与前面讲的相同。
本章要点#
- 定题的作用,是防止讨论中途换题。
- 先查测量,但查测量不能无限推迟对机制的讨论。观察的人也可能是仪表的一部分;检查仪表的好办法,是让观察的人不知道条件。
- 开放世界里,还要固定人群、制度、环境、分析单位和观察窗口;决策不止一个时,分别写出最晚时间。
- 没有现象可解释的决定,从它依赖的判断开始:写成一句能在某个日期被证明是错的话。
把“团队交付变慢了”改写成一个可以出错的解释对象,再分别写出解释问题、分解问题和决策问题。
参考思路
解释对象示例:过去两个迭代(四周)里,支付组从“开始开发”到“上线”的中位周期,从 6 天变成了 11 天;同期需求的数量持平,另外两个组的周期没有变化;变慢主要出现在“代码评审”和“等待测试环境”两段。
- 解释问题:为什么支付组的交付周期在评审和测试环境两段变长了,而其他组没有?
- 分解问题:变长的时间,主要落在哪类需求、哪几位评审人、哪个测试环境上?
- 决策问题:下个季度的上线承诺要不要调整?要不要现在就给支付组加一个专用的测试环境?各自最晚什么时候决定?
写完会发现,“交付变慢”原本容纳的“人不够”“流程太重”“需求变难”这些故事,大多已经可以用上面几个具体的数字去检验了。
第六章 立敌:竞争解释要能改变下一步#
为什么“也许还有别的原因”不算竞争解释?怎样构造一个足以改变调查、行动或风险判断的强敌?
读完应能:
- 让竞争解释和主解释处在同样具体的程度;
- 按几个固定的来源找出竞争解释;
- 区分互相排斥、可以并存和必须组合的机制,并给每个因素分配角色。
一个团队只有一个故事的时候,所谓“分析”,通常只是在给它补细节。竞争解释的价值,在于迫使主解释承担它原本不愿意承担的约束。礼貌地说一句“也许还有别的原因”,做不到这一点。
竞争解释至少要做到三件事:和主解释解释同一个对象;具体的程度相近,而不是一句模糊的口号;如果它更接近事实,观察的先后、行动的规模或风险的判断就会改变。
所以,“也许市场不好”通常不算强敌。“大企业采购的安全审查周期变长了,导致这类客户的后期销售周期拉长;它预期中小企业的自助购买路径基本稳定”,才开始有竞争的资格。
竞争解释要一样具体#
第三章的变体测试能揭开墙纸,却不会自动产生一个有力的对手。把“低意向流量”换成“销售响应变慢”,只完成了一次替换;新的候选还要说明自己的路径、边界和对证据的预期,并且足以改变相对的判断或下一步的行动。
竞争解释不必写成一篇论文,但要和主解释一样具体。不能让主解释拥有完整的机制、数据和边界,却只给对手留一句“也许市场不好”。那不是比较,是找了一个稻草人来证明自己。
对手从哪里来#
有用的竞争解释,大多来自下面几个地方。立敌时可以逐项过一遍:
| 来源 | 要问的问题 | 书里的例子 |
|---|---|---|
| 测量 | 数字本身有没有变:口径、埋点、采样、标签和数据延迟? | 尾延迟事故里的采样缺口;第十二章抽样核对新旧口径 |
| 同一时间的其他变化 | 异常开始前后,还有什么变了:发布、活动、配置、流量来源、季节? | 事故当天的限时秒杀 |
| 共用的资源和上游 | 受影响的部分和别的部分共用了什么:连接池、缓存、供应商、审批队列、销售团队? | 共用的连接池;支付授权;被普通注册挤满的销售队列 |
| 构成的变化 | 总体变了,是不是因为里面各类对象的比例变了,而每一类内部没怎么变? | 第十二章个人用途和广告来源的注册占比上升 |
| 参与者的调整 | 用户、对手或员工,有没有针对我们的规则或指标改变做法? | 第十三章攻击者换掉被规则盯上的标识 |
| 事前验尸 | 假设半年以后证明主解释错了,最可能的原因是什么? | 适合在会议开始时让每个人各写一条 |
最后一项借用了 Gary Klein 提出的事前验尸(premortem)。这张表只用来产生候选,不用来判断谁对。每个候选仍然要满足上面的三条要求:解释同一个对象,同样具体,成立时会改变下一步。
竞争不等于只能留下一个#
现实中的候选解释之间,有三种关系。
有些互相排斥。例如,转化率下降,究竟只是口径变化造成的假象,还是在口径稳定时也真实存在的变化。如果前者足以解释全部现象,后者的权重就应该降低。
有些可以并存。低意向的流量增加、团队协作没有形成、销售响应变慢,完全可能同时发生。这时没有必要逼它们争夺“唯一的根因”;更有用的,是逐条检查每条路径得到了什么支持。
还有一些,只有组合起来才讲得通。新入口先改变了用户的构成,新增的流量又把销售队列拉长,响应变慢,进一步降低了高意向客户的转化。组合解释的要求更高:它必须交代先后、相互作用和放大的关系,而不能只说“都有影响”。
“根因”这个词,在复杂系统里常常误导人。很多事故和业务变化,来自几条平时都能被容忍的路径在某个负载和时机下的叠加,找不到一个单独起作用的原因。把问题改写成“哪些机制共同构成了失败的条件”,通常比寻找唯一的罪魁祸首更接近现实。第十一章的事故就是这样:团队事后粗算,新版本抬高了缓存未命中,当天的秒杀抬高了总流量,两者同时存在,连接池才被打满。秒杀的贡献没有被完全区分,但这至少说明,“唯一的根因是什么”这个问题本身,可能就问错了。
贯穿案例:关掉功能就好了以后,还需要哪些强敌#
“关闭功能以后恢复”只说明新功能参与了事故。要知道怎样安全地恢复,至少还要认真展开这几条机制:
| 候选解释 | 机制路径 | 如果它更接近事实,下一步会怎样不同 |
|---|---|---|
| 缓存键膨胀 | 新版本改变了缓存键 → 未命中增加 → 承运商网关的连接池排队 | 先查缓存键的数量、命中率,以及未命中请求的等待 |
| 共享资源竞争 | 秒杀流量或其他调用方挤占了共享的连接池或缓存 → 几个调用方的尾部一起变慢 | 需要资源隔离、预算,以及按调用方拆开的监控 |
| 支付上游变慢 | 某类支付授权的延迟上升 → 结账的尾部变慢 | 应当按支付方式和授权阶段定位,而不是只盯着新功能 |
| 测量失真 | 采样或调用链缺失 → 仪表夸大了尾部,或者定位错了 | 先核对边缘日志、合成监控和完整的请求链 |
这些解释有的互相排斥,有的可以并存。立敌的产出,是一组足以改变调查和恢复路径的候选机制。
给因素分配角色#
几个因素同时成立时,最有用的问题,是它们在结构里分别做什么;“各占百分之几”往往问不出结果。
| 角色 | 它回答的问题 |
|---|---|
| 长期脆弱点 | 为什么系统长期容易在这里出事? |
| 触发器 | 为什么偏偏在这个时间点爆发? |
| 中介 | 上游的原因通过什么路径影响结果? |
| 调节变量 | 什么条件让某条因果关系变强或变弱? |
| 放大器 | 最初的偏差出现以后,什么让后果迅速变大? |
| 瓶颈 | 当前最限制结果、最值得干预的环节是什么? |
| 症状 | 什么只是结果的可见表现,却被当成了原因? |
| 共同原因 | 什么上游因素,同时制造了所谓的原因和结果? |
调节变量和放大器最容易混淆。冷流量(没有购买意向的访客)会让“定位不清 → 转化下降”这条关系变得更强,它改变的是这条关系的强度;重试则发生在延迟已经上升以后,把一次偏差放大成更严重的拥塞,它处在结果的生成路径上。
用第十一章的事故举例:承运商网关连接池的处理上限,是长期脆弱点;全量放量,是触发器;缓存未命中,是中介;秒杀带来的总流量,是调节变量(同样的未命中率,平日的这个时段打不满连接池,秒杀时就打满了);结账对这项功能没有设超时,是放大器(排队的时间被原样传给了用户);采样的缺口,则是让我们看不清结果的测量问题。
角色不是永久的标签。同一个因素,在不同的解释对象里,可能承担不同的工作。连接池的等待,在这次事故里是中介,在容量规划的问题里可能是瓶颈。角色要相对于当前要解释的现象来写。
六个寻找方向#
房间里只有一个故事的时候,可以沿六个方向找对手:
- 仪表变了,还是世界变了?
- 谁进入了样本,谁没有被观察到?
- 有没有一个共同原因,同时制造了所谓的原因和结果?
- 结果是不是反过来,改变了我们称为原因的那个变量?
- 同样的现象,能不能由另一条机制产生?
- 这个机制,是不是只在某个人群、负载、时段或环境中成立?
这不是必须填满的清单。没有材料的时候,写“目前未知”比硬造六个故事更诚实。重要的是找到那个会改变决策的竞争解释。
从单个数字转向现象的形态#
一行汇总的数字,能容纳太多故事。解释在现象的形态面前才会变具体:它从什么时候开始,集中在哪些人群,平均值和尾部是否同向,哪些地方没有变化,例外是否稳定地存在。
假设改版以后总体付款率下降。“产品变差了”“流量变差了”“销售变慢了”,都能解释这一个数字。如果进一步发现:直接访问的注册稳定、广告来源的下降,个人账户增加、团队邀请减少,而第一块看板的创建率没有变,候选的解释就不再拥有同样的自由度。
一个实用的原则是看残差,也就是当前的解释处理完以后,还剩下哪些重要的现象没有解释。新加的机制,只有在解释了重要的残差,或者改变了某条可以行动的关系时,才值得放进来。把原因清单写得更长,不等于理解得更深。
小心解释给自己加免责条款#
有些理论表面上很坚定,做法却是把所有反例都推给外围的条件。
产品卖不动,团队说“销售不相信产品”;销售积极推了以后还是卖不动,解释变成“客户还没有被教育好”;客户明确指出了功能缺口,解释又变成“销售没有找到对的客户”。核心的主张从来不动,保护它的理由随时在换。
Popper 后来回忆,他在 1919 年就见过这种结构。他向心理学家 Adler 报告了一个在他看来并不符合 Adler 理论的病例;Adler 连那个孩子都没见过,却毫不费力地用自卑感理论作出了解释。Popper 后来举了一对相反的行为:一个人把孩子推进水里,想淹死他;另一个人为了救孩子,牺牲了自己。Freud 的理论和 Adler 的理论,都能同样轻松地解释这两个人。Popper 的结论是:这些理论看起来能解释它们所涉领域里发生的几乎一切,这正是它们的弱点。
科学哲学把这种做法称为免疫策略:不断增加辅助的假设,让核心的主张对任何不利的信息都免疫。它和 hard-to-vary 正好相反。判断一个解释是不是在给自己免疫,不要看它还能不能讲通,而要看不利的信息出现以后,它有没有降低对某条主张的信心。如果唯一的变化是多了一条免责条款,这个团队什么也没有学到。
本章要点#
- 强敌要解释同一个对象,同样具体,并且一旦成立会改变下一步。
- 找对手时,逐项检查测量、同一时间的其他变化、共用的资源和上游、构成的变化、参与者的调整,再做一次事前验尸。
- 复杂系统里更常见的,是几条机制共同构成失败的条件,而不是唯一的根因。
- 新的机制要么解释重要的残差,要么改变一条可以行动的关系,否则不必加进来。
主解释:“最近三个月客户流失率上升,是因为新版 App 太难用。”
- 写一个和它同样具体的竞争解释,要有机制路径、适用边界,以及一个只有它才会预期的现象。
- 说明两者是互相排斥、可以并存,还是必须组合;如果可以并存,给每个因素分配一个角色。
参考思路
竞争解释示例:“三个月前,跨境收款的手续费对月流水低于 5 万美元的客户上调了 0.3 个百分点,这部分客户比价以后转走了。”它预期:流失集中在月流水低于这个门槛的客户;流失的时间,集中在第一张新费率账单之后;流失之前,客户经理的记录里常有“问价格”;而重度使用 App 的大客户,流失并没有增加。
主解释则预期:流失集中在新版上线后活跃度下降的客户,并且和费率档位无关;流失之前,App 内的操作失败或客服投诉增加。
两者可以并存。如果都成立,调价可能是触发器,难用的新版是调节变量:它让本来就在比价的客户更容易下决心离开。这样写完,下一步要看的数据就很具体了:按费率档位和 App 活跃度,把流失的客户分成四格来看。
第七章 摊牌:找出能区分几个解释的观察#
什么样的观察,才能区分几个竞争解释?
读完应能:
- 写出包含方向、时序、边界和中间过程的差异化预期;
- 按失败方式判断证据是否独立,并在开放世界里寻找跨环境仍然成立的结构。
一项材料不会天然地“支持”某个解释。证据总是相对于几个候选解释而言的:要看的是,看到这个现象以后,A 和 B 之中哪一个更难保持原样。
判断一项观察有没有用,要先问:有没有一种观察,在 A 更接近事实时容易出现,在 B 更接近事实时却不容易出现?这种能把两个解释拉开的观察,本书叫差异化预期。只问“什么证据支持 A”,会把两边都能解释的事实也算成 A 的证据。
例如,如果缓存未命中是关键的中间环节,没有命中的请求,连接等待应当明显高于命中的请求。相反,“关掉功能以后系统恢复”,区分不了“缓存键膨胀”和“共享资源竞争”,因为两种解释都预期它会发生。
这里可以借一个不用计算的贝叶斯直觉。如果解释 A 认为某个现象很可能出现,解释 B 认为它很少出现,那么看到这个现象,会明显提高 A 相对于 B 的可信度。如果两边都同样预期它,这个观察也许很重要,却不能在 A 和 B 之间选边。所以,证据的价值不在文件的数量,而在预期的差异。
还有两点常被忽略。
第一,没有出现的现象,同样是证据。如果 A 要求某个现象必然出现,而它没有出现,A 付出的代价,往往比“看到一个 A 预期的现象”带来的支持更大。一条解释即使被许多顺利的观察支持过,只要出现一个它明确禁止的观察,也要被改写。
反过来,“什么都没发生”的记录,也可能是最有区分力的证据。1986 年 1 月,挑战者号航天飞机发射前一晚,工程师和管理人员讨论低温会不会让固体火箭助推器的 O 形密封圈失效。事后的调查指出,那晚讨论的主要是密封圈出过问题的那几次发射。它们分布在冷的和暖的日子里,只看这几次,温度的影响似乎说不清。把此前 23 次发射全部放在一起看,情况就不同了:密封圈没有出问题的 16 次,都发生在约 19°C 以上的日子;数据里最冷的四次发射,约 12 到 17°C,每一次都出现过受损。那些没有出问题的发射,正是把“温度有影响”和“温度没影响”拉开的观察。挑战者号发射时约 2°C,比此前任何一次都冷得多,已经在所有经验之外。第八章会再回到那一晚的决策。
第二,证据把判断推多远,取决于预期的差异;判断从哪里出发,要看这类情况以往通常是怎样的,也就是基础比率。在第十一章的团队里,过去一年,发布后几分钟内出现的延迟事故,大多数确实和那次发布有关,所以“新功能参与了事故”一开始就是一个合理的起点。但基础比率只给起点,不给终点:它说明应该先查新功能,不说明是新功能里的哪一条机制。
贯穿案例:哪些观察能把机制分开#
把“系统恢复了”继续拆细,证据才开始有方向:
| 待观察的现象 | 缓存键膨胀 | 共享资源竞争 | 支付上游变慢 | 测量失真 |
|---|---|---|---|---|
| 缓存键的数量和命中率 | 键的数量上升,命中率下降,集中在结账路径 | 不一定有明显变化 | 不要求变化 | 可能只在仪表里异常 |
| 未命中和命中请求的连接等待 | 未命中的请求明显更高 | 各类请求都可能升高 | 不要求这种差别 | 原始链路可能不支持仪表的结论 |
| 其他调用方的等待 | 不一定一起变差 | 可能一起变差 | 通常稳定 | 不同来源的读数可能不一致 |
| 支付授权阶段的延迟 | 通常稳定 | 通常稳定,或者随后才变化 | 按支付方式明显变差 | 合成监控和真实日志可能冲突 |
“尾延迟上升”是所有解释都能说明的共同事实;表里的分层、时序和中间过程,才可能让某个解释付出代价。
写出差异化预期#
差异化预期不是一句“数据会支持我”。它应当尽量写出方向、幅度、时序和边界。
假设总体付款率下降,团队在比较“低意向流量增加了”和“协作价值没有形成”两种解释,可以这样写:
| 待观察的现象 | 流量构成解释的预期 | 协作路径解释的预期 | 主要的测量威胁 |
|---|---|---|---|
| 高意向账户的付款率 | 接近历史水平 | 也会下降 | “高意向”的标签是不是事后定义的 |
| 第二位成员的真实使用 | 变化不大 | 明显下降 | 发出邀请,是否等于真的在用 |
| 加上协作引导以后的先后顺序 | 付款不一定跟着变 | 先提高真实使用,随后付款改善 | 干预是不是只改变了表面的行为 |
这张表不需要像物理定律那样精确。它的用处,是在结果出来之前,把“什么结果会改变判断”说出来。少了这一步,人会在结果出来以后重新解读每一个数字,把任何方向都记成胜利。
双方共同预期的事实仍然有用。它不能直接区分 A 和 B,但可能同时排除第三类解释,也可能暴露两个解释共同漏掉的现象。例如,几个独立的来源都显示真实付款在下降,这区分不了流量构成和协作路径,却能削弱“只是埋点出了错”的说法。证据可以改变候选的集合,不必每次都选出唯一的赢家。
一次经典的摊牌#
1854 年伦敦霍乱流行时,主流的解释是“瘴气说”:疾病通过污浊的空气传播。John Snow 主张另一条机制:霍乱通过被粪便污染的饮用水传播。两种解释都能讲通“穷人聚居的低洼地区死得更多”,因为那里的空气更污浊,水也更脏。
Snow 找到了一个让两种解释作出不同预期的观察。泰晤士河南岸的几个区,由两家公司供水:Southwark and Vauxhall 公司仍然从伦敦市区受污染的河段取水;Lambeth 公司则在 1852 年,把取水口迁到了上游没有受伦敦污水影响的河段。在两家公司都供水的街区,两家的水管铺在同样的街道上,相邻的两户人家,用的常常是不同公司的水。按 Snow 的说法,两家公司都既给富人供水,也给穷人供水,用户在境况和职业上没有差别,呼吸的也是同样的空气。瘴气说预期,两类住户的死亡率相同;饮水传播说预期,用下游水的住户死亡率明显更高。
Snow 和一位助手逐户查访了死亡病例的住处,确认每一户用的是哪家公司的水。按他 1855 年出版的书里的数字,流行的头七周,Southwark and Vauxhall 公司供水的 40,046 户中,死于霍乱 1,263 人,每万户 315 人;Lambeth 公司供水的 26,107 户中,死亡 98 人,每万户 37 人;伦敦其他地区,每万户 59 人。住户常常说不清自己用的是哪家的水,Snow 就去查他们的缴费单据;还查不到时,就往水样里加硝酸银,看盐分的多少,因为下游河水的含盐量高得多,两家的水一眼就能分开。判断供水公司的方法和死亡登记来自不同的来源,两者不会因为同一种错误而一起失真。
这个例子里,有本章要说的几件事:先找两种解释预期不同的观察,而不是罗列双方都能解释的事实;证据的设计,要针对当时最危险的混杂,在这里就是贫富和空气;来源是否独立,要看失败的方式,而不是看文件的数量。
独立性要按失败方式判断#
四份报告,可能只是同一段叙事被重复了四次。高管先说“定位不清”,销售复盘沿用这个词,客户成功的备注继续照抄,访谈提纲最后又把它提示给了用户。文件越来越多,独立的约束却没有增加。
对关键的判断,可以画一张简单的证据来源图:
原始产品事件 ──> 分层漏斗
销售系统时间戳 ──> 首次响应时间
无提示访谈 ──> 用户怎样理解产品
账单系统 ──> 实际付款与退款
然后问:这些证据,是否共用同一个样本入口、同一处埋点错误、同一套标签定义、同一种提问方式,或者同一种组织激励?
“独立”不等于来自不同的文件,也不一定要来自不同的系统。两个系统可能共用同一套错误的用户标签;同一个系统里的两项原始记录,也可能不受同一种叙事偏差的影响。要找的,是不同的失败方式。Snow 的缴费单据和硝酸银检测,就是这样一对来源。
因果图公开假设,不负责证明#
因果问题适合画图,因为箭头会逼人说清上游、中介、共同原因和反馈。
flowchart LR
A["入口改变"] --> B["流量构成变化"]
A --> C["销售队列变长"]
A --> D["协作引导路径变化"]
B --> E["实际付款率变化"]
C --> E
D --> F["协作行为变化"]
F --> E
G["测量口径"] -.影响观测.-> H["观测到的付款率"]
E --> H
图只是把假设公开出来。每条关键的箭头还要标明状态:只是相关,有机制线索,有干预支持,被某项证据削弱了,还是还没有检查。图外也要留出“没有建模的共同原因”和“能不能迁移到别处”的位置。
数学、约束或历史的问题,不必为了形式统一去画因果图。前提和推导链、来源之间的关系、同期的材料和激励的结构,同样能起到“公开假设”的作用。
没有哪种方法自动站在证据的顶端#
“没有通用的证据等级”,不等于所有方法一样强。针对特定的威胁,有些设计确实有明显的优势。执行良好的随机分配,通常比简单的观察比较,更能抵抗没有测量到的混杂;但它仍然可能受到失访、执行污染、测量错误和外推失败的影响。
这四个词,具体在担心什么:
- 未测混杂:有一个没有记录的因素,同时影响了所谓的原因和结果。例如,购买意向同时影响了协作行为和付款。
- 失访:一部分对象,没有走到观测结果的那一步,而且离开的方式和分组或结果有关。
- 执行污染:名义上的两组,实际接受了相似的处理。例如,销售把实验组的话术也用在了对照组身上。
- 外推失败:结果只在当前的人群、版本、负载或环境下成立,却被推到了没有研究过的范围。
所以,不要问哪种方法的名字最高级,先问当前最危险的错误是什么。担心口径漂移,就审计原始记录;担心选择偏差,就检查谁进入了样本;担心共同原因,就找更合适的对照、自然发生的变化或随机的设计;担心干预没有按计划执行,就看过程指标;担心外推,就回到目标的人群、负载和环境。
证据的强度,来自“设计是否针对了当前的威胁”,而不是方法的标签。Snow 没有做随机试验,但两家公司的水管交错铺设,已经替他处理了当时最危险的混杂。
开放世界里,找跨环境仍然成立的结构#
在相对封闭的系统里,一条链路追踪,可能直接排除好几条候选的路径;开放的系统,很少给出这种一次定胜负的证据。更可靠的做法,是让同一个机制在几个有意义的环境里接受检验:
- 换一个时间窗口,方向和先后顺序是否还在?
- 换一个渠道、人群或地区,哪些关系保持,哪些消失?
- 换一种测量来源,现象是否仍然存在?
- 在按理不该受影响的对象(负对照)上,变化是否确实没有出现?
- 干预以后,中间过程是否先于最终的结果发生变化?
例如,协作引导对不同客户的提升幅度可以不同;但如果“真实的协作”是承重的机制,改善应当先出现在真实的协作行为上,而不能只出现在与这个机制无关的表面指标上。
这里要找的是条件不变性:参数可以随环境移动,结构不能在每个环境里都换一套说法。一次显著的结果,可以支持一个局部的效果;在几个环境里都保持方向、顺序和边界,才更接近“机制获得支持”。
本章要点#
- 证据的价值,来自不同的解释对它的预期有多不同;没有出现的现象,也是证据。挑战者号的数据里,最有区分力的是那些没有出问题的发射。
- 双方共同预期的事实,可以排除第三种解释,但不能在这两种之间选边。
- 方法没有固定的等级;设计有没有针对当前最危险的错误,决定了证据的强度。
接着第六章的练习(“新版 App 太难用”对“手续费上调”):
- 写一张三行的表:每个解释各自独有的预期;再写一项双方共同预期的事实。
- 为其中一个解释加一个负对照:什么结果会说明,原来的关系只是巧合?
参考思路
| 待观察的现象 | App 难用 | 手续费上调 |
|---|---|---|
| 流失客户的费率档位 | 和档位无关 | 集中在被上调的档位 |
| 流失之前的 App 行为 | 操作失败和投诉增加 | 没有明显变化,但有询价的记录 |
| 流失的时间点 | 随着新版上线逐步出现 | 集中在第一张新费率账单之后 |
双方共同预期的事实:账单系统和客户经理的记录,都显示流失在上升。两边都解释得了,不能选边;但两个独立的来源一致,能削弱“只是统计口径变了”。
负对照:费率没有变化的高流水客户。如果“手续费上调”是主因,这些客户的流失率不应上升;如果它们也一样上升,手续费的解释就要降低权重。
第八章 决策:把判断变成有边界的行动#
即使我们对几个解释的相对判断已经改变,为什么仍然不能直接推出“现在就全量执行”?
读完应能:
- 区分稳健动作、信息动作和承诺动作;
- 根据环境、可撤回性、反馈速度和承受不起的损失,决定行动的规模;
- 说明决策在什么时候发生,以及它和五个动作的关系。
决策不在五个动作里的固定位置。它在两种时候发生:一个决定到了最晚时间;或者某种损失变得承受不起。第一次决策可能发生在定题之前:序里的值班负责人,在弄清机制之前就关掉了功能,这是在承受不起的损失面前先止损。一个问题也常常同时挂着几个决定,时限各不相同,要分别在各自的时间作出。每次决策,都用当时手上的判断。决策选中了信息动作以后,由下一章的试探把它设计成具体的探针;探针的结果入账以后,到下一个决定的时间,再决策一次。
解释回答“为什么”,证据回答“我们现在该更相信什么”,决策还要回答另一个问题:即使我们可能错,下一步做什么最合适?
决策先问:哪项未知一旦改变,会让行动的排序、规模、时机、监控方式或权限边界发生变化?如果一个未知无论结果怎样都不会改变下一步,继续收集信息,可能只是在拖延。如果某种损失承受不起,就应该先止损或升级,不必等解释完整以后再动。
这一步不能只看哪个解释排在前面,至少还要看三种结构。
期望值:普通的得失怎样权衡。 当结果大致可以比较、损失也承受得起时,可以估算各个选项在不同解释下的收益和成本。概率不必假装很精确,但要把幅度、受影响的人和时间写出来。
期权价值:保留选择本身有价值。 可以撤回的动作,不只产生业务结果,还买到了学习。5% 的灰度可能比马上全量慢,却保留了回滚的能力,让后来的信息还有机会改变方向。反馈越快、回滚越便宜,分阶段行动的价值越高。这就是实物期权的直觉:不确定性高的时候,等待和小步试探,是在购买以后的选择权。当然,机会可能错过,等待也有成本,所以“永远先做小规模”同样不是定律。
承受不起的损失:有些损失,不能用平均收益来抵消。 当某种后果涉及人身安全、违法、数据泄露、系统性的破坏,或者组织承受不起的损失时,普通的期望值就不够用了。一次无法恢复的失败,不会因为平均收益为正就变得合理。这时先看硬的边界:哪些后果承受不起,谁可能承担,发现是否滞后,有没有更安全的替代方案。解释再可信,也不能越过这些边界。
面对承受不起的损失,举证责任应当落在主张冒险的一方。挑战者号发射前一晚,工程师最初建议不要在这样的低温下发射。据工程师 Roger Boisjoly 后来在调查中的陈述,那次会上变成了要由工程师证明不能发射,这和平时要先证明可以安全发射的做法正好相反。数据本来不足以证明低温下安全;要求被倒过来以后,同样不足的数据,被当成了可以发射的理由。
三类动作#
多数场景里,动作可以分成三类。
稳健动作是在仍然值得保留的几种解释下都合理的动作,例如补监控、修复已经确认的测量缺口、停止扩大明显的伤害。它们不需要先选出唯一的解释。
信息动作的主要价值,是减少会改变决策的不确定性,例如分层重算、独立来源核对、灰度发布、来源复核或者仿真。信息也有成本。如果结果不会改变行动的排序、规模、时机、监控方式或合规的边界,继续调查就未必值得。
承诺动作代价高、难以撤回,或者只在一部分解释下合理。它通常需要更强的证据、更清楚的最坏情形,以及独立的审查。
把“不行动”也写进选项。维持现状不是没有做决定:它可能保住资源,也可能让损失继续累积。只比较主动的方案,会系统性地低估拖延的风险。
一张最小的行动表,可以这样写:
| 选项 | 如果解释 A 更接近事实 | 如果解释 B 更接近事实 | 没有建模的风险 | 回滚与发现的延迟 |
|---|---|---|---|---|
| 维持现状 | 机会损失继续 | 避免了错误的改造 | 风险可能累积 | 什么时候重新评估 |
| 小规模获取信息 | 买到了区分信息 | 买到了区分信息 | 干预可能改变环境 | 范围小,可以暂停 |
| 全量承诺 | 收益可能更大 | 错配的代价高 | 暴露最大 | 回滚慢,发现滞后 |
重大的决策,不能停在“好、中、差”这种符号上。至少还要写出最好、基准和最坏的情形,机会成本,不行动的后果,以及谁有权承担这些后果。
几种解释分不出胜负时,找都合理的动作#
控制理论里有一个直觉:我们不必先精确地知道系统的全部参数,才有资格阻止它进入危险区域。当解释 A、B、C 还分不出胜负时,不要只问“哪一个最可能正确”,还要问:
- 哪个动作,在 A、B、C 下都能减少明显的伤害?
- 哪个动作,保留了回滚和继续学习的能力?
- 哪个动作,只有在某一个解释正确时才安全,因此应该暂缓?
补监控、修复已经确认的测量缺口、限制无法撤回的暴露,常常属于第一类;全量的组织重构、永久的政策调整和高成本的押注,通常需要更强的机制支持。
止损动作也要对照解释#
稳健动作是相对于写下的几个解释而言的。一个动作在我们想到的解释下都安全,在没想到的解释下,可能恰恰有害。
2012 年 8 月 1 日,美国的证券公司 Knight Capital 上线新版的交易路由软件。新代码只成功部署到八台服务器里的七台;第八台上还留着一段多年不用的旧功能,而新代码重新启用了一个原本控制这段旧功能的开关。开盘以后,第八台服务器开始向市场大量发单。团队找不到原因,采取的止损动作,是把七台服务器上的新代码卸掉。按“新代码有问题”这个解释,这是标准的回滚;按真实的机制,卸掉新代码以后,那个开关让七台服务器也开始运行旧功能,问题更严重了。45 分钟里,系统为了处理 212 笔客户订单,向市场发出了四百多万笔订单,损失约 4.6 亿美元。美国证券交易委员会事后的处罚决定还指出,开盘前系统已经发出 97 封报错邮件,没有人据此采取行动。
回滚常常是稳健动作,因为大多数时候,最近的改动就是问题所在;但它并不在每一种解释下都安全。承受不起的损失正在发生时,先找在每个候选解释下都能止损的动作,例如停止这套系统对外发单,再决定要不要回滚。
环境改变行动的默认偏好#
同一个解释排序,在不同的环境里,不应该自动产生同一种动作。
| 环境 | 更合理的默认偏好 | 什么时候可以提高承诺 | 必须接受的代价 |
|---|---|---|---|
| 相对可封闭 | 针对已经找到的路径修复,配套回归测试,逐级恢复 | 主要的生成路径可以重建,修复落在承重的环节上,剩余的风险有监控 | 可能过早地认定边界已经清楚,漏掉用户、供应商或组织的因素 |
| 开放适应 | 先做在几种解释下都合理的动作;把承诺拆小、做成可以撤回的,写清外推的边界 | 局部机制受到多种约束,换了环境仍然出现预期的现象,最坏的情形承受得起 | 学得慢,局部的结论不一定能外推,也可能错过机会 |
| 对抗适应 | 分层控制,限制无法撤回的暴露,保留独立的停止权,持续监控对方的变化 | 冻结规则以后的前瞻验证有效,对正常用户的伤害受控,规则有版本和失效条件 | 误伤和漏放同时存在;公开透明、可以审计,和不让对手学到之间有张力 |
越开放的系统,越要承认“当前最可能的解释”之外还有别的可能;越对抗的系统,越不能把对历史的拟合当成未来的稳定。但机会就要错过、损失正在无法挽回地扩大时,稳健动作也可以是快速、大范围的止损。区别在于,我们把它记成风险控制,而不是完整的识别。
环境带来的四组取舍#
精确与稳健。 生成路径清楚时,针对机制的修复通常效率最高;几种解释都还可能成立时,过于精确的动作反而可能押错,在几种解释下都合理的动作虽然不够“最优”,却不容易酿成大错。
速度与可撤回。 分阶段的动作保留了选择权,却可能错过时机;快速全量能抢时间,却放大了误判的后果。反馈越慢、损失越难恢复,越要重视回滚和止损;危险正在扩大时,先大范围控制暴露,也可能比等待识别更合理。
学习与干扰。 在开放的系统里,干预本身会改变人群、激励和后来的数据。一次试点既产生信息,也可能改变被观察的对象。第九章会展开这一点。
透明与对抗。 规则需要审计、复核和正当的程序,但公开得太细的阈值和模式,可能被攻击者拿去研究怎样绕过。办法是把对外公开的原则、受控的调查细节和独立的内部审查分开,监督仍然要有。
信息只有在决定之前到达,才有价值#
一项信息值不值得买,不只看它能减少多少不确定性,还要看它什么时候到。第十二章的团队面对两个决定:三周后的预算会上,要定下季度的获客投入;另外,要不要上线一项协作引导。一项像样的产品试验,从批准到出结果要将近四个月,对三周后的预算会毫无帮助。所以,获客的决定只能基于现有的证据,再配一个能在季度中途给出信号的小规模加投试验;产品试验则服务于第二个决定。
把每个决定的最晚时间写下来,再看每项信息什么时候能到,常常会发现:一些大家最想要的信息,在决定之前根本拿不到。这时该问的是:没有它,我们能做的最好的动作是什么?
先扩大选项,再精算#
很多坏决定,出在候选的选项一开始就太差,比较的方法再精密也补不回来。房间里只剩“全量上线”和“彻底放弃”的时候,再准确的解释,也只能在两个坏选项之间挑一个。
遇到假的二选一,可以沿六个方向生成第三个选项:
- 推迟承诺:先买一项真正会改变决定的信息。
- 缩小规模:只在一个人群、区域或流量层级上行动。
- 做成可以撤回的:把一次无法撤回的承诺,拆成几个可以停下的阶段。
- 组合:稳健动作和信息动作一起做,把承诺动作推到门槛之后。
- 退出:承认这个问题不值得继续投入。不选,也是一种选择。
- 对冲:几种解释都还可能成立时,构造一个不会被任何单一解释完全击穿的组合。
还可以反过来,先列出几乎一定会让我们失败的做法:在解释还不稳定时一次性下注;主动拿掉回滚的能力;让新的信息即使出现,也来不及改变动作。先排除这些做法,再谈最优,往往比在坏选项里精算更有用。
行动的范围不能超过证据的范围#
同一个解释,可以支持 5% 的灰度,却不支持 100% 发布;可以支持某个人群,却不支持全部用户;可以支持两周的调整,却不支持永久的组织重构。第十二章的加投试验也是这样:它测的是“多投 30%”时的边际成本,证据就只覆盖到 30%,覆盖不到翻倍。
所以,行动的结论应当写成一个有边界的句子:
在当前的证据、版本和适用人群之内,我们暂时更看重解释 A。它足以支持两周、可以回滚的小规模调整,但不足以支持全量改造。产品版本、人群定义或外部环境变化以后,需要重新评估。
这比给某个解释贴上“可以行动”的标签更准确。决策充分不是某个解释的永久属性,而是解释、证据、规模和风险一起得出的临时结论。
本章要点#
- 决策是和五个动作并行的一条线:每到一个决定的最晚时间,或者某种损失变得承受不起时,做一次;第一次可能在定题之前。
- 决策不只看哪个解释更可信,还要看损失是否对称、选择权的价值,以及谁有权决定。
- 几种解释分不出胜负时,先找在每一种解释下都合理的动作;环境越开放、越对抗,越要保留回滚和停止的能力。
- 回滚和止损也要对照每个候选解释检查;面对承受不起的损失,举证责任在主张冒险的一方。
- 信息要在决定之前到达才有用;行动的范围,不能超过证据覆盖的人群、版本、幅度和时间。
一条新的风控规则,在 10% 的交易上运行了两周。解释 A:它拦下的主要是欺诈交易。解释 B:它拦下的主要是正常的新客户,欺诈只是碰巧减少了。业务方希望下周推到全部交易。
- 写出维持现状、稳健动作、信息动作和承诺动作四个选项,并在 A、B 两种解释下比较。
- 指出一个在 A、B 下都合理的动作,和一个只有 A 正确时才安全的动作。
参考思路
- 维持现状(10%):A 正确时,其余 90% 流量里的欺诈继续发生;B 正确时,避免了更大的误伤。
- 稳健动作:对被拦下的交易抽样人工复核,并给被拦下的正常客户一个快速申诉的通道。无论 A 还是 B,这两件事都有用:前者直接区分 A 和 B,后者减少 B 情况下的伤害。
- 信息动作:把规则扩到 30%,但对命中的交易只加一步验证,而不是直接拒绝;同时比较命中交易在之后一个月里的拒付和申诉率。
- 承诺动作:全量直接拒绝。只有 A 正确时才安全;如果 B 正确,会大面积拒绝正常的新客户,而且这种伤害很难事后弥补。
在复核的结果出来之前,“下周全量拒绝”超出了证据的范围。
第九章 试探:好的探针只回答一个关键问题#
怎样设计一个动作,让它减少一个会改变决定的不确定性?
读完应能:
- 把诊断用的探针和治疗用的动作分开;
- 写出事前的结果映射、护栏和停止权,并识别干预对开放系统的干扰。
很多团队把“做个小实验”当成务实的代名词。一个实验规模小,不代表它能给出有用的信息。一个动作如果同时改变了定价、界面、销售跟进和目标人群,哪怕只覆盖 1% 的用户,也很难告诉我们究竟是哪一条机制起了作用。
探针的目标,是以可以接受的风险,减少一个会改变决定的不确定性。它不一定是实验。数学问题的探针,可以是一个反例;历史问题的探针,可以是一处来源冲突;受监管的场景,可以是一次合格专家的复核;工程问题,可以是离线重放或故障注入。
试探执行的是决策选中的信息动作。摊牌指出哪项观察能区分几个解释,决策判断这项信息值不值得现在花代价去买,试探负责用最小、最安全的方式把它拿到。
第五章的两个历史例子,都是只回答一个问题的探针:Pfungst 只改变了马能不能看见提问的人,Wood 只取走了一块棱镜。
设计探针时,先回答五个问题。
关键分歧是什么? 哪个不确定性一旦改变,下一步就会不同?
什么观察最有区分力? 为什么它在两个解释下会有不同的预期?
结果怎样解读? 哪种结果增强哪条主张,哪种结果削弱它,哪种结果仍然分不出来?
护栏是什么? 出现什么情况,必须暂停、回滚或升级?
谁负责更新? 谁执行,谁复核,什么时候把结果写回同一份记录?
便宜的探针先做#
第十二章的团队在会议上有三个各自完整的解释,也有一项从批准到出结果要将近四个月的随机试验。但他们先做的,是四件几天就能完成的事:抽样核对新旧口径;用注册时就知道的特征,给改版前后的两批账户重新加权;从销售系统里拉出首次响应的时间;查看最早几批账户在更长时间里的付款。这四件事没有一件能单独结束争论,却各自削弱或支持了一条具体的主张,也让那项四个月的试验只需要回答一个更窄的问题。
探针的顺序,应该按“每单位成本能减少多少会改变决定的不确定性”来排,而不是按谁的解释说得更响。
小规模测不出总量才出现的问题#
小规模的探针有一个系统性的盲区:它测的是单个请求、单个用户的反应,测不出只有总量达到某个水平以后才出现的约束。
第十一章的事故里,5% 的灰度运行了三天,一切正常。新功能在灰度时也有问题,只是 5% 的流量远远不足以把连接池打满。第十二章里,在两个区域多投 30% 的广告,测得新增投入带来的每次注册,比平均成本贵约二成;这个数字不能直接推到“投入翻倍”,因为好的广告位是有限的,投得越多,新增的每一次注册越贵。
所以设计探针时,要问一句:我们担心的问题,是随规模按比例变化的,还是只在某个总量之上才出现?如果是后者,探针要么覆盖到那个总量(例如让每一级灰度都经过高峰时段,并看共享资源的绝对用量),要么在结论里写明“更大规模时没有检验过”。
开放世界的探针会改变被观察的对象#
在软件环境里,离线重放通常不会改变原来的系统;在市场、组织和欺诈问题里,探针本身可能成为新的原因。价格试验会改变进入样本的人,访谈会改变参与者对问题的理解,风控规则会促使攻击者转移。
所以开放世界的探针,除了问“能不能区分几个解释”,还要问三件事:
- 干预有没有改变人群的构成,或者参与者的策略?
- 结果是不是只在参与者知道自己被观察时才成立?
- 探针结束以后,这个机制在自然的环境里还会持续吗?
常用的局部封闭手段包括:固定观察窗口;事先定义谁有资格进入试验;随机或近似随机的分配;负对照;留出一段不参与建模的时间;影子模式(规则只记录、不执行);分阶段发布;独立复核。它们只是让某一条关键的关系,暂时更容易接受现实的检验;整个世界仍然是开放的。
诊断和治疗尽量分开#
处理事故时,可能必须同时做好几件事来止损;医疗和安全的场景,也可能先治疗、后识别机制。这没有问题,但要承认:这些动作解决的是风险,不一定识别了唯一的原因。
条件允许时,诊断用的探针应当尽量只改变一个关键环节,这样才知道结果落在哪一条关系上。如果必须同时改变几个环节,记录里要写清:我们得到的是“组合方案有效”的证据,而不是每个部件各自的解释。
有效的干预,不等于识别了机制#
1847 年,维也纳总医院的产科医生 Semmelweis 面对一个异常。医院有两个产科病区,隔天轮流接收产妇。第一病区由医生和医学生接生,1841 年到 1846 年间,产妇死于产褥热的比例平均约 10%;第二病区由助产士接生,同期约 4%。产妇们知道这个差别,有人宁可在街上分娩,生完再入院。
他先逐一检验了当时流行的解释。如果是“大气、宇宙和土壤”带来的流行病,两个病区呼吸的是同样的空气,差异不应该存在;而且在街上分娩以后才入院的产妇,死亡率反而更低。如果是拥挤,第二病区更拥挤。有人说,是神父摇着铃穿过病房,吓坏了产妇;他让神父改道、不再摇铃,死亡率没有变。有人说是分娩的体位;他改了体位,也没有变。
1847 年 3 月,他的同事 Kolletschka 在尸检时被学生的手术刀划伤了手指,随后死去,尸检所见和产褥热极为相似。Semmelweis 由此提出:医生和学生做完尸检以后,直接去检查产妇,把“尸体上的微粒”带给了她们;助产士不做尸检,所以第二病区的死亡率低。这条解释同时说明了病区之间的差异、街头分娩的低死亡率和 Kolletschka 的死;改动其中任何一个关键细节,它至少会有一件事解释不了。1847 年 5 月中,他要求所有人在检查产妇之前,用氯化石灰溶液洗手。第一病区的死亡率,从当年 4 月的 18.3%,降到 6 月的 2.2%;1848 年全年约为 1.3%,和第二病区相当。
洗手有效,但机制并没有识别完。当年 10 月,一位患子宫癌、病灶溃烂流液的产妇住了进来。检查她之后,检查者只用肥皂洗了手,同一批待产的十二位产妇中,十一位死亡。Semmelweis 不得不把解释从“尸体上的微粒”扩大为“腐败的有机物”,来源也可以是活人身上的病灶。病原是细菌,这要到大约二十年后 Pasteur 和 Lister 的工作之后,才被人们理解。洗手同时切断了几条可能的传播路径,所以它作为治疗是对的,作为诊断却很粗。这也说明,它为什么值得在机制弄清之前就采用:代价很小,而在当时所有仍然站得住的解释下都有好处,是一个典型的稳健动作。
同样的结构,也出现在个人的问题里。一个人在开放的写作任务上反复拖延,候选的机制有两条:任务太模糊,不知道第一步该做什么;或者对评价太焦虑,觉得初稿必须足够好。“每天固定时间交两百字的粗糙初稿”可能非常有效,因为它同时减少了模糊,也降低了评价的压力。作为改善行为的办法,它没有问题;作为诊断,它分不出哪一条机制承重。要区分,可以分别设计更窄的探针:只提供清晰的提纲,但不降低质量的要求;或者允许匿名自由地写,但不提供任何结构。哪一个单独起效,才更能说明哪一条路径重要。
这条原则适用于医院、个人行为、产品实验和系统事故:用来治疗的动作,可以同时切断几条路径;用来诊断的探针,最好一次只改变一个环节,这样才知道结果对应哪一条关系。现实要求先治疗时,先降低伤害,再如实写明因果的问题还没有解决。
贯穿案例:恢复不是“重新打开看看”#
尾延迟事故稳定以后,团队没有直接全量恢复,而是把学习放进了恢复的过程:
- 离线重放去掉身份信息的缓存键,查清键的数量为什么暴涨;
- 在预发布环境里,给这项可选的依赖加上超时预算和降级方案,并关闭自动重试;
- 按固定的用户分桶逐级放量:1% → 5% → 25% → 50% → 全量,每一级都要经过至少一个高峰时段;
- 每一级都检查尾延迟、完整请求的成功率、连接池等待、共享缓存集群的用量、超时和订单的正确性;
- 任何一条护栏触发时,由事先指定的值班负责人(而不是发布负责人)回滚或升级。
这个探针同时有业务价值和信息价值:它恢复了服务能力,也让团队看到“缓存修好以后,共享资源在更高的流量下还会不会出问题”。但它不会自动识别所有的机制;恢复的结果,只能更新它实际检验到的那几条关系。
本章要点#
- 实验规模小,不代表信息有用;探针要围绕一个会改变决定的分歧,便宜的先做。
- 小规模测不出只在总量之上才出现的问题;诊断用的探针一次只改变一个环节,治疗用的动作可以同时切断几条路径。
- 开放世界的探针会改变参与者,要设计局部封闭和独立复核。
为了提高月活,团队打算在 5% 的用户上,同时改首页布局、推送频率和积分规则,运行两周。
- 作为探针,这个设计能回答什么,回答不了什么?
- 删掉同时变化的因素,重新设计;如果删不掉,写明你只能得到哪一种结论。
参考思路
它能回答“这三项改动合在一起,两周内对 5% 用户的月活有没有影响”;回答不了是哪一项起了作用,也回答不了效果能不能持续:推送频率提高带来的活跃,常常在几周后因为用户关掉通知而消失。
重新设计时,先问哪个分歧会改变决定。如果团队真正在争的是“推送能不能拉回沉默的用户”,就只改推送频率,只看过去三十天没有登录的用户,观察四周,并把关闭通知的比例作为护栏;首页和积分另外做。如果时间只允许做一次组合实验,就在记录里写明:得到的是“组合方案在两周内有效或无效”的证据,不能拿它去论证任何一项单独的改动。
第十章 入账:把结果写回原来的判断#
现实反馈回来以后,怎样只修改它真正触及的主张,并让解释、行动和治理分别更新?
读完应能:
- 做最小必要的更新,不把局部的结果扩写成完整的胜负;
- 为开放世界的判断,记录版本、有效期、残差和复核条件。
结果出来以后,人最容易做的一件事,是改写自己的记忆。
1972 年尼克松访问北京和莫斯科之前,心理学家 Fischhoff 和 Beyth 请一批参与者估计这两次访问可能出现的各种结果的概率。访问结束一段时间以后,他们出其不意地请同一批人,回忆自己当初给出的数字,并说明自己认为每件事有没有发生。对认为已经发生的结果,人们回忆出的概率,普遍高于当初写下的;对认为没有发生的结果,回忆出的概率则更低。回忆朝着已知的结局移动,而参与者并不觉得自己改过什么。这和记性好坏无关:人在知道答案以后,很难重建不知道答案时的状态。在团队里,这种效应会更强,因为复盘会上还叠加了责任、地位和叙事的压力。
最可靠的办法是:在结果出来之前,把判断写下来;结果出来以后,回到那份记录上去改。
另一种常见的错误,是把证据扩写到它没有覆盖的范围:一次局部的试验,被写成历史的根因;一次回滚,被写成完整的机制;一次失败,又被写成整套理论的崩溃。
更新落在最小必要的位置#
单次观察很少能推翻一个完整的解释。更可靠的写法,是下面几种之一:
- 某一条关系得到了支持;
- 某一个边界假设被削弱了;
- 当前的结果,还分不清两个机制;
- 原来的口径或问题需要重写;
- 证据足以支持一个有限的动作,但不足以支持更大的承诺。
局部更新有两个好处:它防止团队因为一次结果大幅摇摆;以后有新证据时,也清楚该更新判断的哪一部分。
三种触发条件不要写成一句话#
现实反馈会改变三样东西:解释、动作和治理关系。三者可能联动,却不能共用一个含糊的“停止条件”。
| 触发的类型 | 约束什么 | 典型的后果 |
|---|---|---|
| 解释更新条件 | 对某个解释或某条因果关系的信心 | 增强、削弱、保留未决、重写 |
| 行动中止条件 | 安全、成本、质量和风险暴露 | 暂停、回滚、缩小范围、换方案 |
| 治理升级条件 | 权限、合规和冲突的处理 | 交给事故负责人、专业人员或更高一级的授权者 |
解释被削弱时,一个在几种解释下都合理的稳健动作仍然可以继续;动作因为成本超支而停止,也不代表解释错了。只有把三者分开,团队才知道现实到底改变了什么。
贯穿案例:一条结果应该写回哪里#
修正缓存键以后,1% 和 5% 的灰度都通过了。放到 25% 的那个晚高峰,结账路径的缓存命中率保持在 96%,承运商网关的调用远低于上限;但十一分钟后,购物车服务读取缓存的延迟开始上升,它的护栏触发,流量退回 5%。
坏的总结是:“缓存不是根因。”它把一次新的观察,写成了整个解释的失败。
更准确的入账是:
缓存键膨胀 → 未命中增加 → 网关连接池排队:得到支持;修正后结账路径命中率 96%,网关调用远低于上限。
“修复版本不会给共享缓存集群带来新的压力”:被削弱;25% 晚高峰时,购物车读缓存变慢。
支付上游是主要来源:继续被削弱。
秒杀流量的贡献:仍未区分。
当前动作:退回 5%;查清共享缓存集群为什么变慢;
满足 25% 的观察窗口和护栏以后,才允许进入下一阶段。
每一项观察,只改它真正改变的那个位置,不给整个故事判“对”或“错”。
账本只追加,不覆盖#
最简单的办法,是保留一份只追加状态变化的判断账本。它不需要记录所有的讨论,只需要让人看见:哪项证据在什么时候出现,哪条主张因此变化,行动有没有跟着调整,下一次复核在什么时候。
一次判断,至少要留下五类信息:当时的问题;主解释与竞争解释;事前预期的差异;采取了什么观察或动作;结果怎样改变了解释和下一步。
账本有两条纪律,比格式更重要。第一,条目在证据到达时就写,而不是等到季度复盘;拖到复盘时再写,写下的已经是被结果改过的记忆。第二,条目引用原来那次判断的版本号,改的是那个版本上的具体主张,而不是另起一段新的成功叙事。
写下事前的把握,事后对照#
如果想提高自己的判断力,账本里还值得多写一样东西:事前,你对每条主张有几成把握。不必精确,“七成”“三成”就够了。
这不是为了证明某个解释。按 Deutsch 的看法,解释不会因为概率变高而被证实;这里的数字属于决策这一层,记录的是你自己的判断习惯。积累二三十条以后回头看:你说“七成把握”的事,是不是大约七成发生了?如果你说七成的事只有四成发生了,说明你在这类问题上系统性地过度自信;如果九成都发生了,说明你太保守,可能因此错过了本来可以更早做的决定。没有事前写下的数字,这种校准就无从做起,因为事后的回忆,会像 Fischhoff 的实验那样,悄悄地向结果靠拢。
校准是可以练出来的。美国国家气象局的预报员每天发布降水概率。Allan Murphy 和 Robert Winkler 在 1977 年分析了这些预报,发现预报员说“七成会下雨”的那些日子,下雨的比例大体就在七成附近,写下的概率和实际的频率相当一致。一个常见的解释是,预报员每天写下概率,一两天之内就知道结果,反馈又快又清楚。多数组织里的判断,缺的正是这两样:事前写下的数字,和及时回来的结果。所以,账本要尽量缩短从判断到结果的时间:能按周复盘的,不要等到季度末。
开放世界的判断,要带版本、有效期和复核条件#
软件修复通常绑定在版本和回归测试上;商业、组织和欺诈的判断,还要绑定在环境上。在这些问题里,解释不应被保存成永久的事实,而应当像一个会过期的版本:写明它依据哪一段数据形成,适用于什么环境,什么变化会迫使它重新接受评审。入账时,至少写清:
当前解释的版本:
适用的人群 / 制度 / 环境:
数据的观察窗口:
解释做到了哪一步:路径完整 / 机制获得支持 / 仍是候选
足以支持的动作及其范围(决策充分):
已经验证的预期现象:
仍然没有解释的现象(残差):
有效期或复核日期:
复核条件:出现下列变化时,重新评估
- 产品、政策或市场结构变化
- 人群构成或分析单位变化
- 指标定义或数据的产生方式变化
- 原有规则的命中率或效果明显变化
- 参与者或攻击者出现新的适应行为
一个解释过期,不等于它过去是错的。危险的是,产生数据的机制已经变了,组织却继续把旧的判断当成不带版本的事实。
有些问题暂时没有合法、合乎伦理或有信息量的探针。这时仍然可以形成临时的判断,只要写清证据的强度、适用的范围和复核的条件。不要为了满足模板,而发明一个没有意义的实验。
本章要点#
- 入账的单位通常是一条关系、一个边界或一个动作的资格,而不是整套世界观。
- 解释更新、行动中止和治理升级,是三种不同的触发条件。
- 事前写下判断和把握,事后回到原来的记录上改;开放世界的判断,要带版本、有效期和复核条件。
- 校准靠事前写下的数字和及时回来的结果,账本要尽量缩短从判断到结果的时间。
事前判断:“推送太频繁,是沉默用户增加的主要原因(把握七成)。”团队把推送频率减半四周后:沉默用户的比例没有变化;关闭通知的比例下降了 30%;投诉减少了。
- 写三行:支持了什么,削弱了什么,仍然分不清什么。
- 为当前最好的解释,补上有效期和两个复核条件。
参考思路
- 支持:推送频率会影响用户对通知的反感,关闭通知和投诉都下降了。
- 削弱:“推送太频繁,是沉默用户增加的主要原因”。频率减半四周,沉默的比例没有变。这条事前有七成把握,结果却不利,应当记下来,以后用来校准。
- 仍然分不清:沉默的主要原因,是推送的内容不相关,还是产品本身的使用频率就低;四周是否足够让已经沉默的用户回来。
当前最好的解释:推送频率主要影响的是通知这个渠道能不能保住,不是沉默的主因。有效期:到下个季度的推送策略评审为止。复核条件:推送内容的推荐方式更换;新用户的来源结构明显变化。
第四部 三个环境,三次完整推演#
案例难度地图#
三个案例的环境,一个比一个开放。
| 案例 | 环境 | 主要练习什么 | 解释能做到哪一步 | 默认的行动偏好 |
|---|---|---|---|---|
| 尾延迟事故 | 相对可封闭,但受流量和共享依赖的影响 | 从现象的形态、调用链和逐级恢复中,重建失败链 | 主要链路接近路径完整 | 针对机制修复,回归测试,带护栏逐级恢复 |
| 注册与付费 | 开放适应:系统难以封闭,参与者会适应,没有明显的对手 | 在无法重来一个季度时识别局部机制,并把两个时间线不同的决定分开 | 局部机制获得支持;两个动作分别判断是否决策充分 | 限定人群、可以撤回的试验,不过度外推 |
| 协同欺诈 | 混合:交易系统能封闭,攻击者针对规则调整 | 在对手主动隐藏和转移时,改变分析单位 | 跨账户协调的机制获得支持;有限的防御动作决策充分 | 分层防御,有限的摩擦,前瞻验证,规则带版本 |
读案例时,每出现一条新的观察,先停下来写:它增强了哪条主张,削弱了哪条,还有什么分不清。然后再往下读书里的更新。要练的是把证据落到最小必要的位置上;案例的结论记不住也没关系。
第十一章 一次尾延迟事故#
在一个相对可封闭的生产系统里,怎样先控制影响,再用调用链、资源状态和逐级恢复,接近具体的失败路径;同时避免把“关掉就好了”写成唯一的根因。
本章的服务名、时间和指标都是虚构的。真实的事故,必须遵守所在系统的值班、变更、安全、数据保护和授权流程。
某电商平台有一个配送时效服务,根据仓库和收货地址计算预计送达的时间。它原本只为购物车页面提供城市级的预计送达:城市级的组合不多,全平台约四万个缓存键,命中率长期在 99% 以上。结果缓存在一个与购物车服务共用的缓存集群里。没有命中时,它通过一个连接池调用承运商的网关重新计算。连接池的上限是 200 个连接,一次网关调用平均约 0.4 秒,所以这条路径每秒最多能处理约 500 次调用。平时,购物车路径的未命中每秒只有二三十次,连接池大部分时间是空闲的。
新功能是在结账页显示精确到街道的“预计送达日期”,由结账服务同步调用同一个配送时效服务来获得;价格、税费、库存、支付和风控都不依赖这项预估。功能先对 5% 的结账用户开放,运行了三天,各项指标正常。09:57,发布负责人把它放到了全量。
版本、调用路径、缓存状态、连接池和发布的流量,都可以检查或重放;团队还能用功能开关和灰度,制造近似的“如果当时不这样”。它并不绝对封闭:秒杀流量、共享依赖和客户端重试来自边界之外,所以最终的解释要为它们留出未决的位置。
时间线#
10:00,当天的限时秒杀开始,结账流量比平日同一时段高约 30%,达到每秒约 5,000 次。10:02,结账接口的尾延迟告警:中位延迟从 230 毫秒升到 260 毫秒,最慢 1% 的请求(下文也记作 p99)从 1.25 秒升到 11.8 秒,超时率明显上升。10:04,值班负责人宣布事故,冻结所有发布。10:06,团队确认,关闭“预计送达日期”以后,结账可以在不显示日期的情况下正常完成。10:09,功能关闭。10:16,p99 回落到 1.4 秒。秒杀在 10:30 结束。
先控制影响,再讨论原因#
关闭功能是为了缩小伤害,不是为了宣布唯一的根因。事故现场要同时维持两条线:处置线负责恢复到安全状态、控制对客户的影响;学习线负责保全时间线、日志和调用证据,等系统稳定以后再区分机制。
两条线混在一起时,团队要么为了诊断而延误了止损,要么因为止损有效,就过早地宣布自己理解了事故。
把异常写成形态#
解释问题可以写成:为什么全量以后,结账的尾延迟和超时突然恶化,中位延迟却基本稳定?哪些证据支持新功能这条可选依赖的链路,哪些现象还可能由支付上游、共享资源竞争或测量失真造成?
安全决策是另一句话:功能保持关闭时,需要什么证据和护栏,才允许逐级恢复?
最初的候选包括:
- 监控或采样的变更夸大了尾部;
- 新版本造成大量缓存未命中,承运商网关的连接池开始排队;
- 某类支付请求同时变慢了;
- 秒杀流量、重试或其他调用方挤占了共享资源。
这些机制不必互相排斥。新版本可以制造更多的未命中,秒杀又可以把问题放大。
每条观察只更新一小段判断#
调查得到了下面这些(虚构的)结果。
边缘网关的日志、合成监控和浏览器端的数据,都看到了尾部恶化,所以“纯属测量失真”被削弱。但最慢 1% 请求的调用链大多没有被采样到,因为链路追踪按固定比例采样,不优先采样慢请求。遥测问题没有被完全排除,这一点被记为缺口。
支付授权的延迟基本稳定,不同的支付方式都出现了同样的尾部问题,所以“支付上游是主要来源”被削弱。
缓存的原始指标给出了最有区分力的证据。配送时效服务的缓存命中率在 09:57 以后几分钟内,从 99% 以上掉到约 95%;按调用方拆开看,购物车路径仍在 99% 以上,结账路径只有 89%。原因很快在代码里找到了:旧的缓存键是仓库、收货城市和商品类目的组合;新功能为了把日期精确到街道,把键改成了仓库、街道级地址编码和购物车里商品组合的哈希,可能的键有几千万个。热门的地址和常见的购物车(秒杀时,很多人买的是同一件商品)还能命中,但大约一成的结账请求落到了从来没有被缓存过的键上。
多出来的未命中,正好超过了连接池的处理能力。每秒 5,000 次结账,有 11% 没有命中,就是每秒约 550 次网关调用,加上购物车路径原有的二三十次,超过了每秒 500 次的上限。到达的速度一旦超过处理的速度,排队就会不断变长,直到请求超时被丢弃。结账服务调用配送时效服务时,没有单独设置超时,连接池的等待也没有单独的上限,整条调用只受承运商网关客户端 12 秒总超时的约束,所以最慢的请求正好停在 12 秒附近。结账服务用的是异步 I/O,等待中的请求不占用工作线程,其他请求照常处理,这就是中位延迟几乎不变的原因;代价是,等待被原样传给了用户。在同一类请求里,没有命中的请求连接等待明显更长,这支持了“未命中进入连接队列”这一环。
关闭功能七分钟后,尾延迟回落,而秒杀还要持续到 10:30。这说明新功能参与了事故,也说明秒杀的流量单独不足以造成它。但这一项观察仍然无法单独区分缓存键、重试、连接池和总负载各自的贡献。
秒杀的贡献可以粗算,但不能确认。平日同一时段每秒约 3,800 次结账,按同样 11% 的未命中率,网关调用约每秒 420 次,加上购物车路径,约每秒 440 次,低于 500 次的上限。也就是说,如果没有秒杀,连接池可能不会被打满,但余量已经很小。这个估算依赖一个没有验证的假设:秒杀期间的地址和购物车构成和平日相同,命中率也相同。团队把它记为“秒杀可能是必要条件之一,贡献没有完全区分”。这个判断只针对上午这个时段:后文恢复时会看到,平日晚高峰每秒约有 6,000 次结账,按同样 11% 的未命中率粗算,网关调用约每秒 680 次,没有秒杀也会超过上限。秒杀决定的是事故在什么时候发生;功能如果一直全量开着,到了晚高峰同样会出事。
灰度为什么没有拦住它#
5% 的灰度跑了三天都正常,这件事本身也需要解释。
灰度期间的未命中率更高,因为只有 5% 的结账流量在填充一个几千万个键的空间。但平日每秒约 190 次灰度结账,即使一半没有命中,也只有每秒百次左右的网关调用,离 500 次的上限很远。没有命中的请求只是多花了 0.4 秒,并没有排队。灰度期间,p99 从 1.25 秒升到 1.6 秒,低于灰度门槛的 2 秒;缓存命中率不在灰度的观察指标里。
灰度测量的是单个请求的行为,测不出资源在总量上的饱和。一个只在总量超过某个阈值以后才出现的问题,在小比例的灰度里本来就看不见。这个认识后来决定了恢复过程的设计:每一级放量都要覆盖一个高峰时段,并且要看共享资源的绝对用量,不能只看延迟。
此时的工作结构,可以写成:
新功能全量
├─> 缓存键数量暴涨 ─> 缓存未命中增加 ─┐
└─> 秒杀抬高总流量 ─────────────────┼─> 网关调用超过连接池的处理能力 ─> 排队 ─> 结账尾延迟与超时
结账未设超时预算 ─> 排队时间原样传给用户
按固定比例采样 ─> 最慢请求的调用链缺失
这幅图上没有“根因”的标签。它记录的是每一环目前得到了多少支持,以及哪些贡献仍然没有区分。
为什么说这条解释难以任意改动#
回到第一章。这条解释里几乎每一个细节,都能用另一项独立的观察来核对:
- 尾部变慢、中位数几乎不变:只有约一成的请求没有命中,而且结账服务是异步的,等待不影响其他请求。如果未命中的比例是五成,中位数也会变;如果服务是同步的线程模型,线程被占满以后,中位数也会变。
- 最慢的请求停在将近 12 秒:唯一起作用的超时,是网关客户端的 12 秒。换一个超时,p99 就会停在别的位置。
- 事故发生在全量以后、并且在秒杀期间:5,000 次的 11% 加上购物车的未命中,超过了 500;3,800 次的 11% 加上购物车的未命中,没有超过。
- 灰度没有发现问题:5% 的流量离 500 次的上限很远。
把第一章那句“接口变慢,是因为数据库有问题”放到这里,它就要同时说明三件事:只有结账路径的命中率掉了;最慢的请求恰好停在 12 秒;关掉一个和数据库无关的功能,延迟就恢复了。它一件也说明不了。换掉一个部件,其他几项观察立刻对不上,这就是难以任意改动在工程里的样子。
恢复本身是一项新的决策#
系统稳定以后,团队离线重放了去掉身份信息的缓存键,确认配送时效实际上只取决于仓库和街道级的地址,购物车里的商品组合对结果几乎没有影响,大件商品另有一个标记。把商品组合的哈希从键里去掉以后,键的数量降到约两百万,重放得到的命中率回到 96%。为了让同一个键能服务不同的购物车,修复版本把承运商网关的完整返回缓存下来,读取时再按购物车的内容取出需要的部分。
在预发布环境里,团队给这项可选的依赖加上了 300 毫秒的超时预算:命中缓存的请求在预算内返回;没有命中的请求,这一次不显示日期,由后台异步回填缓存。客户端的自动重试被关闭。
恢复不是“重新打开看看会不会出事”。流量按固定的用户分桶逐级放量,每一级都要走满一个至少包含一个高峰时段的观察窗口,检查尾延迟、完整请求的成功率、连接池等待、共享缓存集群的用量、超时和订单的正确性。任何订单、价格、税费或支付状态不一致,都立即停止并升级。停止权在值班负责人手里,不在发布负责人手里。
在这次虚构的恢复中,1% 和 5% 的灰度都通过了。第二天 19:30,团队特意选在晚高峰,把流量放到 25%。结账路径的缓存命中率保持在 96%,网关调用远低于上限。但 19:41,购物车服务访问缓存集群的延迟开始上升,它的护栏触发。值班负责人把流量退回了 5%。
调查发现了第二条机制。修复版本为了复用同一个键,缓存的是承运商网关的完整返回,包括每家承运商、每个服务等级在未来十四天里的时效窗口,每个缓存条目从不到 1 KB 涨到了约 50 KB,而结账页实际只用其中很小的一部分。晚高峰每秒约 6,000 次结账,25% 就是每秒 1,500 次读取,仅这一项就是每秒约 75 MB 的出口流量。这个集群按仓库分片,晚高峰的读取集中在两三个分片上,每个分片的网卡是 1 Gbps,再加上购物车服务原有的会话读写,这几个分片的网络带宽接近上限。这条机制同样在小比例的灰度下看不见,同样只在总量达到某个阈值以后才出现。
这个结果没有推翻缓存键那条链路,而是暴露了第二条机制:键的数量修好以后,值的大小成了新的瓶颈,而共享的缓存集群没有给这项功能预留预算。
团队随后把配送时效的缓存迁到独立的实例,把缓存的值裁剪到结账页实际需要的字段,约 3 KB,并给这项功能设了明确的带宽预算和限流。第三天晚高峰,25% 通过;随后,50% 和全量各走满一个包含高峰的观察窗口,尾延迟、超时、共享资源用量和订单正确性都保持在门槛以内。
复盘要改变系统的设计#
最终的记录没有写“缓存是唯一的根因”,而是写:新功能把缓存键的数量放大了几个数量级,没有命中的请求超过了承运商网关连接池的处理能力,排队直接变成了结账的尾延迟;秒杀抬高了总流量,可能是上午打满连接池的必要条件之一,贡献没有完全区分;修复版本放大了缓存值的大小,在恢复到 25% 时,暴露为共享缓存集群的带宽瓶颈;结账对这项可选的依赖没有设超时预算,让排队原样传给了用户;最慢请求的调用链,因为采样方式而缺失。
长期动作包括:可选的同步依赖必须有超时预算和降级路径,默认不重试;发布门槛加入尾延迟、缓存命中率、键的数量和共享资源用量,任何一项越界就自动回滚;灰度必须覆盖高峰时段,并检查资源的绝对用量;链路追踪改为优先采样慢请求;共享的缓存和连接池要按调用方划分预算,并做隔离。
“发布前测试不充分”几乎可以套在每一场事故上。上面的解释更有用,因为它改变了下一个系统的设计约束。
本案做到了哪一步#
对“新功能怎样通过缓存未命中和连接池排队拉长尾部”这条主链路,本案接近路径完整:版本、状态变化、资源等待、超时设置和恢复的结果,能够互相约束。它没有穷尽秒杀流量和所有失败请求的贡献,所以“路径完整”仍然是相对于这一次的解释对象和观测覆盖而言的。
决策这一边,每一级恢复都是在当时的证据下决策充分的有限动作;全量恢复是在第二条机制被修复、并且走满了包含高峰的观察窗口以后才获准的。
用五个动作和决策线回看本案#
- 定题:解释的是“中位数稳定、尾部暴涨”这个形态,而不是笼统的“系统慢”。
- 立敌:保留测量失真、缓存未命中、支付上游和共享资源竞争,并让秒杀作为可能的必要条件留在图里。
- 摊牌:每一项观察只更新一环;“关掉就好了”只被记为“新功能参与了事故”,没有扩写成完整的根因。
- 试探:恢复按流量层级推进,每一级覆盖一个高峰时段,用护栏和回滚能力继续区分机制。
- 入账:最终的记录既写了得到支持的两条链路,也保留了秒杀的贡献和采样缺口这些未决项。
- 决策线:第一次决策发生在弄清机制之前:先关功能、冻结发布,这是在几种解释下都合理的止损。之后每一级恢复各是一次决策;25% 那一级在护栏触发时退回了 5%,全量恢复被拆成了带门槛的几个阶段。
第十二章 注册多了六成,付费账户反而少了#
在一个无法把历史重来一遍的商业系统里,怎样把汇总的变化拆成可以比较的机制,把时间线不同的决定分开,设计一个局部封闭的试验,并严格区分“局部干预有效”和“历史成因已经识别”。
本章的公司、用户和数字都是虚构的,只用于展示方法。样本量、阈值、成本和预算,不能直接搬到真实的业务里。
一家面向中小企业团队的协作软件公司,产品是项目任务看板,按席位收费,一个付费团队平均每年贡献约 8,000 元。四月初,公司把网站的主入口从“预约演示”改成“免费开始使用”。价格、核心功能和销售政策都没有同步调整。
十六周后的七月底,团队复盘。每周新注册从约 1,000 个增加到 1,650 个;但在相同的四十二天观察窗口中比较,首次付款率从约 10% 降到了 5%。下季度的获客预算要在三周后的预算会上定下来,增长负责人的提案是把搜索广告的投入翻倍。
会议上很快出现了三个解释。增长负责人认为,免费入口带来了大量低意向的个人用户,平均值自然被拉低,付费账户的绝对数其实没掉多少。产品负责人认为,新用户完成了个人操作,却没有经历团队协作的关键时刻,所以看不到付费的理由。销售负责人则认为,大量普通的注册淹没了高意向的线索,首次响应变慢,本该成交的客户在等待中流失了。
三个故事都合理,而且可以同时成立。如果会议直接讨论“自助增长的战略对不对”,每个人都会把自己看到的局部机制扩大成整体的立场。
公司不能把同样的十六周再经历一遍,只在其中一次更换入口。渠道构成、竞争环境、销售行为和用户预期也可能同时在变。所以本案不追求重建整个季度唯一的因果路径,而是制造一个限定人群、固定版本和明确观察窗口的局部封闭,用来识别一条可以行动的机制。
团队先把问题拆成三句:
解释问题: 改版以后的成熟账户中,为什么注册显著增加,付款率却下降了?
分解问题: 口径固定以后,差异主要落在哪些人群和环节?
决策问题: 三周后的预算会上,要不要把下季度的获客投入翻倍?以及,要不要上线一项协作引导?
最后一句包含两个决定,时间线不同:预算会在三周以后,而任何像样的产品试验,从批准到出结果都要将近四个月。这意味着获客的决定不能等试验,只能基于现有的证据来做。
第一步:先检查仪表#
数据负责人先纠正了一个数字。每周首次付款的账户从约 100 个降到了约 82 个,少了近两成。所以这不只是分母变大的问题,付费账户的绝对数也在下降。增长负责人“绝对数没掉多少”的前提不成立。
团队随后统一了三个口径:只有注册满四十二天的账户才进入分母;付款以账单系统的首次结算成功为准;团队用途按注册时填写的信息分层,不能用“后来有没有邀请同事”来定义。
最后一条尤其重要。如果用“后来邀请了同事”来定义团队账户,就等于用改版以后的结果重新分组。两批人不再可比,分析会把机制的一部分偷偷塞进样本的定义里。
数据负责人从改版前后各抽了 400 个账户,用原始账单记录逐条核对:新旧口径只在三个账户上给出了不同的付款状态,对付款率的影响不到半个百分点。由此可以写下一个有限的更新:纯测量的假象被削弱了,它解释不了 5 个百分点的主要变化。
注意,这并不证明免费入口造成了付款下降。它只排除了一个竞争解释的主要版本。
第二步:看差异落在哪里,先做便宜的检查#
分层以后,差异落在哪里就清楚了。按流量来源看,改版前每周约 700 个注册来自搜索广告,落地页是预约演示;约 300 个来自直接访问和老客户推荐。两类的付款率都在 10% 左右。改版后,广告带来的注册涨到约 1,350 个,付款率只有 4%;直接访问和推荐仍然是约 300 个,付款率 9.5%。注册时声明个人用途的账户占比从 25% 升到了 45%。而且,声明团队用途的账户付款率也从 12.5% 降到了 8%。
团队只用改版之前就存在、并且在注册当时就能看到的特征,给两批账户重新加权:流量来源、声明的用途和组织规模。把改版后的账户按改版前的构成加权,付款率从 5.0% 回到 6.4%。也就是说,5 个百分点的总差距里,用户构成的变化大约对应 1.4 个百分点;剩下约 3.6 个百分点落在同类账户的内部:同样是广告来源、同样声明团队用途的账户,改版以后就是付得更少。
这与“用户构成解释了一部分汇总的变化”一致,但仍然不是因果分解。标签可能有误,看不见的购买意向也没有被处理。更准确的说法是:构成变化值得保留,剩下的差距还需要别的机制来解释。
“有没有创建第一块看板”发生在入口改变以后,所以不能用来筛选历史账户,否则比较的是两组经过不同筛选后剩下来的账户。它可以在以后的试验里用来定义谁有资格参加,却不能在历史分析里假装成改版之前的特征。
有两项检查几天就能做完,团队在等试验结果之前先做了。
第一项来自销售系统。对注册时声明团队用途的线索,销售首次响应时间的中位数从改版前的 3 小时拉长到 11 小时,因为线索量涨了六成,销售人数没有变。这支持了销售负责人那个解释的前提。但在同一意向层级内,4 小时内得到响应的账户,和 24 小时后才得到响应的账户,付款率只差 2 个百分点;而且销售本来就优先联系规模更大的公司,这个差距说不清是响应快带来的,还是本来就更可能付费的客户被优先联系了。所以这个解释的前提得到了支持,因果贡献仍然没有识别。
第二项来自账单。改版后前三周注册的账户到复盘时已经满了九十天。它们的九十天付款率是 6.6%,比自己的四十二天付款率 5.1% 高 1.5 个百分点;改版前的账户从四十二天到九十天,也大约涨了 1.5 个百分点,到 11.5%。付款确实会晚到,但晚到的幅度和过去差不多,差距没有随时间缩小。“付款只是推迟了”作为主要解释被削弱了;不过目前只有三个周批次,还看不出趋势,要等更多批次成熟。
第三步:让每个机制承担不同的预期#
便宜的检查做完以后,四条路径的状态已经不同了:
| 候选机制 | 它解释什么 | 最有区分力的观察 | 目前的状态 |
|---|---|---|---|
| 流量构成 | 低意向的个人账户拉低了平均值 | 按改版前的构成加权以后,差距是否消失 | 约对应 1.4 个百分点,剩余 3.6 个百分点未解释 |
| 协作路径 | 用户完成了个人操作,却没有形成团队的价值 | 协作引导能否先提高第二位成员的真实使用 | 未检验 |
| 销售响应 | 高意向的线索在更长的队列里等待 | 同一意向层级的首次响应是否变慢,慢响应是否对应更低的付款 | 前提得到支持,因果贡献未识别 |
| 付款时点 | 付款没有消失,只是推迟了 | 九十天的累计付款,是否恢复到历史水平 | 作为主要解释被削弱;只有三个周批次 |
眼前的产品决定并不要求一次识别四条机制。团队选了一个会改变近期动作的关键分歧:对已经声明团队用途、并且创建了第一块看板的账户,协作引导能不能提高第二位真实使用者的比例,并进一步改善付款?
这个问题比“历史上的下降是不是产品造成的”窄得多,也更适合一个安全、局部的探针。
第四步:先给获客决定算账#
预算会等不了试验,所以团队先把获客决定的账算出来。获客的钱花在搜索广告上,所以账要按广告渠道来算,而不是按全部注册来算。
改版前后,每周的搜索广告支出都在 35 万元左右。改版前,这笔钱带来约 700 个注册,每个注册约 500 元;四十二天付款率 10%,也就是约 70 个付费账户,每个付费账户的获客成本约 5,000 元。改版后,落地页把广告点击变成注册的比例提高了,同样的钱带来约 1,350 个注册,每个注册降到约 260 元;但广告渠道的付款率只有 4%,约 54 个付费账户,每个付费账户的获客成本约 6,500 元。
按 8,000 元的年合同价值和约 80% 的毛利率,一个付费团队首年贡献约 6,400 元的毛利。改版前,每获得一个付费账户,首年还有约 1,400 元的结余;改版后大约打平,甚至略亏,回报要靠续约。
用九十天口径算会好看一些。广告渠道改版后的九十天付款率约 5.5%,每个付费账户约 4,700 元;改版前约 11.5%,约 4,300 元,差得不多。但这个数字只来自三个周批次;而且投入翻倍以后,新增的每一次注册通常会比现在的平均成本更贵,因为好的广告位置是有限的。
于是,获客的决定被拆成了三层。
稳健动作:维持当前的投入,既不翻倍,也不削减。
信息动作:在六个广告区域中选两个,把投入提高 30%,运行四周,其余四个区域保持原样作为对照,测量新增投入带来的每次注册成本,以及这些账户的付款率。它的结果会在预算会之后出来,服务的是季度中途追加预算的决定。
承诺动作,也就是翻倍,推迟到两个条件都满足以后:第一,至少八个周批次成熟以后,按九十天口径,每个付费账户的获客成本不高于 5,000 元;第二,加投区域里新增投入带来的每次注册成本,没有明显高于平均成本。这两个门槛由财务负责人解释。
预算会接受了这个方案。它没有满足增长负责人的提案,也没有否定它,只是让翻倍的资格取决于两项还没有到手的证据。
第五步:设计只回答局部问题的试验#
试验方案经过产品、隐私和数据负责人按组织流程批准。团队以组织为单位随机分组,同一家公司不能跨组。有资格参加的是:注册时声明团队用途,七十二小时内创建了第一块看板、并添加了至少三个任务,而且还没有分配销售人员的组织。按当时的注册量,声明团队用途的组织每周约 900 个,其中约六成在七十二小时内建了看板、添加了任务,再去掉已经分配了销售的,每周大约有 500 个组织满足条件。入组十周,去掉重复注册的组织以后,每组约 2,400 个。加上四十二天的观察窗口,从批准到出结果将近四个月。
处理组和对照组只有一处不同。处理组的用户建好第一块看板以后,会看到一个引导步骤:邀请一位同事一起完成这块看板,邀请信里预先填好看板的名称,并说明对方打开以后会看到什么。对照组只有原来设置页里的“邀请成员”入口。定价、销售跟进和其他流程,两组完全一样。
主指标不是“发出了邀请”,因为发邀请可能只是原有意向的反映。团队用了一个更接近机制的指标:七天内,第二位不同的用户接受邀请以后,在看板上完成了编辑、评论或任务分配。四十二天付款率是后续的结果。护栏有三条:邀请被举报为骚扰的比例、支持工单的数量、权限异常的数量,任何一条超过批准的阈值,就关闭这个功能。关闭的决定权在独立的支持与隐私负责人手里,不在产品负责人手里。
事前的结果映射写得很清楚:
- 真实使用提高、付款不变:协作行为可以被拉起来,但经营上的价值还没有出现;
- 两者都不变:削弱这条具体的引导路径;
- 付款提高、真实使用不变:预设的中间环节可能写错了;
- 两者都提高:引导同时影响了真实使用和付款,和预设的作用链相容;但它仍不能证明真实使用是付款改善的中间环节,更不能证明这条链造成了历史上的下降。
最后一条划出了这个案例的边界:一个办法在局部试验中有效,不等于历史问题是由缺少这个办法造成的。
团队还在事前写下了“值得保留”的门槛。按每年约 26,000 个有资格的组织计算,付款率每提高 1 个百分点,每年约多出 260 个付费组织,按首年 6,400 元的毛利计,约 170 万元;保守起见,只算首年,不算续约。这项引导的维护、支持和投诉处理,加上占用的工程人力,估计每年约 250 万元,所以低于 1.5 个百分点的提升不值得保留。
第六步:读取结果,不替结果扩写故事#
下面继续用虚构的结果。分析按最初的随机分组,纳入全部有资格的对象。
处理组第二位成员的真实使用约为 25%,对照组约为 19%。四十二天付款率约为 9.9% 对 7.5%,差异估计为 2.4 个百分点,95% 置信区间为 +0.8 到 +4.0 个百分点。三条护栏都没有触发。
点估计高于 1.5 个百分点的门槛,但区间仍然包含低于门槛的效果。团队仍然决定保留这个引导,理由是它可以随时撤回:点估计明显高于门槛,而判断错了的代价只是几个月的维护成本。如果这是一个难以撤回的动作,比如据此重组销售团队,同样的区间就不够。
所以,结果支持一个有限的结论:在试验定义的人群和版本中,这个协作引导提高了第二位成员的实际参与,也提高了四十二天付款率。团队找到了一个有效的办法。
它没有证明四件事:免费入口对所有用户都有效;历史上的付款下降主要是协作路径造成的;销售响应不重要;九十天的经济账一定足以支持扩大获客。
第七步:把行动和解释分别入账#
团队保留有资格人群中的协作引导,不推广到个人用途的账户。销售运营负责人要在两周内提出一个只改变线索分配方式、不改变其他环节的试验方案。
到试验出结果的时候,获客那条线的证据也已经到手了。加投试验显示,新增投入带来的每次注册,比平均成本高约二成,这些账户的付款率和平均水平相当;十个周批次成熟以后,按九十天口径,每个付费账户的获客成本约 4,700 元,低于 5,000 元的门槛。两个门槛一个通过、一个没有通过。
财务负责人没有批准翻倍,但批准了全部区域加投 30%。理由很具体:加投试验的证据覆盖的就是“多投 30%”这个幅度;按它测出的边际成本和九十天口径,每个新增的付费账户约 5,700 元,仍然低于首年 6,400 元的毛利。翻倍时的边际成本没有测过,而好的广告位越往后越贵。
判断记录写成:
纯测量漂移:被削弱,不是主要解释。
流量构成:与部分汇总变化一致(约 1.4 个百分点),具体因果贡献仍未识别。
协作引导的局部效果:在限定人群和版本中得到随机试验支持。
“入口改变 → 协作路径恶化 → 历史付款下降”:仍未识别。
销售响应:前提得到支持,因果贡献未识别。
付款时点:作为主要解释被削弱;十个周批次的九十天付款率约 6.5%,差距未缩小。
当前行动:只在试验人群中保留协作引导,不推广到个人账户;
获客:全部区域加投 30%,翻倍继续暂缓(边际成本只在 +30% 的幅度上测过);
销售运营两周内提出只改线索分配的试验方案。
复核条件:入口、定价、渠道构成或销售流程改变时,重新评估以上各条。
这次试验没有给出一个宏大的增长答案。它把一个大争论切成了几个可以分别更新的判断,并让每个行动的规模停在支持它的证据范围之内。
本案做到了哪一步#
协作引导在限定人群和版本中的局部效果,达到了机制获得支持,也足以支持“保留这项引导”这个有限的动作,所以对这个动作是决策充分的。它没有达到路径完整,也没有识别历史下降中各个机制各占多少。获客这一边,证据对“加投 30%”是决策充分的,对“翻倍”不是。
用五个动作和决策线回看本案#
- 定题:把“自助增长对不对”改写成成熟账户的注册、付款和人群差异,并把两个时间线不同的决定分开。
- 立敌:同时保留测量、流量构成、协作路径、销售响应和付款时点,每一条都写得一样具体。
- 摊牌:让每个机制说明高意向账户、第二位成员、响应时间和长期付款应该怎样变化;先用便宜的检查更新其中的三条。
- 试探:只在限定的人群里改变协作引导,回答一个局部的问题。
- 入账:把局部效果、历史成因和商业动作分开记录;行动的幅度停在证据测过的范围之内。
- 决策线:两个决定按各自的时限作出。三周后的预算会上,获客的钱按广告渠道算账,维持投入,并用分区加投购买边际成本的信息;协作引导等随机试验出了结果再定。
第十三章 单看每一笔交易,都看不出攻击#
当对手会隐藏真实的状态、学习规则并改变做法时,怎样保留多轮假设,利用残差改变分析单位,并把风险控制、机制识别和对正常用户的伤害分开处理。
本章的公司、攻击、指标和调查结果都是虚构的合成案例,只用于展示防御性的分析。真实的欺诈调查必须遵守所在组织的风控、法务、隐私、证据保全和执法协作流程。本章有意省略了可以被复用的绕过阈值、规则细节和具体的标识。
一家数字商品平台以自己的名义对外收款;礼品卡、游戏点卡和充值类商品,在付款后几秒内自动发货。平台上有数百家供货商。连续十二天,发卡行的欺诈通报和客户申诉显示,未经授权交易造成的损失约为此前基线的三倍;正式的拒付还要几周才会陆续到来。可是,批准率、总体拒绝率和风险评分的分布,都没有明显的跳变。
更反常的是,损失并不集中在刚注册的账户。许多受影响的账户已经存在了几个月,有过正常的购买记录;单看某一笔交易,金额、设备、地区和付款方式也很少同时显得异常。
团队最初面对的,是一组互相矛盾的事实:
- 损失是真的,但可靠的标签通常要在交易后几天到几周才出现;
- 单笔交易看起来正常,汇总的损失却在持续上升;
- 有些账户出现了新的设备,另一些完全没有登录异常;
- 损失集中在能快速发货的商品上,但没有集中在某一家供货商、某一个促销或某一个国家;
- 新的风险评分模型刚上线不久,评分分布却没有出现典型的漂移。
交易规则、风控决策路径、发货流程和事件日志相对可封闭:团队可以检查代码、重放历史快照,验证某项控制在系统内部是怎样执行的。
攻击者的身份、资源和策略,却属于开放、会适应的世界。他们会隐藏真实状态,观察防御,轮换直接的标识,并把一个网络级的行为拆成许多局部看起来正常的行为。所以调查要同时做两件事:重建平台内部发生了什么;识别一个会主动欺骗观察、并在干预以后改变做法的机制。
合理的终点,未必是知道每一个真实身份和每一条完整的攻击路径;更现实的终点是:一条跨账户协调的机制在明确的范围内得到支持,并且足以支持有限、可以监控的防御动作。
会议上很快出现了一句危险的话:“这肯定是新的评分模型漏掉了一批盗卡交易。”
它可能包含一部分真相,却把至少三个问题压成了一个:
解释问题: 为什么未经授权的损失集中出现在长期、低风险的账户中,而单个账户和单笔交易的指标大体正常?
处置问题: 在不大面积误伤正常用户的前提下,哪些流程必须临时增加摩擦或者推迟发货?
调查问题: 哪些证据能区分盗卡、账户接管、促销滥用、评分模型退步和跨账户的协同?
这次调查经历了多轮假设。每一轮都留下了三样东西:它解释了什么,没有解释什么,下一轮凭什么有资格出现。
风控的决策目标,不是尽快给每个对象定性#
欺诈控制同时面对两种错误:漏放会造成资金、信任和合规上的损失;误伤会拒绝正常用户,给他们制造不公平的麻烦,还会污染以后的证据。标签又常常晚于价值的转移,所以“等完全确定再行动”和“先大面积封禁再说”都可能失败。
| 决策上的张力 | 一端的风险 | 另一端的风险 | 本案的选择 |
|---|---|---|---|
| 漏放 vs. 误伤 | 损失继续扩大 | 正常用户被拒绝或被调查 | 几类信号同时出现才加摩擦;摩擦选轻的,不直接拒绝 |
| 快速止损 vs. 等证据成熟 | 标签来得太晚 | 过早行动,把相关当成因果 | 止损和识别分成两条线,分别入账 |
| 规则透明 vs. 对手适应 | 缺少监督和复核 | 具体的阈值被对手拿去研究怎样绕过 | 原则可以审计,细节受控,独立复核 |
| 押一条规则 vs. 分层防御 | 押错一个模式 | 多层控制带来成本和摩擦 | 同时管理发货的暴露、关系检测和反馈的延迟 |
所以在风控里,“决策充分”常常先于“完整的归因”:只要证据足以支持一个范围有限、可以撤回、误伤受控的动作,就可以先减少无法挽回的损失;但不能把被控制的对象自动写成已经确认的欺诈者。
先缩小损失,不把止损写成结论#
事故负责人先启动了既有的欺诈响应流程:限制高风险商品的即时发货;保全原始的授权、登录、订单和申诉记录;缩小调查数据的访问范围;把对外沟通交给获得授权的风险和法务人员。
团队没有按国家、设备类型或账户年龄做大面积封禁。这些维度未必无关,但单一的属性既缺乏区分力,又容易造成严重的误伤。
止损和识别是两条线。临时推迟发货可以减少损失,却不能证明“发货速度就是攻击的原因”;暂停某类交易可以保护系统,也不能把所有被暂停的对象都写成欺诈者。
第零轮:是真实的攻击,还是账务和标签变了#
这一轮甚至没有讨论攻击者。团队先怀疑观察系统本身。
两周前,平台刚调整过拒付的回填逻辑;如果同一笔申诉被重复计入,或者成熟日期被错误地归到交易日期,仪表板上也会突然出现“三倍的损失”。
这个解释要求看到:收单机构的原始争议记录和内部账本无法逐笔对上;异常主要来自某一个回填批次;客户申诉和实际发货的损失并没有同步增加。
审计的结果是:新的回填逻辑确实让损失曲线看起来更陡,但解释不了主要的增量。收单机构的原始争议、客户的未经授权申诉、商品发货记录和退款账本,能够互相对上。
所以,团队只写下了一个局部的更新:
测量与回填问题:解释了异常“什么时候被看见”的一部分,
但解释不了实际的未经授权损失为什么增加。
如果跳过这一步,后面所有完整的攻击故事,都可能只是在解释一个仪表错误;如果因为发现了一点口径问题就停止调查,又会把真实的损失放着不管。
第一轮:是不是传统的盗卡测试#
未经授权的交易增加,最自然的解释是:盗来的支付工具先被用于小额试探,然后用于更大的购买。
这个解释并不空泛。它要求一组相对具体的现象:失败授权和重复尝试明显增加;同一个支付工具在短时间内跨多个账户或商品反复出现;新账户和小额试探比长期账户更突出;成功的交易之前,留下较密集的失败记录。
实际数据只满足其中一部分。确实存在被盗的支付工具,但总体失败授权率接近基线;多数支付工具只出现一次;成功交易的金额分布,也不像从小额逐步放大的试探序列。而且,大量损失来自有正常历史的账户。
团队没有把“盗卡”删掉,因为未经授权的资金来源仍然重要;被削弱的,是一个更具体的版本:
- 被削弱的主张: 这次损失主要来自一批可以在单笔授权记录中识别出来的传统试探行为。
- 仍然保留的主张: 攻击链中包含被盗的支付工具,但它们可能被分散到别的账户和时间里使用。
第一次更新没有找到答案,却留下了一个残差:为什么支付工具彼此分散,账户本身又看起来可信?
第二轮:是不是账户接管#
长期账户突然出现未经授权的订单,很像账户接管(Account Takeover,常简称 ATO):攻击者拿到了已有账户的访问权,借用它的历史信誉完成购买。
这个解释要求:登录或账户状态先发生变化,例如异常的找回密码操作、新的会话、与历史不一致的设备或地区;原来的账户主人随后报告不认识这些行为。
调查发现,约三分之一的案例符合这个形态:交易之前出现了新的会话或找回操作,客户确认账户曾经失去控制。对这部分损失,账户接管是得到较强支持的解释。
但剩下的多数案例没有可见的凭据找回、登录失败或会话迁移;有些客户仍然能正常使用账户,只是否认那些订单。团队也检查了“会不会是遥测漏掉了会话变化”,但不同的日志来源给出的结论大体一致。
所以,第二轮的更新是:
账户接管:解释了一个重要的子集;
解释不了没有认证异常、却在相近时间出现的其余损失。
这一步防止了一个常见的错误:因为账户接管在部分案例中确实成立,就把所有长期账户的损失都写成同一种机制。
第三轮:是不是促销或某类商品被滥用#
损失集中在即时发货、容易转手的数字商品上,于是第三个解释出现了:也许某个促销、某家供货商的配置或者某个商品流程被系统性地滥用了。
如果促销是主要原因,损失应当围绕同一个优惠码、价格边界或优惠资格聚集;如果某家供货商的配置有漏洞,暂停这家或修复配置以后,攻击应当明显收缩;如果商品类型只是偶然相关,换到价值相近、发货方式不同的商品以后,损失的形态不应该稳定存在。
团队停用了相关的促销,并检查了供货商的配置。促销滥用确实存在,但只覆盖很小的一部分;损失继续出现在多家供货商和不同的商品上。真正稳定的共同点是:价值可以在可靠的标签出现之前迅速离开平台。
回看变更时间线,团队还发现了一件事:异常出现前几天,平台刚放宽了即时发货的资格。原来只有过去一年稳定消费、从来没有过争议的账户才能即时发货;新规则改成了“注册满 90 天,并有过至少三次正常购买”。这个变化和“为什么偏偏是现在”相容,也和“为什么损失集中在老账户”相容。团队据此写下了一个可以检验的预期:如果放宽资格是触发器,损失账户里应当有很大比例,正是在规则放宽以后才获得即时发货资格的账户。核对的结果是约四分之三。
但这个变化只能说明损失为什么在这几天开始。它说明不了之后交易为什么反复集中在几个很短的时间窗口里,也说明不了许多看似无关的账户,为什么行为顺序相似、兑换去向相同。它更像触发器,而不是完整的攻击机制。
于是,商品和发货流程被重新分配了角色:
- 不是主要的协调机制:它说明不了之后反复出现的集中时间窗口、相似的行为顺序和相同的兑换去向;
- 是选择条件:攻击偏爱可以快速转手的价值;
- 是放大器:在标签到来之前,发货已经无法撤回;
- 放宽资格是触发器:它让一批老账户在同一时间够了即时发货的资格。
第三轮把“攻击为什么损失这么大、为什么是现在”解释得更好,却仍然没有解释“攻击是怎样组织起来的”。
第四轮:是不是新的评分模型退步了#
新的风险评分模型在异常出现前不久上线,所以它自然成了组织里最容易被接受的解释:新版本给出的风险分偏低,原本会被拦下的交易被批准了。
团队冻结新旧两个版本,在相同的历史快照上做离线重放,逐项检查特征缺失、分数校准和决策路由。结果是:旧模型对这些交易也大多给出了低风险。新版本改变了少量边界上的决策,但远不足以造成三倍的损失。
这意味着,问题出在别处,不是“新模型忘了一个旧信号”。两个版本都在做同一件事:主要按单笔交易和单个账户来判断风险。当前没有解释的现象,是单个账户看起来没有明显异常。
问题在这里被改写了。原来的问题是:“哪一个账户信号失效了?”新的问题是:“是否存在一种关系,只有把许多账户、支付工具和发货去向放在一起看时才会出现?”
这叫改变分析单位:承认攻击可能根本不以单个账户为单位发生,而不是继续给单账户的模型加特征。
第五轮:残差迫使团队从看单个账户转向看账户之间的关系#
到第四轮结束,仍有五个现象没有被同一个解释同时说明:
- 账户大多有一定的年龄,也有正常的历史;
- 单个支付工具、设备或网络位置很少高频重复;
- 交易却反复集中在几个短的时间窗口里;
- 账户在较长的安静期之后,以相似的顺序完成登录、浏览、下单和收货;
- 一些直接的标识不断变化,但兑换码最终的去向(收货邮箱、兑换账户)反复落在少数几组关系里。
团队在获得批准的环境中,把去掉身份信息的账户、会话、支付工具、设备关系和兑换码去向组织成一张关系图。图里的一条连线不代表犯罪,也不代表两个账户属于同一个人;它只表示两个对象之间有一个需要进一步审查的关系。
flowchart LR
P1["支付工具组 A"] --> A1["长期账户 1"]
P2["支付工具组 B"] --> A2["长期账户 2"]
P3["支付工具组 C"] --> A3["长期账户 3"]
A1 --> S1["会话 / 设备关系簇 X"]
A2 --> S1
A3 --> S2["会话 / 设备关系簇 Y"]
A1 --> F1["兑换去向组 M"]
A2 --> F1
A3 --> F1
T["相近的激活窗口"] -.协调.-> A1
T -.协调.-> A2
T -.协调.-> A3
单看任何一条连线都很弱:家人可能共用设备,网络地址可能属于公共出口,兑换去向也可能来自正常的代购服务。有区分力的是:几条弱信号在时间上和结构上一起出现,而且在已经确认的损失中反复出现。
团队找到的不是某一个“坏 IP”或“坏国家”,而是一种稳定的关系形态:一批长期、局部看起来正常的账户,在较长的安静期之后,于相近的时间窗口被集中激活;支付工具和直接标识被分散使用,让任何一个对象都不容易越过阈值;但跨账户的会话关系、行为顺序和兑换去向形成了重复的结构。攻击把一个网络级的行为拆成了许多局部正常的行为,而防御系统主要按单笔交易和单个账户打分。
可以把当前最好的解释压缩成一条链:
长期脆弱点:风控以交易 / 账户为主要分析单位,关系和时序的信号弱
+
可用资源:一批事先注册、维持少量正常消费、等着够资格的长期账户,
一部分被接管的账户,以及被盗的支付工具
+
触发器:即时发货资格放宽到“注册满 90 天 + 三次正常购买”
↓
在多个账户之间分散行动,让每个账户的风险都保持在正常范围
↓
多个账户在相近的窗口里,协调完成购买和兑换
↓
欺诈通报、申诉和拒付滞后
↓
在系统拿到可靠的标签之前,损失已经无法撤回
问题出在尺度上:攻击组织起来的尺度,和防御观察的尺度不一致;规则的阈值本身并没有设错。发货速度和标签延迟,又把这种不一致放大成了实际的损失。
第六轮:怎样确认这张图不是事后拼出来的#
关系图特别容易产生事后的过度拟合。只要先看过所有坏案例,总能找到一些共同的连线。所以,团队不能把“图看起来像一个团伙”直接写成结论。他们做了四件事。
第一,冻结模式的定义。 在查看下一批标签之前,先写清需要哪些关系、时序和行为顺序;结果出来以后,不得随意增删条件。
第二,用没有参与建模的时间窗口来检验。 冻结的模式以影子模式运行在随后十天的新交易上,只记录、不执行。标签到来以后,结果是:被标记的订单约占已批准订单的 1.7%,覆盖了约 58% 的确认损失;被标记的订单里,事后确认为未经授权交易的约占十分之一。作为对照,团队也试了一条单账户规则:“沉寂超过 30 天的老账户,首次购买即时发货的商品”。它能覆盖相近比例的损失,但会标记约 8% 的订单,其中确认为未经授权交易的约占五十分之一。
这组数字也要和前面对上。损失是基线的三倍,所以当前的损失里,大约三分之一是平时就有的背景欺诈,关系模式本来就不该覆盖它们;账户接管解释了约三分之一的案例,其中一部分账户后来被用进了同一批协调行动,另一部分是单独的接管,不在模式里。58% 的覆盖率,和“模式主要抓住了新增的那部分损失”是相容的。
第三,引入失败方式不同的证据。 独立的复核人员在不知道图分数的情况下,检查原始申诉、账户活动和发货记录;客户的未经授权确认、收单机构的争议和关系模式大体相容。某个特征单独出现时,不算作攻击的证据;只有几类来源同时满足时,才进入处置。
第四,做一次有区分力的前瞻验证。 被标记的订单里,大约九成来自正常用户,所以处置只能是轻的摩擦:平台按批准的流程,对满足多重关系信号的一小部分交易加了一步二次确认,或者推迟发货。这一步本身当然会减少损失,所以“损失下降了”不能证明机制。更有区分力的,是二次确认的失败形态:如果被标记的主要是零散的正常用户,失败应当零星、分散;如果是协调行动,失败应当成批地出现在同一组关系和同一个时间窗口里。结果是后者:九成以上的放弃集中在少数几个关系簇里,而且往往在几分钟内一起发生;被标记的正常用户大多顺利通过了确认。同时,平台监控了正常批准率、申诉、人工审查负担和客户抱怨,都在批准的范围之内。
团队还讨论过,要不要留一小部分被标记的交易不加摩擦,作为对照,以便准确测量效果。这样做能得到更干净的证据,代价是明知可能是欺诈也要放行。最后,他们只在金额很低的商品上保留了一个很小的对照组,并由风险负责人签字批准。
这组结果支持“跨账户协调是主要机制”这个工作解释,但仍然不能证明所有相关账户属于同一个真实身份,也不能证明图里的每一条连线都有因果意义。
攻击者开始适应以后,解释也要继续接受检验#
防御上线以后,直接的共享关系很快减少了。如果团队把某个设备簇或兑换去向当成永久的黑名单,模式会很快失效,还会误伤正常用户。
但更抽象的结构仍然存在:长时间的低活动,相近窗口里的集中激活,跨账户相似的行为顺序,价值迅速离开,以及标签反馈慢于攻击的转移。这说明,承重的是“分布式的协调 + 每个账户看起来低风险 + 反馈延迟”这个组合,具体的标识只是它的表面。
在对抗的环境里,要优先寻找对方改不了、或者改起来代价很高的约束。直接的标识最容易变:设备、网络位置、账户组合和兑换去向都可以轮换。更承重的,是攻击者为了达到目的不得不承担的东西:
- 必须获得或准备什么资源。在这个案例里,是够资格即时发货的老账户;按放宽后的规则,准备一个这样的账户,至少要 90 天和三次真实的购买;
- 必须经过哪些绕不开的业务步骤;
- 必须怎样在多个账户之间协调;
- 必须在什么时间窗口内把价值转出去;
- 哪些延迟、成本或失败的概率,会让攻击不再划算。
所以在对抗的环境里,hard-to-vary 不只问“哪个字段长期稳定”,还要问:当表面的特征全部轮换以后,对方如果还想得到同样的收益,哪些结构上的成本和时序约束仍然存在?这也给出了一个比封设备更持久的防御方向:让即时发货的资格依赖对方难以批量伪造的东西,而不只看账户年龄和购买次数。
这些约束也不是永远不变的。控制上线以后,攻击者可能换目标、换资源、换算账的方式,所以它们同样需要版本、有效期和复核条件;只是比起某个具体的 IP、设备或账户,它们通常更接近真正承重的部分。一旦控制被公开或者被推断出来,对方就会改变做法。所以,模式要有版本、适用期和复核条件;具体的信号、阈值和调查材料,不应该写进面向所有人的公开文档。
前几轮假设各自解释了什么#
回头看,前四轮分别处理了最终解释里的不同部分:
| 轮次 | 当时最强的解释 | 它解释了什么 | 它没解释什么 | 最终的位置 |
|---|---|---|---|---|
| 0 | 账务或标签变化 | 为什么曲线突然变陡 | 实际的未经授权损失 | 测量层面的部分原因 |
| 1 | 传统盗卡测试 | 资金工具为什么未经授权 | 失败率低、长期账户、使用分散 | 攻击的输入之一,不是主要的组织方式 |
| 2 | 账户接管 | 一部分长期账户为什么异常 | 多数没有认证异常的案例 | 重要的子机制,也是账户的来源之一 |
| 3 | 促销或商品滥用;资格放宽 | 攻击为什么偏爱某类商品,为什么是现在 | 跨供货商、跨账户的协调 | 选择条件、放大器和触发器 |
| 4 | 评分模型退步 | 为什么团队首先怀疑防线变了 | 旧模型同样漏判 | 被削弱;暴露了分析单位的问题 |
| 5 | 跨账户的关系与时序协调 | 局部正常、整体异常的共同形态 | 真实的身份和全部的参与方式 | 当前最好的工作解释 |
每一轮都让没有解释的部分变得更窄、更具体。
最终入账:原因不止一个#
调查记录最后没有写“某个设备、地区或模型版本是根因”,而是把因素分到了不同的角色:
- 长期脆弱点:风控主要以交易和账户为分析单位,跨账户的关系和协调时序不足;
- 可用资源:事先准备或被接管的长期账户、被盗的支付工具、可以轮换的直接标识;
- 触发器:即时发货的资格放宽,让一批老账户同时够了资格;
- 中介:多个账户在相近的窗口里分散地完成购买;
- 放大器:无法撤回的发货快于欺诈通报、申诉和拒付;
- 症状:成熟的损失曲线突然上升,而实时风险分布看起来正常。
行动也分层入账:
立即动作:缩小无法撤回的发货暴露,保全证据,对满足多重关系信号的交易加轻的摩擦。
短期动作:引入关系和时序层面的检测,用多类信号、而不是单一属性决定是否处置。
长期动作:让风险判断同时覆盖交易、账户、关系和时间窗口几个尺度;
缩短可靠反馈的延迟;让即时发货的资格依赖难以批量伪造的信号,并单独设风险预算。
未决问题:账户有多少来自接管、多少是事先准备的、多少来自其他渠道;
控制改变以后,攻击者会转向哪些商品和发货路径。
复核条件:模式的命中率或误伤率明显变化;发货资格的规则再次调整;
出现新的兑换去向或新的账户来源。
本案做到了哪一步#
本案没有达到路径完整:团队不知道每一个真实身份、账户来源和全部攻击链。跨账户协调这条机制,在冻结模式、留出时间窗口、独立复核和有区分力的前瞻验证中得到了支持,所以达到了机制获得支持。轻的摩擦和发货控制,收益和误伤都在监控之下,所以对这些有限的动作是决策充分的。对“按关系簇直接封禁账户”这样的动作,证据仍然不够:被标记的订单里,九成来自正常用户。
用五个动作和决策线回看本案#
- 定题:解释的是“长期低风险账户里真实损失上升、局部指标却稳定”这个形态,而不是笼统的“欺诈为什么上升”。
- 立敌:先后认真展开测量错误、盗卡测试、账户接管、商品滥用、评分模型退步和跨账户协调,没有让最终的解释从一开始就享有特权。
- 摊牌:每一轮都写出失败授权、认证事件、促销边界、版本重放和关系时序上的不同预期;放宽资格这个触发器,也用“损失账户里有多少是新获资格的”检验过。
- 试探:核对原始账本,独立确认客户,冻结模式后用留出时间窗口检验,再用二次确认的失败形态做前瞻验证;没有一看到关系图就全量封禁。
- 入账:保留账户接管、发货速度和标签延迟的局部贡献,把“分析单位不匹配”写成系统的脆弱点,并给模式设了版本和复核条件。
- 决策线:止损和识别分开,各按自己的时限;按关系模式的精度,只选轻的摩擦,不直接拒绝。
这次调查没有找到一条永远有效的规则。它保住的是一种能力:当对方故意让每个局部都显得正常时,团队仍然能换一个尺度看问题,让分散的事实重新组成一个能被现实检验的解释。
第五部 让团队拥有纠错能力#
第十四章 团队共用一份判断记录#
怎样把个人的推理变成团队可以一起纠错的结构,同时不让流程和模板取代思考?
读完应能:
- 设计逐层展开的记录、角色分离和独立的停止权;
- 让评审先写明环境和本轮目标,并允许“目前无法区分”成为合格的产出。
个人可以在脑子里同时保留几个解释,团队却不能依赖每个人的记忆。没有共同的记录,讨论很快会退化成地位、表达能力和事后印象的竞争;记录太重,又会把思考变成填表。
更好的办法,是只用一份案例记录,按风险逐层展开。低风险、可以撤回、反馈快的问题,只需要写清现象、当前的决定、主解释、一个有力的竞争解释、下一步和复盘日期。需要多人协作时,再补上测量假设、证据来源、可以并存的机制、关键分歧和负责人。高影响、难以撤回或者反馈很慢的决定,才继续展开最好与最坏的情形、不行动的风险、数据治理、审批、行动中止和治理升级。
风险上升时,前面的材料可以直接沿用,不必在几份相似的文档之间反复抄写。判断账本只记录状态变化,也不复制整份案例。工作手册第三部分给出了这份记录的全部字段,第四部分用三个案例各填了一份。
先写明环境和本轮目标#
一次评审开始时,除了确认风险和问题类型,还应写下环境和本轮目标:
系统能封闭到什么程度:基本能 / 部分能 / 很难
参与者会不会调整做法:基本不会 / 会适应 / 针对我们
当前环境:相对可封闭 / 开放适应 / 对抗适应 / 混合
本轮目标:路径完整 / 机制获得支持 / 足以支持某个具体的动作(写明是哪个)
这几行能防住两种相反的错误:要求商业问题交出一条像程序调用链那样完整的路径;或者因为世界是开放的,就允许任何故事长期不承担可以观察的后果。环境判断可以被后来的证据修改,但不能省略。
一次有效的解释评审#
评审会不是从零开始发现真相的地方。会前至少要有一页材料:原始数据或时间线、解释对象的草稿、当前必须作出的决定,以及每位参与者各自独立写下的一个解释和他最怕看到的一项观察。先让大家独立地写,是为了减少地位带来的影响:第一个开口的高管,不该决定房间里有哪些候选。
一小时通常足够完成一轮轻量的评审,顺序是:先定题,再立敌,再摊牌;然后对这次会上到了时限的决定做决策;最后只定下一步的试探和复盘日期。工作手册第六部分给出了逐段的时间分配和主持人的话术。材料不足时,合格的产出可以只是一项补充证据的任务。强迫会议给出结论,通常只会奖励最会讲故事的人。
会议结束时,允许保留未决#
一次评审可以有三种合格的产出:带范围和触发条件的有限行动;写明证据强度、适用边界和复核日期的暂时判断;明确写下“目前无法区分”,并安排一项真正能提高分辨率的工作。
不合格的产出只有一种:因为大家已经讨论过了,就把仍然没有区分开的几个解释包装成“已经找到根因”。流程要做的,是让确定和不确定的部分都被如实记下来,不必逼出确定性。
角色的目的,是暴露利益冲突#
一次重要的评审,至少要有人承担以下几项职能:把住问题的边界;认真展开竞争解释;审查数据和测量;作出业务上的决定;拥有行动的停止权。
这些职能不一定由五个人承担,但冲突不能被藏起来。执行者天然希望项目成功;项目负责人如果同时掌握指标定义、结果解读和停止权,在不利信息出现以后就更容易继续加码。第十一章把恢复的停止权交给值班负责人,而不是发布负责人;第十二章把试验的停止权交给支持与隐私负责人,而不是产品负责人,都是同一个原因。
设独立的停止权,和信不信任执行者无关,它承认的是激励结构。
把分歧从人身上移到解释上#
当解释牵涉到责任、预算和声誉时,直接说“你的故事站不住”通常只会让人防御。更有用的说法是:
解释 A 和解释 B 对接下来两周有不同的预期。我们先找一个风险可控的观察。如果 A 被削弱了,下一步怎么变?如果 B 被削弱了,又怎么变?
这句话把争论从“谁更聪明”移到了“现实会迫使哪条主张改变”。
但说话的技巧消除不了权力。团队至少要认清,自己的讨论处在哪一种场合。在以求真为主的场合,参与者大体愿意让证据修改判断;在谈判的场合,解释同时在分配资源、责任和声誉;在身份被锁定的场合,提出竞争解释可能被理解为敌意;在欺诈调查、安全审计和尽职调查这类有对手的场合,对方甚至会主动适应你的检查方式。
越接近后几种场合,证据的来源路径、权限分离和正式监督就越重要。不能只靠“大家开放讨论”。
记录也有边界#
判断记录应当放在组织批准的系统里,按需要限制访问,并遵守目的限制、最少收集、保留期限和审计的要求。
访谈原话、录音、客户信息、员工评价、欺诈线索和安全证据,都有各自的授权和保全规则。“为了学习”不是未经授权收集信息、或者建立私人影子档案的理由。遇到举报、骚扰、违法或重大风险的线索时,应当进入受保护的正式渠道,而不是继续留在普通的解释评审里。
本章要点#
- 共同记录的价值,在于保存分歧、事前预期和状态变化,而不是产生更多文档。
- 角色分离是在承认激励冲突,尤其要保护证据来源和停止权。
- 评审先写明环境和本轮目标;“目前无法区分”是合格的产出。
- 为你下一次团队评审指定主持人、竞争解释负责人、证据审查者、决策者和停止负责人。有没有哪个人同时占了两个会产生冲突的位置?
- 写下本轮的环境和目标,再检查团队是不是在暗中要求更高或更低的标准。
第十五章 这套方法会怎样失败#
这套方法进入真实的组织以后,会以哪些方式被滥用、变成仪式,或者反过来成为逃避判断的借口?
读完应能:
- 识别假装封闭、以复杂为借口、过早收紧、指标反噬和权力阻断;
- 判断什么时候该完整地使用这套方法,什么时候应先行动、后复盘,或者交给专业的流程。
任何方法一旦被组织采用,就会开始服务于组织的激励。它原本用来纠错,后来可能只剩下表格、术语和仪式。
把开放世界当成封闭系统#
在商业、组织和对抗的问题中,最常见的过度自信,是把一次局部试验、一个回归模型或一张关系图写成完整的历史路径。它忽略了没有观测到的共同原因、制度的变化、外推的边界和参与者的适应。
修正的办法是缩小主张的范围,机制仍然要讲:写明适用范围、做到了哪一步、残差、有效期和复核条件。一个得到支持的局部机制,仍然比一个宏大却经不起检验的故事更有用。
用“世界太复杂”为任意的故事开脱#
相反的失败同样危险:因为系统是开放的,就说任何解释都只是观点,于是不必写方向、时序、边界或反例。
开放增加了识别的难度,却没有取消约束。一个解释仍然要说明:它在什么条件下成立,会留下什么可以观察的后果,什么结果会削弱它,以及为什么新加的边界不是事后的补丁。开放世界要求的,是有条件的 hard-to-vary,而不是放弃判断。
收紧得太早,会扼杀探索#
hard-to-vary 适合比较已经成形的候选解释,不适合在探索刚开始时淘汰所有模糊的直觉。
新的问题常常先以异常感、比喻、经验判断或不完整的语言出现。这时需要观察、访谈、阅读和自由联想,让变量和边界慢慢出现。如果一开始就要求每个想法都给出完整的机制和可以检验的预期,团队会偏爱那些容易说清楚的旧概念,错过新的问题。
探索阶段允许解释暂时容易变;进入比较和行动阶段以后,再逐步收紧约束。两个阶段不能用同一个标准。
结构太多,会让流程代替思考#
如果一场评审没有带来新的区分方式,没有改变下一步,也没有暴露隐藏的假设,只是让文档变长了,它就没有创造足够的价值。
低风险、可以撤回、反馈立刻可见的小动作,不需要完整的流程。专家在高度重复、反馈充分的场景里形成的直觉,也不必每次都拆成因果图。紧急的事故先按应急手册处置,稳定以后再做结构化的复盘。
结构的目的,是降低重要错误的概率,不是让所有判断看起来都一样正式。
表格会漏掉难以表达的现实#
表格、指标和因果图天然偏爱可以拆分、可以计数、可以命名的东西。它们会让容易表达的问题显得更重要,也可能把真正关键、却暂时难以量化的东西挤到边缘。
一个团队评估是否继续和一位联合创始人合作,可以列出交付准时率、招聘转化率和开会的响应速度。但决定合作能否继续的,往往是另外几件事:对方在压力下会不会歪曲事实,会不会提前暴露坏消息,利益冲突时会不会维护大家共同认可的事实。
这些东西不是不能讨论,只是不能因为暂时放不进表格,就假装它们不存在。每次建模之前,都值得问一句:图里没有的东西,是不重要,还是我们还没找到合适的语言?
指标会取代原来的目的#
如果组织把“探针区分率”“解释被推翻的比例”或“按时复盘率”直接设成绩效指标,参与者很快会去优化这些数字。只挑简单的问题,可以提高区分率;为了显得开放而故意修改解释,可以提高“被推翻的比例”。
这就是 Goodhart 定律描述的反作用。Goodhart 在 1975 年的原话是:任何观察到的统计规律,一旦被用于控制的目的,就会趋于失效。更流行的说法“当一项度量成为目标,它就不再是一项好的度量”,来自人类学家 Marilyn Strathern 1997 年对英国大学评估制度的批评。
复盘应当先看具体的案例:哪些竞争解释后来证明被漏掉了?哪些停止条件触发了却没有执行?哪些案例长期没有结果?流程的成本和风险是否相称?统计数字可以辅助,但不能代替逐案的判断。
组织可能不允许纠错#
好解释不保证会被采纳。如果组织奖励隐藏坏消息,惩罚承认错误,让项目负责人独占证据和停止权,任何方法都会变成仪式。
这时要问的,是现实反馈有没有权力改变行动;把论证写得更有力,帮助不大。如果没有这种权力,继续加强论证,可能只会让提出异议的人承担更多的风险。
合理的做法有时是:保留正式的记录,降低个人和系统的暴露,寻求合法的独立监督,或者离开一个无法纠错的环境。
反过来看:什么几乎一定会失败#
从失败倒推,下面这些做法尤其危险:
- 先有结论,再找一个能被它解释的问题;
- 主解释写得很细,竞争解释只剩一句口号;
- 用报告的数量代替证据的独立性;
- 每次出现反例就加一个补丁,却从不降低对核心主张的信心;
- 在反馈慢、难以回滚时,一次性全量承诺;
- 让同一个人定义指标、解读结果、决定是否停止;
- 结果回来以后不更新原来的记录,只留下新的成功叙事。
这些错误来自不同的领域,却有一个共同点:系统没有给反对的信息留入口。
什么时候合上这本书#
下面这些场景不适合完整地走一遍流程:危险正在扩大,时间很短;动作低风险、可以撤回,反馈立刻可见;专家面对的是高度重复、反馈充分的熟悉模式;探索刚开始,变量和语言都还没有稳定;审美、关系和手艺里有大量暂时说不清的经验;干预不合法、不合乎伦理,或者超出了自己的权限。
合上书不等于放弃学习,只是把学习放到更合适的时候:可以先行动,事后再复盘;可以先观察,等变量稳定了再建模;也可以请有资格的人来判断。
本章要点#
- 两种相反的失败:把开放世界当成封闭系统;用“世界太复杂”为任意的故事开脱。
- 结构只在带来新的区分、有限的动作或明确的未决时才有价值。
- 组织如果不给不利信息改变行动的权力,再好的方法也会变成仪式。
- 回看一次失败的复盘:它更接近“把开放世界当成封闭系统”,还是“用复杂为借口逃避约束”?
- 找一个被当成绩效指标的流程数字,说明它可能怎样取代原来的目的。
结语 让不利的信息能够改变行动#
好解释不会让人从此不犯错。它能做的是:在相对封闭的系统里,让我们有机会重建结果是怎样产生的;在开放和对抗的系统里,让机制、适用范围、可以观察的后果和失效条件彼此约束。无论在哪种环境,它都要求竞争解释得到公平的机会,让证据能够改变具体的主张,也让行动的规模不超过我们当前知道的东西。
最难的时刻,通常在现实给出不利信息以后。这时要做的是几件具体的事:承认问题写错了,降低对一条因果关系的信心,停掉一个已经投入很多的动作,把“目前无法区分”写进正式的记录。这些事都有代价,而且代价通常落在提出原来判断的人身上。
所以,评价一个判断系统,要看它能不能让错误尽早出现,有没有人能够指出错误,以及错误出现以后,有没有权力改变下一步。
术语、技术旁注与延伸阅读#
核心术语#
“路径完整”“机制获得支持”“决策充分”,是本书为了区分实践中的完成程度而使用的工作术语,不是所有学科共用的分类。
解释对象(explanandum):这一次需要解释的现象、规律、差异、异常或者待证明的结果。
hard-to-vary(难以任意改动):一个解释在继续解释同一件事时,不容易被随意改动;关键细节一变,原来的解释就会受损,或者带来新的、可以被批评的后果。
延伸力(reach):一个为某个问题提出的解释,不加改动,就能在别的问题上继续起作用。
工作解释:足够具体、可以被比较和批评,但仍然允许随新证据修订的暂时解释。
竞争解释(rival):和主解释解释同一个对象、同样具体,并且一旦成立,会改变相对判断或下一步行动的候选解释。
事前验尸(premortem):假设一段时间以后证明主解释错了,写出最可能的原因。它是产生竞争解释的一种办法。
差异化预期:不同的解释,对方向、幅度、时序、边界或中间过程作出的不同要求。能把两个解释拉开的观察,才有区分力。
基础比率:这一类情况以往通常怎样。它决定判断从哪里出发;差异化预期决定证据把判断推多远。
残差:当前的解释处理完以后,仍然没有得到解释的重要现象。
免疫策略:不断增加辅助的假设,让核心的主张对任何不利的信息都免疫。
分析单位(unit of analysis):推理中被当作一个对象来观察和比较的单位,例如一笔交易、一个账户、一个团队、一组相互关联的账户或一个时间窗口。选错时,每个局部都可能正常,整体的机制却看不见。
环境的两个问题:系统能封闭到什么程度;参与者会不会调整做法,是否针对我们。两个回答组合起来,常见的有相对可封闭、开放适应、对抗适应和混合四种环境。
相对可封闭系统:在当前的问题中,主要的边界、状态和干预可以暂时固定,生成机制可以通过代码、仪表、重复运行或受控比较继续接近的系统。“封闭”是相对于当前任务而言的暂时状态。
开放适应系统:重要的原因可能来自边界之外,机制只能部分观察,而且人、组织、市场或攻击者,会根据观察、激励和干预改变行为的系统。
混合系统:一部分机制可以通过代码、流程和日志检查,另一部分来自不能完全观察、而且会适应的参与者。欺诈同时包含可以检查的交易系统,和会主动转移的攻击者。
有条件的 hard-to-vary(conditional hard-to-vary):在写明的人群、时间、制度和环境下,机制、适用范围、预期的现象和失效条件之间的关系,不能在看到结果以后被免费改写。
条件不变性(conditional invariance):参数可以随环境变化,但一条机制在事先说明的条件下,仍然保持方向、时序、边界或中间过程上的结构。
局部封闭(local closure):在开放的世界里,暂时固定人群、时间窗口、版本、流程或观察方式,让一个关键的分歧,能在相对稳定的环境里接受检验。
路径完整(trace-complete):能够重建某一次结果的主要生成路径,并指出改变哪一步,会让后面的状态和输出不同。它始终相对于当前的解释对象、版本和观测的覆盖范围。
机制获得支持(mechanism-supported):不能重建全部的生成路径,但一条机制受到时序、中间过程、跨环境比较或多种独立证据的共同约束,并在限定的范围内反复出现预期的现象。
决策充分(decision-sufficient):现有的证据,足以支持某一个写明范围的动作,或者足以排除某个承受不起的动作。它总是针对具体的动作,描述的是行动的资格,不是真理的等级;机制还没有被唯一识别时,它也可以成立。
决策线:和五个动作并行的决策。每到一个决定的最晚时间,或者某种损失变得承受不起时,用当时的判断,在稳健动作、信息动作和承诺动作之间选择一次。
稳健动作:在几种仍然可能成立的解释下,都能减少明显的伤害、保留选择或改善观测的动作。
信息动作 / 承诺动作:信息动作的主要价值,是减少会改变决策的不确定性;承诺动作代价高、难以撤回,或者只在一部分解释下合理。
探针(probe):为了减少一个会改变决策的关键不确定性,而设计的观察、反例、复核、仿真或安全的干预。
负对照:按理不应受到影响的对象。如果它也出现了同样的变化,原来的关系可能只是巧合,或者是测量的问题。
对抗性适应:对方会根据已知或推断出的控制改变行为,所以规则和模式必须有版本、适用期和复核条件,不能把某个具体的标识当成永久的规律。
有效期与复核条件:一个解释,在哪段时间、哪个版本、哪类人群和环境内暂时有效;出现哪些产品、政策、指标、人群或对手行为上的变化时,必须重新评估。
判断账本:只追加、不覆盖的记录,保存事前的判断、事前的把握、实际的结果和更新,用来防止记忆在事后被改写。
技术旁注:概率、压缩与解释#
差异化预期可以看成似然(likelihood)的日常语言版本:它衡量的是,如果某个解释为真,这项观察会有多意外。随意的自由度,也和贝叶斯方法里对复杂度的惩罚、或者最小描述长度,有相似的结构:一个能适配任何结果的模型,命中当前的结果时,并没有得到多少信息。
放到摊牌这一步,这个结构有一个直接的后果。一个什么结果都能容纳的解释,要把自己的预期分摊到所有可能的结果上,所以它对任何一个具体结果的预期都不高;另一个解释如果事先预言了某个具体结果,而这个结果真的出现了,两者的似然比就会明显偏向后者。能随意改动的解释,因此很难在证据面前胜出。David MacKay 的 Information Theory, Inference, and Learning Algorithms 第 28 章,用模型比较讲了同一个道理。
这种相似很有启发,但不是形式上的等价。hard-to-vary 关心的,是解释的关键细节怎样受问题约束;概率和压缩的方法,需要明确的模型空间、编码方式或概率分布。二者可以互相补充,不能互相冒充。
延伸阅读#
- David Deutsch, The Beginning of Infinity(中译本《无穷的开始》),第一章关于好解释、hard-to-vary 和延伸力的讨论,包括四季的例子。
- David Deutsch, “A New Way to Explain Explanation”,2009 年的 TED 演讲,hard-to-vary 的通俗讲解。
- Karl Popper, Conjectures and Refutations,第一章关于猜想、批评和反驳,以及他对 Adler 和 Freud 理论的回忆。
- Peter Lipton, Inference to the Best Explanation,关于竞争解释和最佳解释推理。
- T. C. Chamberlin, “The Method of Multiple Working Hypotheses”(1890),同时保留几个工作假设的早期论述。
- John R. Platt, “Strong Inference”(1964),列出备选假设、设计能排除假设的实验、再循环,是立敌、摊牌、试探、入账这个顺序的早期表述。
- Charles Kepner and Benjamin Tregoe, The Rational Manager(1965),用“是”和“不是”的对照写清问题,和第五章的定题相近。
- Gary Klein, “Performing a Project Premortem”(Harvard Business Review, 2007),事前验尸的做法。
- David MacKay, Information Theory, Inference, and Learning Algorithms(2003),第 28 章讲模型比较怎样惩罚能容纳任何结果的模型。
- John Snow, On the Mode of Communication of Cholera(第二版,1855),两家供水公司的比较。
- David Freedman, “Statistical Models and Shoe Leather”(1991),以 Snow 为例,说明细致的因果推理,为什么常常比复杂的统计模型更可靠。
- Ignaz Semmelweis, The Etiology, Concept, and Prophylaxis of Childbed Fever(1861),洗手的记录和他对解释的修订。
- Carl Hempel, Philosophy of Natural Science(1966),第二章用 Semmelweis 的调查讲假说的提出和检验。
- James Woodward, Making Things Happen,关于干预和因果解释。
- Miguel Hernán and James Robins, Causal Inference: What If,关于因果问题、数据和识别的假设。
- Richard Cook, “How Complex Systems Fail”,关于复杂系统的失败,为什么很少只有一个根因。
- Nancy Leveson, Engineering a Safer World,关于复杂的事故和控制结构。
- Donella Meadows, Thinking in Systems,关于反馈、延迟和系统的结构。
- Baruch Fischhoff and Ruth Beyth, “I knew it would happen: Remembered probabilities of once-future things”(1975),关于事后的回忆怎样向结果靠拢。
- Philip Tetlock and Dan Gardner, Superforecasting,关于怎样记录和校准自己的判断。
- Allan Murphy and Robert Winkler, “Reliability of Subjective Probability Forecasts of Precipitation and Temperature”(Applied Statistics, 1977),天气预报员的概率校准。
- Oskar Pfungst, Clever Hans (The Horse of Mr. von Osten)(德文原版 1907,英译本 1911),用只回答一个问题的检验,查明马读的是提问人的身体信号。
- R. W. Wood, “The n-Rays”(Nature, 1904),他在 Blondlot 的实验室里取走棱镜的经过。
- Report of the Presidential Commission on the Space Shuttle Challenger Accident(1986);Edward Tufte, Visual Explanations(1997)中关于发射前一晚的数据的一章;Siddhartha Dalal, Edward Fowlkes and Bruce Hoadley, “Risk Analysis of the Space Shuttle: Pre-Challenger Prediction of Failure”(1989);Diane Vaughan, The Challenger Launch Decision(1996)。
- U.S. Securities and Exchange Commission, In the Matter of Knight Capital Americas LLC, Release No. 34-70694(2013),Knight Capital 事故的官方调查结论。
- Gary Klein, Sources of Power;Michael Polanyi, The Tacit Dimension,关于专家的直觉和难以言传的知识。
- James C. Scott, Seeing Like a State,关于可读化、度量和对现实的遗漏。
V20 版本说明#
V20 在 V19 的课程结构、环境轴和欺诈案例之上,恢复了 V17 中更具体的案例和史料,并修正了几处逻辑问题。详细的修改理由,见 好解释-V20-修改说明。
- 三个案例的数字彼此对得上,可以验算:尾延迟案例写明了连接池的处理能力、超时的设置,以及灰度为什么看不见饱和;增长案例按广告渠道算获客成本,并把两个时间线不同的决定分开;欺诈案例补上了模式的精度,以及它和基线损失、账户接管之间的对账。
- 新增五个真实的例子,补上原来例子的两个缺口(调查中没有人按错误的解释付出过代价;历史例子都是少数派后来被证明正确):聪明的汉斯和 N 射线(第五章),挑战者号(第七、八章),Knight Capital(第八章),天气预报员的校准(第十章)。
- 恢复了四个真实的历史例子:Snow 的供水比较(第七章)、Semmelweis 的洗手(第九章)、Popper 与 Adler(第六章)、Fischhoff 与 Beyth 的事后回忆实验(第十章)。
- “路径完整 / 机制获得支持 / 决策充分”,改成了两个问题:解释做到了哪一步;证据够不够支持某个具体的动作。
- 第四章只讲环境和目标,开放世界的具体做法,分到了第五、七、八、九、十章,去掉了重复。
- 新增:没有出现的现象也是证据;基础比率;信息要在决定之前到达;小规模测不出总量问题;事前写下把握,以便校准。
- 第一至十章,每章增加了一道带参考思路的练习。
- 框架调整:决策改为和五个动作并行的一条线,在每个决定的最晚时间、或者损失变得承受不起时发生;环境改为用两个问题判断(系统能封闭到什么程度;参与者会不会调整做法),四种环境是两个回答的组合;第六章增加竞争解释的来源清单;第五章增加没有异常时的入口。
- 统一用语:“解释”不再和机器学习的“模型”混用;“合成探针”改为“合成监控”,避免和本书的“探针”混淆;第十四章讨论场合时用“场合”,不再和环境判断混用“环境”;“漂移触发器”改为“复核条件”。