激活可解释性这几年有点被当成“找机制”的快捷方式了跑一遍正常推理再跑一遍被改坏的推理然后把前者的激活塞回后者看答案能不能回来。代码很简单结论却很容易下过头。真正动手做几轮之后你会发现问题从来不是“怎么 patch”而是“patch 完以后我们到底敢说找到了什么”。这篇就围绕这个问题展开适合正在做模型可解释性、机制可解释性或者想复现电路分析类工作的朋友。先说清楚一件事Activation Patching激活修补本身是一个很漂亮、很直接的因果干预工具。它不靠梯度不靠注意力分数不靠激活值的绝对值大小而是直接问“如果我把某个中间状态换掉模型行为变不变”。这种“直接上手改内部状态”的思路比看热力图、看权重范数要硬核得多。但工具硬核不代表推论就成立。答案恢复了、分数上去了、电路图画出来了离“机制被找到”可能还有一整条街的距离。这篇博文想聊的就是这条街怎么走以及路上有哪些坑。1. 为什么“答案恢复”成了解释性的黄金标准先说背景。Transformer 内部动辄几十亿参数、几百个注意力头谁都想把“模型是怎么答对这道题的”给拆出来。早期的主流做法是看注意力权重注意力分数高的 token 被认为是“重要的”。后来大家发现注意力分数高不等于因果重要于是梯度类方法上来分一杯羹。再后来Redrock 那批工作把 Activation Patching 推到前台用它从语言模型里挖出很多清晰的“电路”。这套逻辑之所以流行是因为它符合最朴素的科学直觉你怀疑某个东西是机制的一部分那就把它拿走试试拿走以后结果变了说明它确实参与把它放回去结果恢复了说明你对它的理解至少在这一步是成立的。放到神经网络里“拿走”不是把参数删掉而是把某个位置上的激活向量替换成另一次运行里的值“放回去”就是把原值替换回来或者把另一个因果相关的值修补进去。“恢复答案”也因此成为最有说服力的证据之一它不是相关性而是干预。我改动了组件 A模型的正确率从 80% 掉到 20%我修补回组件 A 的正确激活正确率回到 75%。这个从 20% 到 75% 的跳跃比任何一张热力图都更有分量因为它能被观察到、被量化、被复现。但这里藏着一个关键盲区我们关注的是“恢复答案”这一个结果而不是整个修复过程背后的语义变化。说白了恢复答案可能有很多条路你修补的那个组件可能只是其中一条路上的一个开关也可能它压根不在这条路上只是你换进去的激活向量碰巧让模型进入了一种“更倾向于输出正确答案”的状态。我自己的体会是这种“碰巧”不是个例而是系统性的偏差。因为模型内部是分布式表征同一个行为往往由多个子网络支持。你单独换一个节点噪声太大模型扛不住于是错误率下降你再把另一个节点的激活填回去模型整体被“拉回”了正确状态于是答案恢复。看起来像是你找到了那条“损坏的电路”实际上你只是把整个系统推回了原来那个能够正常运转的吸引域。这个区别在真正的机制解释里是致命的。所以在动手做激活修补之前先接受一个判断“恢复答案”是一个必要不充分的证据。它可以帮你缩小搜索范围可以帮你提出机制假设但它不能独自证明“这个组件就是机制本身”。后面所有更严格的验证本质上都是在补这块短板。2. 激活修补的实际操作从干跑到修补既然要批判它就得先真的会用它。很多文章把激活修补讲得很玄乎拆开其实就是几个固定步骤。我按自己常跑的流程写一遍稍微有点基础的朋友可以直接照着搭。2.1 干跑、损坏跑和修补跑激活修补的核心是构造两种运行状态干净运行clean run和损坏运行corrupted run。干净运行就是正常的模型推理模型给出正确预测损坏运行则是故意把输入改掉让模型给出错误预测。然后你把干净运行的激活值替换到损坏运行的对应位置看预测能不能恢复。举个具体例子如果你想分析“The Eiffel Tower is located in”这个句子里模型是怎么知道答案是“Paris”的那么损坏输入可以改成“The Colosseum is located in”让模型从“Paris”跑偏到“Rome”。接下来你在损坏运行的某个中间层、某个注意力头或者某个 MLP 模块上把干净运行时的激活值替换过去。如果模型预测从“Rome”变回“Paris”这个位置就被判为因果相关。关键是要弄清楚“损坏”是怎么做的。最常用的是换 token 或换句子因为你改变的是输入的语义内容而模型内部的运算结构保持不变。另一种损坏方式是加噪声或者随机采样但噪声损坏很难解释清楚你“损坏”的到底是什么语义所以新人入门我建议先做 token 替换等熟悉了流程再考虑更复杂的噪声方案。2.2 修补的对象残差流、注意力头和 MLP在 Transformer 里可以修补的位置非常多。粗分下来有三大类残差流residual stream、注意力头输出attention head output和 MLP 层输出MLP output。这三者的语义层级不太一样修补时要根据自己的问题来选择。残差流是模型信息的“主干道”每一层的输入输出都在这里叠加。修补残差流影响往往很大因为它相当于直接改写了这一层看到的总信号。注意力头输出则是“信息筛选器”它决定了模型在某一层重点关注哪些 token 的信息。MLP 输出更像是“知识存储和变换”的地方很多事实性知识被认定存放在 MLP 里。实际操作里我习惯先做残差流的修补圈定大致范围再下沉到注意力头做精细定位。原因是残差流维度高、位置少扫描一遍成本较低定位很快注意力头数量多组合爆炸得靠残差流先缩小搜索空间。这个“先粗后细”的顺序几乎适用于所有 6B 到 70B 级别的 decoder-only 模型。2.3 从单点修补到路径修补单点修补的标准做法是固定一个中间层把该层所有位置的激活全部替换。这样做的好处是工程简单但问题在于你无法区分“这个位置重要”是因为它本身存储了信息还是因为它连接了上游的重要信息。这时候就需要做路径修补path patching。路径修补是一种更精细的变体它把干预限制在某一个计算路径上。比如你想看“token 2 经由 head 4 到 token 5”这条路是否存在你就可以先替换掉 token 2 的激活然后在 head 4 的输出位置把干净激活补回来观察 token 5 位置上的预测是否恢复。如果恢复了说明这条路径确实在传递 causally relevant 的信息。路径修补的计算成本比单点修补高一个量级但它提供的信息密度也高得多。你要画一个有向图式的电路几乎必须依赖路径修补而不是单点修补。我的经验是不要一上来就全模型扫描路径先做单点扫描找出 top-10 的关键节点再在这些节点之间做路径分析。这样既能控制算力又不至于漏掉主要机制。3. 答案恢复背后的三个理论陷阱这是整篇博文最想聊透的部分。工具本身没有错错的是我们在解读结果时经常犯的三个错误。没有任何一个错误是“致命”的但如果三个叠加在一起你的“机制解释”基本就是自说自话了。3.1 必要性不等于充分性修补实验最常下的结论是“这个位置是必要的”。这句话严格来说只对应于一种情况损坏这个位置导致行为改变。但我们经常想说的是“这个位置就是这个机制本身”这在逻辑上是一个大跨步。一个组件可以必要但不充分——它可能只在某个特定上下文中参与了该行为而该行为的真正“指挥官”在别处它也可能只是“放大器”没有它模型会失败但它本身并没有携带多少语义信息。我印象很深的一次实验是在某个数学推理任务里把某两个注意力头的输出同时换掉模型完全崩溃但单独修补其中任意一个头模型都能恢复得不错。从必要性的角度你可能会说这两个头都“重要”但如果你把其中一个头理解为“机制”就解释不了为什么去掉另一个头它也能恢复。这说明模型内部存在冗余或互补路径单点修补看到的可能只是冰山一角。所以任何结论都要说清楚这个头“在什么条件下、对什么行为、起到了什么程度的因果作用”而不是直接说“模型的某某能力位于这个头”。后者听起来有解释力但对于真正想理解模型的人来说几乎是零信息。3.2 修补的是激活不是语义激活替换实验里有一个隐性的前提假设不同运行里相同维度的激活值享有相似的“语义空间”。但神经网络的表征空间并不是固定不变的微小的上下文变化可能导致同一维度的含义发生偏移。给你一个反例思路你把干净激活替换进损坏运行模型答案恢复了。你猜原因是什么可能是你放进去的向量“补充了缺失的信息”但也可能是这个向量改变了损坏运行的总体分布状态把模型推出了一个错误的“局部吸引域”。换句话说它可能没有被模型当作“正确的语义”来理解而只是起到了一个“方向校正”的作用。这种情况在跨 token、跨位置的修补里特别常见。你修补目标位置旁边的激活跟修补目标位置本身的激活效果可能完全不一样因为“旁边”和“本身”在模型内部对应的语义角色完全不同。如果对修补位置的语义角色不清楚你看到的“恢复”很可能只是向量空间里的巧合。缓解的方法不是不做修补而是多做对照。比如你修补一个随机位置看它是否也能恢复答案。如果随机位置恢复效果和你的目标位置差不多那就说明你的“定位”根本没定位到语义单元上你只是随便找到了一个能影响输出的旋钮。补一组随机 baseline几乎所有结论的置信度都能提高不少。3.3 单一运行时快照的幻觉很多激活修补实验只用一两个输入样例比如经典的“IOI”任务或者“城市-国家”任务。这个层面上的操作当然方便但危险在于你在两个输入样本上观察到的“恢复”可能只是该样本的特有现象而不是模型内部稳定机制的一部分。举个例子你分析“公司的 CEO”指代消解任务发现某个注意力头负责把“CEO”的信息传递到“公司”上。看起来很合理。但换 50 个不同公司、不同 CEO 的句子之后你发现这个头只在其中 20 个句子里有显著效果另外 30 个句子靠的是别的头。如果你只看那 20 个句子你会画出一个漂亮的电路但它无法泛化。所以更严谨的做法是在一批样本上分别做修补统计恢复率或者说恢复幅度的分布。不要只报一个“能恢复”或“不能恢复”的二元结果而是报“有多少比例的例子恢复了、恢复了多少百分点”。这个分布信息比单点恢复的视觉效果重要得多决定你是否真的发现了一个跨样本稳定的机制。4. 更严格的验证框架别让“恢复”孤军奋战好的机制解释不能只靠激活修补一个证据。把激活修补放进一个多方法验证的框架里结论的可信度会高很多。下面是我自己比较常用的几个组合拳。4.1 反向干预破坏而不是恢复一个常见的验证方法是把方向反过来不看“损坏后修补会不会恢复”而是看“干净时替换成损坏激活会不会把正确预测打坏”。这个方向的干预同样很能说明问题。如果组件 A 是机制的一部分那么两件事应该同时成立损坏时修补 A 可以恢复答案干净时用损坏激活替换 A 会破坏答案。如果只满足前者而不满足后者你会怀疑 A 的“恢复效果”不是因果而是某种补偿机制——它只是把模型推回全局正确状态并不负责传递特定信息。实操时我会先做“破坏测试”再做“恢复测试”最后对比两组结果。只看恢复率容易高估一个位置的重要性同时看破坏率和恢复率才能对因果作用有更立体的感觉。一个被我反复验证过的现象是很多中间层位置“恢复率”很高但“破坏率”很低因为它们更像是一个全局的“状态调节器”而不是某个具体知识点的所在。4.2 跨样本和分布外验证前面提到不要只看一两个样本。这一条值得单独拿出来讲因为它是很多工作被审稿人打回去的主要原因。完整的验证至少应该覆盖三种样本同分布样本、近分布样本和明显分布外样本。同分布样本证明机制稳定近分布样本证明机制对输入扰动不敏感分布外样本则能帮你看到机制的边界。在模型解释里没有边界的机制几乎等同于没有机制因为你无法告诉别人“这个机制在什么条件下不适用”。举个实际的例子你修补了一个模型在“加法题”上的激活发现某个路径负责进位运算。同分布样本、改变数字位数、换一种表达方式效果都在。但你把题目从“2358”换成“two hundred thirty plus fifty eight”结果完全失效。那你就不能说“这个路径负责加法”只能说“这个路径负责数字列表格式下的加法运算”。这个边界本身就是解释的一部分。4.3 与梯度归因、消融实验交叉验证激活修补不是唯一能给出因果信号的工具。梯度归因gradient attribution和消融ablation可以做交叉验证。三种方法侧重点不同如果它们指向同一个结论你的机制解释就相当扎实了。梯度归因计算输入或隐藏状态对输出的影响速度快覆盖范围广但它本质上是一个局部线性近似容易漏掉非线性相互作用。激活修补则更直接但计算量高且不能覆盖所有组合。消融实验比如直接把某个 head 的输出置零看起来很像修补但它修掉的是一个“常量”而不是另一个运行状态因此更容易被冗余路径吸收。三种方法各自有偏交叉验证的主要目的就是让偏差相互抵消。如果你用梯度归因找到了 top-5 的节点用激活修补验证其中 3 个有强恢复效果再用消融确认另外 2 个也有关键作用最后画出来的电路就比单用任何一种方法都可靠。4.4 加入“反事实”和“弱化”测试最后一个我自己特别偏好用的测试是弱化修补weak patching。不做全量替换而是把修补的激活按比例混合进去比如 30%、50%、70%、100%。如果恢复效果随修补比例单调上升说明你捕捉到的是一个“可扩展”的因果信号如果效果在某个比例突然跳变或者没有单调性说明模型的行为可能是切换式的、甚至混沌的。单调性测试往往能消灭很多“伪机制”。因为真正的信息通路通常支持连续的信息注入而偶然的向量近似往往只在特定比例下才有恢复效果。你不需要把每种比例都铺开跑但我至少建议做 0%纯损坏、50%、100% 三档观察趋势。顺带一提这个测试还能帮你估算机制的“冗余度”。如果 50% 修补就能恢复 90% 的效果说明这个组件携带的信息高度浓缩如果必须 100% 才能恢复说明该机制依赖比较完整的激活模式局部信息没有独立作用。5. 从“找到位置”到“讲清楚机制”一个可复用的工作流理论讲清楚了给一套可以直接上手的流程。这套流程我从科研到落地场景都试过属于性价比比较高的那条路。5.1 建立你的基准样本集好的修补实验始于好的基准样本集。挑选样本的黄金标准是模型在这些样本上表现稳定多次运行结果一致、这些样本表面多样但内在结构相似、并且你能预判“正确答案”是什么。比如你想研究“事实回忆”机制就准备 100 个“国家-首都”问题但不要全是同一个模板。混合“What is the capital of France?”和“Frances capital is ___”这类句法变化甚至加上“Berlin? No, the capital of France is ___”这种带干扰的样本。样本越多样你后续画出来的电路越有泛化力。有了样本集之后先在干净运行下记录每个样本的正确答案再在损坏运行下记录错误答案。只有那些“干净运行对、损坏运行错”的样本才适合进入后续修补分析因为你需要一个明确的行为反差来观察恢复。5.2 粗粒度扫描、细粒度定位、路径确认三步法第一步是粗粒度扫描。按层扫描残差流看哪些层在替换后对正确率影响最大。结果通常是一个 U 形或者多峰曲线影响大的层就是机制可能存在的区域。这一步不用做太多花活直接按 token、按位置 mean-pool 修复即可。第二步是细粒度定位。在粗扫描圈定的几层里逐个替换注意力头和 MLP 的输出记录对每个样本的恢复效果。将结果排序后你会得到一张“候选组件列表”。不要把前几名直接当成机制它们只是下一步的输入。第三步是路径确认。在候选组件之间做路径修补验证是否存在从输入 token 到中间组件、再到输出 token 的传播路径。具体来说就是替换掉某个源头 token 的激活再通过候选组件把信息“桥接”回去观察预测是否恢复。这一步画出来的通路才算是有因果支撑的机制图。整套流程跑下来快的话可能只要一两天慢的话一周也不夸张。可控成本的关键在于不要一开始就做最细粒度的分析而是粗扫、细定、路径三步慢慢降维。5.3 报告结果时的校准语言最后聊一聊怎么写结论。“实验结果显示在 80 个样本中有 76 个样本在修补头 4.1 后从错误预测恢复到了正确预测”和“实验结果表明头 4.1 是事实回忆机制的关键部件”是两句话前者是数据后者是解释。你当然可以给出解释但要把证据和推断分层陈述。我在自己的分析报告里固定会用三种措辞来分层“观测到”描述现象、“符合假设”解释方向、“可以预期”泛化结论。这样即使读者不认可我的解释也能充分利用我的观测数据同时我也能明确知道自己的解释还有哪些不确定点。这种校准意识比任何技术工具都重要。因为机制解释的最终目的不是“画一张看起来很聪明的图”而是帮助别人包括未来的自己理解模型在什么条件下怎么做决策。图可以画错但如果你连证据和推断都混在一起别人就无法纠正你。6. 常见问题与排查技巧实录实操里大家踩的坑高度一致我直接把最经典的几个问题列出来每条附上排查思路。6.1 为什么修补了“最相关的头”答案就是不恢复排查顺序是先确认损坏运行是否正确失败——如果损坏运行仍然给出正确答案那么你根本没有构造出需要恢复的行为落差再确认修补位置是否足够靠下——有时候你需要修补整个残差流而不是单个头最后确认是否做了路径修补——单头输出影响较小路径修补往往才体现真正的因果链路。我见过最多的情况还是第一种损坏输入设计得不够“狠”模型依然能猜出正确答案。这样后面所有修补都失去了意义。设计损坏输入时最好保证“干净运行 95% 正确损坏运行 50% 以下正确”留出足够大的恢复空间。6.2 恢复率很高但是换一批样本就崩了怎么回事十有八九是基准样本集太单一。模型内部处理机制往往对句法、领域、token 位置高度敏感。你只在一个模板上发现“头 4.1 恢复得很好”不代表在所有相关任务里都如此。解决方案就是回到第 5.1 节扩大基准样本集的多样性然后看恢复率的分布。还有一个隐蔽的原因是样本集的标签不均衡。比如你准备了一堆“国家首都”样本但所有样本的正确答案都是“Paris”或者“Rome”这种高频词。那么模型可能不需要真正“回忆”信息只需要根据上下文猜一个高频城市名就能答对。这种情况下修补实验看到的效果有很大概率来自频率偏置而不是机制本身。6.3 用噪声损坏跟用 token 替换损坏结论完全不一样正常吗正常而且这正是模型机制非线性的体现。token 替换改变的是语义内容噪声损坏改变的是向量空间上的连续状态。模型可能在连续状态空间里表现得很鲁棒但在离散语义层面很敏感也可能反过来。这不代表某一种方案是对的一种方案是错的而是说明“机制”本身依赖于你定义的输入分布。我的建议是在正式分析里用一种主要的损坏方式比如 token 替换在附录里补充至少一种其他损坏方式的结果。如果两个结果一致结论更强如果不一致把不一致本身当作发现写下来而不是强行统一。6.4 需要采集多少个样本才有统计意义统计学上没有统一答案但我的经验值是少于 50 个样本的恢复率几乎不具备说服力最好到 100 个以上而如果你在做一个“发现型”分析可以先跑 20 个样本快速探测再在探测到的机制上用 200 个样本验证。另外不要只报平均值。修复样本的恢复率分布往往是双峰的——一批样本恢复得很好另一批完全没效果。只报平均值会掩盖这种双峰分布让你误以为机制是“部分有效”的而实际上它可能是“在某些子类上完全有效在另一些子类上完全无效”。画一个恢复率的直方图比任何均值都更有洞察力。7. 写在最后机制解释是一条渐进逼近的路聊了这么多往回看标题里的问题恢复答案之后能不能说找到了机制我的答案是不能马上说但你已经站在一条比绝大多数分析方法都靠谱的路上了。激活修补的价值在于它把“机制解释”从黑盒猜想推向可干预、可验证的因果推断它的风险在于“恢复答案”这个指标太直观、太大快人心以至于我们容易忘记验证因果需要更多条件。我自己跑过不少修补实验交过学费也画过事后看不靠谱的电路。现在我的行动准则是补丁只是假设生成器验证才是假设检验器。也就是说激活修补非常适合用来“提出机制候选”但真正的解释还需要跨样本稳定性、反向干预、路径确认和多方法交叉验证来共同托底。如果你正准备做一个机制分析我的建议是第一把修补当成起点而不是终点第二给自己的结论加上边界条件第三拥抱“这个机制可能只是模型内部众多并行的补偿通路之一”这种可能性。仔细想清楚这一点你画出来的电路图才经得住同行审也经得住自己三个月之后的审视。
