1. 这不是又一篇讲“相关不等于因果”的科普文
你点开这篇,大概率是被标题里“Modern Approach”和“Fundamental Problem”这两个词勾住的——前者暗示有新东西可学,后者直指因果推断领域里那个被反复咀嚼、却始终难以下咽的硬核内核:我们永远无法同时观测到同一个体在干预与未干预两种状态下的结果。这句拗口的话,就是Neyman-Rubin潜在结果框架(Potential Outcomes Framework)里最朴素也最残酷的公理:the fundamental problem of causal inference。它不是数学漏洞,而是现实物理限制:一个人不能既吃药又不吃药;一个用户不能既看到推荐广告又完全没看到;一个城市不能既实施限行政策又维持原有交通流。我们能拿到的,永远只是其中一种状态的观测值,另一个则是永远沉默的“反事实”(counterfactual)。
我做因果建模落地项目整十年,从电商AB测试平台搭建,到金融风控策略归因,再到医疗效果评估系统开发,踩过所有把“统计显著”当“因果成立”的坑。今天这篇,不讲教科书定义,不堆公式推导,只讲2020年后真正改变工业界实践逻辑的三股技术合力:基于表示学习的协变量平衡(Representation Learning for Balancing)、结构化反事实生成(Structural Counterfactual Generation),以及可解释性驱动的因果效应异质性建模(Heterogeneous Treatment Effect Modeling with Interpretability First)。它们共同构成了一种“现代方法”——不是替代传统工具,而是让传统工具(如倾向得分匹配PSM、双重差分DID、工具变量IV)第一次具备了在高维、非线性、小样本、混杂强的现实场景中稳定输出可信因果估计的能力。如果你正在用Python写pandas.groupby()算平均提升率,或者还在Excel里手动分组对比转化率,这篇文章会告诉你:那些数字背后,可能连方向都是错的。它适合三类人:想把AB测试从“看涨跌”升级为“算归因”的数据科学家;需要向业务方证明“某策略真实带来X%收入增长”的算法产品经理;以及正在写毕业论文、但被导师一句“你这个相关性分析怎么就敢下因果结论?”打回重写的研究生。下面,我们就拆开这三股合力,看看它们如何一层层瓦解那个“根本问题”。
2. 内容整体设计与思路拆解:为什么旧范式在现实中频频失效?
2.1 传统因果推断的“理想国”假设及其崩塌现场
所有经典因果方法都建立在几个看似合理、实则脆弱的假设之上。我们先看最核心的两个:
无混淆性(Unconfoundedness):要求所有影响处理分配(T)和结果(Y)的混杂因素(X)都已被观测并纳入模型。换句话说,“我们已知所有重要的变量”。但在真实世界里呢?以电商推荐为例,用户此刻的点击意愿,可能受其3小时前刚看完的一条短视频情绪残留、手机电量低于20%引发的决策惰性、甚至窗外突然响起的救护车鸣笛影响——这些变量,99.9%不会出现在你的用户特征表里。传统PSM或回归调整,对这种“不可观测混杂”(unobserved confounding)完全无能为力,估计偏差(bias)会像滚雪球一样放大。
重叠性(Overlap / Common Support):要求每个个体,在给定协变量X下,接受处理(T=1)和不接受处理(T=0)的概率都严格介于0和1之间。即,不能出现“某类用户100%会被推送广告,另一类用户0%会被推送”的极端情况。然而,线上系统天然存在强规则:新注册用户默认不推高风险金融产品;高净值用户自动进入VIP服务通道。这直接导致处理组和对照组在特征空间上严重分离,PSM匹配后剩下可比样本可能不足原始数据的5%,统计效力(statistical power)暴跌,置信区间宽得失去意义。
提示:我曾在一个千万级DAU的社交App里复现过一个经典案例——用传统Logistic回归估计“消息免打扰开关开启”对次日留存的影响。模型显示OR=1.8,p<0.001,看起来效果惊人。但当我们用现代方法引入一个隐含的“用户内容消费强度”代理变量(通过其7天内点赞/评论/分享频次的PCA第一主成分构建)后,效应值骤降至OR=1.03,p=0.42。那1.8的“显著”结果,本质是高活跃用户更倾向开启开关,而他们本身留存就高——一个完美的混杂偏倚(confounding bias)。
2.2 现代方法的破局逻辑:从“强行假设”到“主动构造”
现代方法的核心思想,是放弃在原始高维特征空间(如用户ID、设备型号、行为序列)上直接建模,转而学习一个低维、平衡、语义清晰的“因果表示空间”(Causal Representation Space)。这个空间有两个强制约束:
分布对齐(Distribution Alignment):在这个新空间里,处理组(T=1)和对照组(T=0)的样本分布必须尽可能重合。直观理解,就是让“开了免打扰”和“没开免打扰”的用户,在这个新空间里看起来像同一批人——他们的“画像”分布几乎一致。这直接缓解了重叠性问题,大幅扩充了可比样本池。
预测解耦(Prediction Decoupling):在这个新空间里,任何对结果Y的预测,都只能依赖于处理指示符T和该空间的表示,而不能再从表示本身“偷看”到T的信息。这确保了表示Z是T的“充分统计量”(sufficient statistic),剥离了混杂路径。
实现这一目标的主流架构,是对抗式表示学习(Adversarial Representation Learning)。它借鉴了生成对抗网络(GAN)的思想,但目标完全不同:生成器(Encoder)的目标不是生成逼真图片,而是生成一个能让判别器(Discriminator)无法分辨“这是处理组还是对照组”的表示Z;而判别器的目标,就是竭尽全力去区分。二者博弈的纳什均衡点,就是Z空间达到完美平衡的状态。这不是玄学,而是有坚实的理论保证(如Wasserstein距离最小化、最大均值差异MMD最小化)。
2.3 为何是“现代”?三个关键跃迁
从“静态分组”到“动态表示”:传统方法(如PSM)是静态的——你选好X,跑一次匹配,结果就定了。现代方法是动态的——表示Z是模型根据数据自适应学习的,能捕捉X中复杂的非线性交互(如“年轻女性+高教育背景+深夜活跃”这个组合,其混杂效应远非单个变量之和)。
从“全局平均”到“个体精准”:传统ATE(Average Treatment Effect)只给出一个笼统的“平均提升”,而现代HTE(Heterogeneous Treatment Effect)模型(如Causal Forest, Dragonnet)能输出每个用户的个性化因果效应估计τ(x),告诉你“对张三,这个策略预计提升留存12%,但对李四,反而可能降低3%”。这对精细化运营至关重要。
从“黑箱验证”到“白盒归因”:过去验证因果性,靠的是“找一个好工具变量”或“画一张漂亮的平行趋势图”。现代方法通过可视化Z空间的t-SNE降维图、计算各维度的平衡性指标(如标准化均值差SMD)、以及SHAP值解析τ(x)的驱动因子,让因果推断过程变得可审计、可解释、可辩论。
3. 核心细节解析与实操要点:平衡、生成、异质性,三步落地
3.1 第一步:构建平衡的因果表示空间(Balanced Representation)
这是整个流程的地基。我们以最常用的Dragonnet架构为例(它在KDD 2019上提出,已成为工业界事实标准之一)。它的核心是一个三头神经网络:
共享底层(Shared Base):一个深度全连接网络,输入原始协变量X(如用户年龄、性别、近7天登录次数、最近一次购买金额等),输出一个d维的表示向量Z。这是“表示学习”的主体。
倾向得分头(Propensity Head):在Z之上接一个sigmoid输出层,预测P(T=1|X),即倾向得分。这个头的损失函数是二元交叉熵(Binary Cross-Entropy)。
结果预测头(Outcome Heads):两个独立的全连接网络,分别预测E[Y|T=0, X]和E[Y|T=1, X]。它们的损失函数是均方误差(MSE)。
平衡正则项(Balancing Regularizer):这是最关键的创新。它在共享底层的输出Z上,施加一个额外的损失项:最小化处理组和对照组在Z空间上的分布距离。Dragonnet使用的是MMD(Maximum Mean Discrepancy),其计算公式为:
$$ \mathcal{L}{bal} = \left| \frac{1}{n_1}\sum{i:T_i=1}\phi(Z_i) - \frac{1}{n_0}\sum_{j:T_j=0}\phi(Z_j) \right|_{\mathcal{H}}^2 $$
其中φ(·)是将Z映射到再生核希尔伯特空间(RKHS)的特征映射,通常用RBF核(Gaussian kernel)来近似。这个损失项被加权后(权重λ)与前两个损失一起优化。
实操心得:MMD的核带宽(bandwidth)选择极其关键。太小,模型只关注局部细微差异,过拟合噪声;太大,模型忽略重要结构,平衡不足。我的经验是:先用中位数距离法(median heuristic)初始化,再在验证集上用网格搜索微调。一个简单有效的启发式是:取Z各维度标准差的中位数作为初始带宽。另外,共享底层的深度不宜过深(通常2-3层,每层64-128节点),否则容易学到过度复杂的、难以平衡的表示。
3.2 第二步:生成结构化反事实(Structural Counterfactual Generation)
有了平衡的Z,下一步是回答:“如果这个用户没接受处理,他的结果会怎样?”——即生成反事实Y(0)。传统方法(如回归调整)直接用E[Y|T=0, X]作为Y(0)的估计,但这在X高维且非线性时偏差巨大。现代方法转向结构化生成,其核心是利用Z空间的平衡性,将反事实生成转化为一个条件生成问题。
主流方案是CEVAE(Causal Effect Variational Autoencoder)。它将潜在结果Y(t)建模为:
$$ Y(t) = f_t(Z, \epsilon_y), \quad \text{where } \epsilon_y \sim \mathcal{N}(0, I) $$
其中f_t是一个神经网络,Z是平衡表示,ε_y是独立噪声。CEVAE的训练目标是最大化证据下界(ELBO),它包含三项:
- 重构项(Reconstruction):确保从X能重建出Z和Y。
- KL散度项(KL Divergence):约束Z的先验分布接近标准正态分布,保证Z的平滑性和泛化性。
- 因果正则项(Causal Regularizer):强制Z与T独立(I(Z; T) ≈ 0),这正是平衡性的信息论表达。
一旦模型训练完成,生成反事实就变得非常优雅:
- 对于一个处理组用户(T=1),我们固定其Z,然后采样ε_y,输入到f_0(Z, ε_y)中,即可得到多个Y(0)的样本。
- 同理,对对照组用户(T=0),用f_1(Z, ε_y)生成Y(1)。
这带来的好处是:我们不再只有一个点估计,而是一整个反事实分布。你可以计算其均值(即ATE)、分位数(如90%用户的效果下限)、甚至整个分布形状(是否右偏?是否存在长尾效应?)。这为风险评估提供了前所未有的粒度。
注意:CEVAE的训练非常不稳定,尤其是KL散度项容易坍缩(collapse),导致Z退化为常数。我的避坑技巧是:使用β-VAE变体,将KL项权重β从0开始缓慢增加(annealing),并在训练早期冻结f_t网络,只优化编码器和解码器,待Z空间初步稳定后再联合优化。此外,务必对Y进行标准化(减均值除标准差),否则梯度爆炸是常态。
3.3 第三步:建模异质性效应(Heterogeneous Treatment Effect)
最后一步,是把前面两步的成果,转化为业务可行动的洞见。HTE模型的目标是学习一个函数τ(x) = E[Y(1) - Y(0) | X=x]。这里的关键挑战是:我们永远无法观测到单个x对应的Y(1)和Y(0),只能观测到其中一个。因此,HTE模型本质上是在学习一个双重鲁棒估计器(Doubly Robust Estimator),它结合了倾向得分和结果模型的预测,即使其中一个有偏差,只要另一个准确,最终估计仍一致。
目前最实用的两类模型是:
Causal Forest:基于随机森林的集成方法。它将样本空间递归分割,使得每个叶子节点内的τ(x)尽可能同质。其优势在于:无需假设函数形式(非参数),天然支持高维X,且每个树的分裂规则可解释(例如,“当用户月均消费>5000且注册时长<30天时,效应显著为负”)。缺点是训练慢,超参多。
X-Learner:一个轻量级、模块化的框架。它分为四步:
- 用对照组数据训练一个结果模型μ₀(x) = E[Y|T=0, X];
- 用处理组数据训练一个结果模型μ₁(x) = E[Y|T=1, X];
- 构造两个伪结果:对于对照组,g₀(x) = Y - μ₁(x);对于处理组,g₁(x) = Y - μ₀(x);
- 分别用g₀和g₁作为目标变量,训练两个新的模型,最后加权平均得到τ(x)。
X-Learner的优势在于:它允许你复用任何你喜欢的、成熟的机器学习模型(XGBoost, LightGBM, even linear regression)作为基础学习器,极大降低了工程门槛。
实操心得:在X-Learner中,步骤1和2的结果模型质量直接决定了最终τ(x)的精度。我强烈建议:不要用简单的线性回归,而要用能捕捉交互的模型(如LightGBM with interaction constraints)。更重要的是,必须对μ₀和μ₁进行严格的交叉验证(cross-validation),并监控其在验证集上的MSE。如果MSE很高,说明结果模型本身就不准,X-Learner的“双重鲁棒”优势就荡然无存。一个经验法则是:μ₀和μ₁的验证MSE,应该至少比一个仅用常数(如全局均值)预测的基准模型低30%以上,才值得继续。
4. 实操过程与核心环节实现:从零开始跑通一个完整Pipeline
4.1 数据准备与预处理:超越“删缺失值”
现代因果建模对数据质量的要求,远超传统机器学习。我们以一个真实的电商“购物车弹窗优惠券”实验为例:
原始数据表(user_events):包含字段
user_id,event_time,event_type('add_to_cart', 'purchase', 'click_coupon'等),coupon_id,product_category,device_type,os_version。关键衍生特征(必须手工构建):
is_treated: 布尔值,用户在实验期间是否被分配到弹窗组(由实验平台日志决定)。outcome: 二元变量,实验期结束后7天内是否发生购买(Y=1)。pre_treatment_features: 所有在实验开始前计算的特征,这是铁律。包括:pre_7d_purchase_cnt: 实验前7天购买次数。pre_7d_cart_add_cnt: 实验前7天加购次数。pre_30d_avg_order_value: 实验前30天客单价均值。user_tenure_days: 用户注册至今的天数。category_affinity_vector: 对用户过去90天浏览/购买的Top10品类,构建一个10维的one-hot向量(避免直接用品类ID,防止过拟合稀疏ID)。
提示:绝对禁止使用任何实验期间或之后的数据来构建X!这是一个致命错误。我见过太多团队,因为加入了“实验期间的点击率”作为特征,导致模型学到了T和Y之间的虚假关联(T→click→Y),而非T→Y的真实因果路径。所有X必须是“事前已知”的。
4.2 模型训练:Dragonnet的PyTorch实现精要
以下是Dragonnet核心组件的PyTorch代码骨架(省略数据加载和训练循环):
import torch import torch.nn as nn import torch.nn.functional as F class DragonNet(nn.Module): def __init__(self, input_dim, representation_dim=200, hidden_dim=200): super().__init__() # 共享底层:学习平衡表示Z self.shared_base = nn.Sequential( nn.Linear(input_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, representation_dim) # Z ) # 倾向得分头 self.propensity_head = nn.Sequential( nn.Linear(representation_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, 1), nn.Sigmoid() ) # 结果预测头(两个独立) self.y0_head = nn.Sequential( nn.Linear(representation_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, 1) ) self.y1_head = nn.Sequential( nn.Linear(representation_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, 1) ) def forward(self, x): z = self.shared_base(x) # [batch_size, rep_dim] t_pred = self.propensity_head(z).squeeze(-1) # [batch_size] y0_pred = self.y0_head(z).squeeze(-1) # [batch_size] y1_pred = self.y1_head(z).squeeze(-1) # [batch_size] return z, t_pred, y0_pred, y1_pred # MMD损失计算(简化版,使用线性MMD) def mmd_loss(z_treated, z_control, kernel='rbf'): if kernel == 'rbf': # 计算RBF核矩阵 zz = torch.mm(z_treated, z_treated.t()) zt = torch.mm(z_treated, z_control.t()) tt = torch.mm(z_control, z_control.t()) z_norm = torch.diag(zz).view(-1, 1) t_norm = torch.diag(tt).view(-1, 1) # 广播计算距离矩阵 dist_zz = z_norm + z_norm.t() - 2 * zz dist_zt = z_norm + t_norm.t() - 2 * zt dist_tt = t_norm + t_norm.t() - 2 * tt # RBF核 gamma = 1.0 / (2 * z_treated.shape[1]) # 启发式带宽 k_zz = torch.exp(-gamma * dist_zz) k_zt = torch.exp(-gamma * dist_zt) k_tt = torch.exp(-gamma * dist_tt) # MMD^2 = E[k(z,z')] + E[k(t,t')] - 2*E[k(z,t)] mmd2 = k_zz.mean() + k_tt.mean() - 2 * k_zt.mean() return mmd2 else: # 线性MMD(更快,适用于初筛) mean_treated = z_treated.mean(dim=0) mean_control = z_control.mean(dim=0) return torch.mean((mean_treated - mean_control) ** 2) # 训练循环中的损失计算 model.train() z, t_pred, y0_pred, y1_pred = model(x_batch) # 倾向得分损失 loss_prop = F.binary_cross_entropy(t_pred, t_batch.float()) # 结果损失(只对对应组别计算) loss_y0 = F.mse_loss(y0_pred[t_batch == 0], y_batch[t_batch == 0]) loss_y1 = F.mse_loss(y1_pred[t_batch == 1], y_batch[t_batch == 1]) # 平衡损失 z_treated = z[t_batch == 1] z_control = z[t_batch == 0] loss_bal = mmd_loss(z_treated, z_control) total_loss = loss_prop + loss_y0 + loss_y1 + lambda_bal * loss_bal关键参数调试:
lambda_bal(平衡正则权重)是核心超参。我的经验是:从0.1开始,逐步增大到1.0、10.0,观察验证集上的平衡性指标(如SMD)和ATE估计的稳定性。最优值通常在1.0-5.0之间。如果SMD已经很低(<0.1)但ATE波动大,说明λ过大,模型过度追求平衡而牺牲了预测精度;反之,如果SMD很高(>0.3)且ATE偏差大,则需增大λ。
4.3 效应评估与业务解读:不止于一个数字
模型输出τ(x)后,工作才刚开始。我们需要一套完整的评估协议:
平衡性诊断(Balance Diagnostics):计算每个协变量X_j在处理组和对照组的标准化均值差(SMD):
$$ \text{SMD}j = \frac{|\bar{x}{1j} - \bar{x}{0j}|}{\sqrt{(\sigma{1j}^2 + \sigma_{0j}^2)/2}} $$
其中$\bar{x}{1j}$是处理组X_j的均值,$\sigma{1j}^2$是其方差。SMD < 0.1被视为良好平衡。必须对所有X_j(包括原始特征和其高阶交互项)都进行检查,并绘制SMD直方图。这是模型是否“可信”的第一道关卡。
伪实验验证(Placebo Test):在真实数据上,人为制造一个“假处理”(例如,按用户ID奇偶性分组),然后用同一套模型去估计这个假处理的ATE。理论上,这个ATE应该在0附近,且95%置信区间包含0。如果假ATE显著不为0,说明模型存在系统性偏差(如残余混杂或过拟合)。
业务分层解读:将用户按τ(x)分五档(如最低20%,次低20%...),然后计算每档的:
- 平均τ(x)(即该档的HTE估计)
- 该档用户占总体的比例
- 该档的“预期总收益” = 平均τ(x) × 该档用户数 × 单用户价值(如ARPU)
这张表,就是给CEO看的PPT核心页。它能清晰地告诉决策者:“我们只需聚焦于τ(x)最高的20%用户(约50万人),就能捕获80%的总预期收益,且这部分用户的效应非常稳健(95%CI: [0.15, 0.22])”。
5. 常见问题与排查技巧实录:那些文档里不会写的坑
5.1 “我的MMD损失降不下去,SMD一直很高,怎么办?”
这是最普遍的痛点。原因和对策如下表:
| 现象 | 可能原因 | 排查与解决技巧 |
|---|---|---|
| MMD损失在训练初期就停滞,SMD > 0.5 | 共享底层容量不足,无法学习到足够复杂的平衡表示 | 尝试增加共享底层的宽度(hidden_dim从200→512)或深度(加一层ReLU)。但切记:宽度增加后,必须同步增大λ_bal,否则模型会“躺平”在简单表示上。 |
| MMD损失震荡剧烈,SMD忽高忽低 | 学习率(learning rate)过大,优化器在平衡点附近反复横跳 | 将学习率降低一个数量级(如从1e-3→1e-4),并改用AdamW(带权重衰减)替代Adam。权重衰减能有效抑制表示Z的过拟合。 |
| MMD损失很低(<0.01),但SMD在某些关键特征(如age)上仍>0.3 | 模型学会了“作弊”:用Z的某些维度精确编码了age,但其他维度补偿,使整体MMD低,而age的边际分布未平衡 | 这是MMD的固有缺陷(它衡量的是联合分布,而非边际分布)。对策:在损失函数中,显式加入关键协变量的边际SMD惩罚项。例如,对age,计算其在Z空间的线性投影后的SMD,并加到总损失中。 |
| 训练速度极慢,GPU显存爆满 | RBF核的MMD计算是O(N²)复杂度,对百万级样本不可行 | 改用线性MMD(代码中已提供),或采用随机傅里叶特征(RFF)近似RBF核,将复杂度降至O(N)。RFF的维度设为1000通常足够。 |
5.2 “HTE估计结果看起来很奇怪:有些用户的τ(x)是负的,但业务常识说这不可能!”**
这往往不是模型错了,而是你忽略了测量误差(Measurement Error)和定义偏差(Definition Bias)。
测量误差:你的
outcome(如“7天内购买”)可能被严重低估。例如,用户在APP内没买,但去了线下店扫码支付,这笔订单没被归因到该用户。这会导致Y被系统性低估,尤其对高价值用户(他们更可能跨渠道),从而让τ(x)偏向负值。对策:与数据工程团队合作,打通线上线下ID,或使用更鲁棒的归因窗口(如“实验后30天内首次购买”)。定义偏差:你定义的“处理”(T)可能不纯净。例如,“弹窗曝光”不等于“用户看到并理解了优惠”。大量用户可能在弹窗出现瞬间就划走了,实际未接收干预。此时,你估计的是依从者平均效应(CACE),而非意向治疗效应(ITT)。业务方想要的是ITT(我们推了,效果如何?),但模型估计的是CACE(对那些真看了的人,效果如何?)。对策:在T的定义上,使用更严格的代理变量,如
is_treated = (popup_exposure_duration > 2 seconds) & (popup_click == True)。
5.3 “模型在验证集上表现很好,但上线A/B测试后,预估的ATE和实际观测的ATE相差很大!”**
这是因果建模落地的终极拷问。根本原因在于:离线模型评估和在线A/B测试,面对的是两个不同的数据生成机制(Data Generating Process)。
离线评估:你用历史数据训练模型,其T是过去实验的分配结果,Y是过去发生的事实。这是一个静态快照。
在线A/B测试:新策略上线后,用户的反应(Y)会受到新策略的动态反馈影响。例如,一个强力的优惠券策略,短期内拉升了购买,但长期可能透支用户预算,导致后续几周的购买下降。离线模型无法捕捉这种时间动态性。
我的独家经验:在模型上线前,必须进行前瞻性验证(Prospective Validation)。具体操作:选取一个与当前实验相似的、尚未开始的历史时间段(如上个月的同一周),用当前模型对这个未来时段的用户进行τ(x)预测,并记录下来。等到这个时段真实过去后,立刻用真实的A/B测试结果去校验预测。这个过程重复3-5次,才能建立起对模型长期稳定性的信心。我经手的项目中,只有通过前瞻性验证的模型,其上线误差才控制在±15%以内;未经过此验证的,误差常达±50%甚至更高。
6. 最后一点个人体会:因果不是终点,而是起点
做了十年因果,我越来越确信:“根本问题”之所以根本,是因为它提醒我们,所有数据科学的终极目标,从来都不是拟合一个漂亮的曲线,而是理解一个真实的机制。当你能稳定地回答“如果当初没做这件事,现在会怎样?”这个问题时,你就拥有了在不确定世界中做确定决策的锚点。现代方法没有消除那个根本问题,但它给了我们一把更锋利的手术刀,让我们能更精准地切开混杂的迷雾,触碰到因果关系的肌理。这条路没有捷径,每一次SMD的调试、每一次伪实验的失败、每一次上线前的忐忑,都是在加固我们对现实世界的认知坐标系。所以,别把这篇当作一份操作手册,而把它看作一张邀请函——邀请你加入一场持续十年、并将持续下一个十年的,关于“理解何以可能”的严肃实践。