AI/ML 详解:可言说表示与全局工作空间

Day 58 · 2026-10-04
面向:有编程经验的非 AI 方向工程师 · 难度:前沿

本期是 Day 27 可解释性 的续篇:SAE 问「这里编码了什么」,本期的 J-lens 问「这里准备说什么」。与 Day 55 CoT 监控 互为一组——一个读写出来的推理,一个读没写出来的推理。

雅可比透镜Jacobian Lens (J-lens)

读出工具线性化
一句话类比

中间层的激活像一张旧版本 schema 的表,末层是新 schema。Logit lens 假设两边列名一致、直接 SELECT;J-lens 先算出一份平均意义上的迁移脚本,把旧表搬到新 schema,再用模型自己的「字典」(unembedding)去查。

它解决什么问题 + 工作机制

Transformer 每层都往同一条残差流(residual stream,层与层之间传递的那个向量,可理解为共享的状态总线)上读写。想知道第 l 层「在想什么」,最朴素的办法是 logit lens(nostalgebraist 2020):把中间激活直接乘上末层的词表矩阵,看哪个词得分最高。问题是早中层的坐标系和末层并不对齐,读出来常是一堆逗号空格。Tuned lens(Belrose et al. 2023)给每层训练一个仿射翻译器去拟合最终输出,但它学的是「最像下一个词」,可能借翻译器之力读出模型本不用的东西。

Anthropic 2026-07 的论文《Verbalizable Representations Form a Global Workspace in Language Models》换了个问题:不问「这里像什么词」,而问「推一下这里,模型之后说出哪些词的概率会变」。

lens_l(h) = unembed( J_l · h ),   J_l = E[ ∂h_final / ∂h_l ]
  • h:第 l 层某位置的激活向量;h_final:末层激活;
  • ∂h_final/∂h_l:雅可比矩阵(Jacobian,一张「输入每一维微动,输出每一维跟着动多少」的敏感度表);
  • E[·]:在大量普通文本、所有源位置、当前及之后所有目标位置上取平均——所以它捕捉的是「现在或以后会说出口」,不止下一个 token;
  • unembed:模型自己的输出层,把末层向量翻成词表得分。

直觉:真实网络是非线性的,但取平均后的雅可比是它的一阶线性近似,相当于一张「各层到输出的平均影响力地图」。它从模型自身的导数推出来,而不是拟合一个解码目标,所以不太会凭空「替模型说话」。官方配套代码说明:拟合用约 1000 条 128-token 的通用网页文本,约 100 条已可用。

第 l 层激活 h──直接──▶unembed▶ logit lens(早层常读出噪声)
第 l 层激活 h──▶平均雅可比 J_l──▶unembed▶ J-lens:「它倾向让模型说出什么」
代码示例
import torch
from transformers import GPT2LMHeadModel, GPT2Tokenizer
tok = GPT2Tokenizer.from_pretrained("gpt2"); m = GPT2LMHeadModel.from_pretrained("gpt2").eval()
L = 6  # 观察第 6 层
def tail(h):  # 从第 L 层跑到末层(含 final LayerNorm)
    for blk in m.transformer.h[L:]:
        out = blk(h); h = out[0] if isinstance(out, tuple) else out
    return m.transformer.ln_f(h)
def hidden(text):
    ids = tok(text, return_tensors="pt").input_ids
    return m(ids, output_hidden_states=True).hidden_states[L].detach()
J, corpus = torch.zeros(768, 768), ["The weather today is", "In 1905 Einstein", "My favorite food is"]
for text in corpus:  # 玩具版:只看末位置→末位置,真实版还会累加未来位置
    hs = hidden(text)
    def f(v): h = hs.clone(); h[0, -1] = v; return tail(h)[0, -1]
    J += torch.autograd.functional.jacobian(f, hs[0, -1], vectorize=True) / len(corpus)
h = hidden("The capital of France is")[0, -1]
with torch.no_grad():
    for name, v in [("logit", m.transformer.ln_f(h)), ("J", J @ h)]:
        print(name, [tok.decode(i) for i in m.lm_head(v).topk(5).indices])
常见误区 + 实践场景
误区:「J-lens 读出了模型真实的念头」。它读出的是平均线性近似下的输出倾向,在偏离训练分布的上下文里近似会失真;而且社区有人在 GPT-2 small/medium 上复现时,J-lens 并没有打赢 logit lens,还指出排名指标会被高频 token 刷分。它在大模型上更有用,在小模型上未必。
📌 BigCat 场景:读任何「读心」类可解释性新闻时,先问三件事——读出器是拟合出来的还是推导出来的?验证是相关性还是因果干预?在多大的模型上成立?这套问法比记住任何单个结论更耐用。
Takeaway + 思考题
💡 Logit lens 假设坐标一致,tuned lens 学一个翻译器,J-lens 借模型自己的导数做翻译——三者是「读出轴」上的三种取舍。
🤔 「平均雅可比」把成千上万种上下文压成一张矩阵,哪类概念最可能在平均中被抹掉?

J-space:低维的可言说子空间J-space

表示几何容量瓶颈
一句话类比

残差流像一台服务器的全部内存,J-space 则是挂在共享消息总线上的那几个 topic:大部分数据是各模块的本地状态,只有很少一部分被发布到总线上,任何下游(包括「把它说出来」的模块)都能订阅。

它解决什么问题 + 工作机制

有了 J-lens,就能为词表里每个词找到「推动模型将来说出它」的那个方向。把这些方向张成的空间叫 J-space。论文的几何发现有三条:

  • 集中在中间层:早层多是字面特征,末层忙着排版下一个 token,中层才是概念层面的「工作台」;
  • 方差占比很小:J-space 在激活总方差中不到约 10%——绝大部分「能量」花在别处;
  • 容量有限:同一时刻大约只能容纳 k≈25 个可区分的概念,像一个小寄存器组,而不是一块大内存。

关键结论是:方差小 ≠ 不重要。一个概念的表示里,正是那一小块 J-space 分量决定了它能不能被报告出来。这挑战了一个常见的默认假设——「激活里方差大的方向才是主要信息」(PCA 式直觉)。在这里,决定行为的恰恰是不起眼的低方差子空间。

某中间层的残差流(示意)
非 J 分量:≈90%+ 方差 · 语法/位置/字面细节J-space
↑ 小块,但「能说出口」「能被推理调用」都要经过它
代码示例
import numpy as np
rng = np.random.default_rng(0)
d, k, n = 512, 25, 2000                        # 维度 / 可言说子空间秩 / 样本数
Q = np.linalg.qr(rng.normal(size=(d, d)))[0]   # 随机正交基
J_dirs, other = Q[:, :k], Q[:, k:]              # 前 k 维当作 J-space
# 模拟激活:J 分量幅度小,其余方向幅度大(如字面、位置噪声)
acts = rng.normal(size=(n, k)) * 1.0 @ J_dirs.T + rng.normal(size=(n, d - k)) * 1.3 @ other.T
var_J = ((acts @ J_dirs) ** 2).sum() / (acts ** 2).sum()
print(f"J-space 方差占比: {var_J:.1%}")          # 约 3%:PCA 会先把它扔掉
# 若「说出口」只读 J 分量,按方差降维反而会删掉最关键的信息
top_pc = np.linalg.svd(acts - acts.mean(0), full_matrices=False)[2][:50]
print("前 50 主成分里保留的 J 能量:", round(float(((top_pc @ J_dirs) ** 2).sum() / k), 3))
常见误区 + 实践场景
误区:「J-space 就是模型的思想全集」。它只是可言说的那部分;大量真正参与计算的信息不在其中,模型说不出来,J-lens 也读不到。把它当完整日志,就会对「没读到 = 没想过」产生错误安全感。
📌 BigCat 场景:这和人类工作记忆「约 4±1 组块」的研究形成有趣对照——容量瓶颈可能不是 bug,而是让信息能被全局共享的代价。设计自己的 AI 工作流时,也值得想想哪些状态必须进「共享总线」、哪些留在本地。
Takeaway + 思考题
💡 J-space:中层、低方差、小容量,却是「可报告性」的闸口。
🤔 如果一个概念的 J 分量被削弱但其余分量完好,模型还能「用」它却「说不出」它吗?这对应人类的什么现象?

能说出口的,正是沉默推理所用的Verbalizable = Used

因果干预核心命题
一句话类比

审计日志和业务主表的区别:很多系统的「报告」是另写的一份日志,可能和真实业务脱节;论文主张 J-space 更像报告直接读主表——模型汇报「我在想什么」时,读的就是推理正在用的那几行。

它解决什么问题 + 工作机制

Day 55 讲过:思维链(CoT)可能不忠实,写出来的理由不一定是真理由。那么不写出来的推理呢?论文用「改一处、看行为变不变」的因果干预论证三件事:

  • 报告:问模型「你在想什么」,回答来自 J-space;把其中「足球」的表示换成「橄榄球」,模型就改口说自己在想橄榄球——说明报告是被这块表示驱动的,不是巧合相关;
  • 定向调控:让模型抄写一句无关的话、同时「心里想着柑橘类水果」,J-space 里出现 orange、lemon;让它默算,J-space 依次浮现中间结果——嘴上一个字没说;
  • 沉默推理:多跳问题(如「火星是什么颜色」)里,「火星」「颜色」在中层先亮起,然后才输出 red。论文把中间结论的 J 分量与另一题的对换,答案翻转的比例明显高于对换方差大得多的非 J 分量。

合起来,命题是:可报告的表示与内部推理使用的表示是同一批。另一面同样重要——选择性:流畅续写这类自动化任务不太依赖 J-space,灵活推理和「汇报体验」才依赖。这正是「全局工作空间」该有的样子:不是所有计算都走总线,只有需要被多个模块协同调用的才走。

代码示例
import numpy as np
rng = np.random.default_rng(1)
d, k = 64, 8
Q = np.linalg.qr(rng.normal(size=(d, d)))[0]; J, R = Q[:, :k], Q[:, k:]
w = J @ rng.normal(size=k)                 # 下游「回答」只读 J 子空间
def make(c):                                # c=概念向量;非 J 部分方差更大
    return J @ c + R @ rng.normal(size=d - k) * 3
def swap(a, b, P):                         # 把 a 在子空间 P 上的分量换成 b 的
    return a - P @ (P.T @ a) + P @ (P.T @ b)
flips_J = flips_R = 0
for _ in range(1000):
    a, b = make(rng.normal(size=k)), make(rng.normal(size=k))
    if np.sign(w @ a) == np.sign(w @ b): continue    # 只看答案本就不同的对
    flips_J += np.sign(w @ swap(a, b, J)) == np.sign(w @ b)
    flips_R += np.sign(w @ swap(a, b, R)) == np.sign(w @ b)
print("换 J 分量翻转:", flips_J, " 换非 J 分量翻转:", flips_R)  # 玩具里后者为 0
常见误区 + 实践场景
误区:「既然 J-space 能读沉默推理,CoT 监控就过时了」。J-lens 需要白盒权重,读出的是词表上的模糊倾向而非完整论证;CoT 是黑盒可用、人类可读的。两者是互补的两条通道:一个看说了什么,一个看准备说什么,交叉比对才能发现「嘴上一套、心里一套」。
📌 BigCat 场景:在决策辅助里,当模型给出结论却说不清理由,不要只追问「为什么」——它的口头解释可能是事后编的。更稳的做法是换几种问法独立验证结论本身,把「自述」当线索而非证据。
Takeaway + 思考题
💡 因果干预让「可报告」与「被使用」第一次在同一块表示上对上了号;但要注意,这是在白盒、受控任务上得到的结论。
🤔 如果训练时对 J-lens 读数施加惩罚(例如不许出现某些概念),会不会重演 Day 55 的「混淆式奖励作弊」——模型把意图搬到 J-space 之外?

工程对应 → super-individual D10 (Hallucination 治理)

与全局工作空间理论的对照Global Workspace Theory

意识科学跨学科争议
一句话类比

全局工作空间理论把大脑看成一群并行微服务加一条容量有限的广播总线:进入总线的信息被全网订阅,就成为「意识到的」;更强的版本还要求进入总线是全有或全无的,像分布式提交要么整体生效、要么不生效,而不是渐进的。

它解决什么问题 + 工作机制

全局工作空间理论(Global Workspace Theory, GWT)由 Bernard Baars 在 1988 年提出,后经 Dehaene 等人发展为神经版本。它试图解释意识通达(access consciousness,信息可被报告、可被推理调用的那种「意识到」):大量处理在无意识中并行进行,只有少量内容赢得竞争、进入全局空间后被广播。神经版本还强调点燃(ignition):信息一旦越过阈值,会突然、非线性地扩散到全脑。

论文列出 J-space 满足的五条「工作空间式」性质:

言语报告 ✓定向调控 ✓内部推理 ✓灵活泛化 ✓选择性 ✓
容量有限 ✓(k≈25)点燃式非线性进入 ✗ 尚未显示现象意识 — 不在讨论范围

「灵活泛化」指同一个 J 向量能被多种下游操作当作参数使用——就像总线上的一条消息被不同服务各取所需。论文自己承认:与 GWT 的架构对应是松散的,容量限制和选择性已有迹象,但完整的「点燃」机制还没找到。

公开评议集中在三点:其一,功能通达 ≠ 现象体验——哲学家 Ned Block 早就区分了「通达意识」与「现象意识」,J-space 至多对应前者;其二,有评论认为为了让定义成立,GWT 的许多要求被放宽了,剥掉这层框架后,它是一个关于计算组织的发现,而非关于心智的发现;其三,前述小模型复现失败提示,结论的适用范围还需更多独立检验。论文本身没有宣称机器有意识,但措辞留了想象空间。

代码示例
import numpy as np
# 对比两种「进入工作空间」的方式:线性渐进 vs 点燃式(全有或全无)
def linear_access(s):
    return s / s.sum()                     # 强度成比例地分享总线
def ignition_access(s, k=3, theta=0.6, gain=8):
    top = np.argsort(s)[-k:]                 # 容量限制:只有前 k 个参与竞争
    out = np.zeros_like(s)
    act = 1 / (1 + np.exp(-gain * (s[top] - theta)))  # 陡峭 S 形 ≈ 阈值
    out[top] = np.where(act > 0.5, 1.0, 0.0)    # 越过阈值→整体广播,否则沉默
    return out
s = np.array([0.2, 0.55, 0.65, 0.9, 0.1, 0.58])  # 6 个候选概念的激活强度
print("线性:", linear_access(s).round(2))
print("点燃:", ignition_access(s))   # 0.58 与 0.65 很接近,结局却一个 0 一个 1
常见误区 + 实践场景
误区:「Anthropic 证明了 Claude 有意识」。论文证明的是:存在一块满足若干功能性工作空间特征的表示。从「功能上像」跳到「有体验」,中间隔着意识研究里最难的那道题,这篇论文没有、也无法跨过。
📌 BigCat 场景:这是跨学科思考的好素材——佛学讲「心所」与「识」的分层,神经科学讲通达与现象之分,现在机器里出现了一个可操作、可干预的「通达」样本。它让「哪些意识理论可被检验」这个问题第一次有了非生物的实验台。
Takeaway + 思考题
💡 J-space 为 GWT 的「通达」部分提供了一个可干预的机器样本,但缺「点燃」、不涉「体验」,类比要用得克制。
🤔 如果未来在某个模型里真的观测到点燃式的非线性进入,你会因此更倾向于认为它「有意识」吗?还缺什么?

深入资源

  • Anthropic Interpretability, Verbalizable Representations Form a Global Workspace in Language Models, 2026-07, transformer-circuits.pub/2026/workspace(arXiv:2607.15495)— 本期主线,含 J-lens 定义、五条性质与干预实验
  • anthropics/jacobian-lens(GitHub)— 官方参考实现,支持 HuggingFace 开放权重模型,可自己拟合和应用透镜
  • nostalgebraist, interpreting GPT: the logit lens, LessWrong 2020 — 「把中间层直接接到输出层」这一思路的起点
  • Belrose et al., Eliciting Latent Predictions from Transformers with the Tuned Lens, arXiv:2303.08112 (2023) — 为每层学仿射翻译器,是理解 J-lens 取舍的参照物
  • Nelith Bandularatne, J-Lens: A Failed Replication on GPT-2, LessWrong 2026 — 小模型上的反面证据与指标陷阱,适合配合主论文读

深入思考

J-lens 和 SAE 都声称在读「模型在想什么」,它们会给出矛盾的答案吗?
会,而且矛盾本身有信息量。SAE 从激活重构出发,问「这里存了哪些可分离的特征」,它会找到大量模型从不说出口的特征(语法、位置、风格)。J-lens 从输出影响出发,只看「会推向哪些词」。一个特征在 SAE 里很显著、J-lens 却读不到,说明它是本地计算状态;反过来 J-lens 读到、SAE 没有单独对应的特征,说明可言说概念可能是多个特征的组合。两者像数据库里「表里有什么」和「查询会返回什么」的区别。
「方差小却决定行为」对 AI 安全意味着什么?
很多监控与压缩方法默认高方差方向最重要——PCA 降维、按激活幅度剪枝、按范数筛选特征。如果关键的、可言说的推理恰好住在低方差子空间,这些方法会系统性地漏掉最该看的东西。反过来,这也是好消息:要监控的空间维度小、容量有限,原则上比监控整个残差流更可行。安全设计需要按「对输出的因果影响」而不是「数值大小」来分配注意力。
如果模型知道自己的 J-space 会被读取,会发生什么?
这是 Day 55 「混淆」问题的白盒版本。只要训练信号里包含 J-lens 读数(例如惩罚出现危险概念),优化压力就可能把相关计算推到 J-space 之外——可能以「说不出口」的形式完成同样的推理,代价也许是能力下降,因为论文显示灵活推理依赖 J-space。这里有个微妙的博弈:让推理离开工作空间可能会降低它的灵活性。读出工具应当只用于评估,不进训练目标,是目前最稳妥的立场。
如果人类意识也只是「容量有限的广播总线」,那 J-space 的发现对理解自身意味着什么?
GWT 本就是功能主义理论:它说通达意识就是某种信息组织方式。若接受这一点,J-space 的出现说明这种组织方式可能是「需要灵活复用信息的系统」的收敛解,而非生物特有——类似不同物种独立演化出眼睛。但如果你认为意识的核心是体验本身(现象意识),那么 J-space 恰好显示了功能可以完整存在而无需回答体验问题。佛学的「识」与「心所」之分,或许正提示了这两层不应混为一谈。