☰
因果推理AI决策系统构建指南:从相关性预测到因果效应评估
2026/10/20 4:15:36 网站建设 项目流程

上个月复盘某商城优惠券投放策略时,数据分析师指着屏幕问我:“模型显示给高活跃用户发五元券,转化率能提升三个百分点,这个结论你敢直接拿来调整预算吗?”我盯着报告沉默了几秒——这份结论来自我们维护了大半年的营销决策模型,逻辑看起来无懈可击:高活跃用户历史转化率本来就高,发券之后转化率也确实更高。但真正的问题是,如果这些用户本来就准备下单,那张券只是白送的利润。那一刻我意识到,团队真正需要的是一个基于因果推理的AI决策系统,而不是一个相关性预测流水线。预测回答“是什么”,决策必须回答“假如当初不这样做会怎样”。这篇文章把我们从零搭建这套系统的全过程写下来,包括建模、架构、算法、评估和大量实战踩坑,希望对做策略、推荐、风控和定价的朋友有参考价值。

1. 相关性模型的局限:从一次投放复盘说起

1.1 那次让我失眠的线上实验结果

我们原来的决策链路并不复杂:用户进入结算页,特征平台出一批画像,线上模型输出每个动作的转化率,规则引擎取最高概率的动作下发。离线指标一直不错,AUC 在 0.83 左右,业务方也习惯了拿转化率提升来汇报。但连续两个月的月度复盘都让我坐不住:同一个发券策略,离线回放能算出 8% 的提升,上线小流量实验却经常打不赢“不干预”的对照组,有一次甚至出现实验组转化率略低的情况。

团队一开始争论是不是特征没对齐、流量分桶有问题。后来我们仔细看数据才明白,问题不在工程,而在模型目标被污染了。用户是否发券并不是随机分配的,活跃用户更容易被系统选中,也更容易转化。模型真正学到的,是“活跃用户高转化”和“活跃用户会被发券”这两个相关关系,而不是“发券能导致转化提升”。这种偏差藏在训练样本的分布里,离线指标根本看不出来,只有随机实验能戳破。

那天晚上我失眠,想的不是修 bug,而是整个决策框架的问题。预测模型的输入是用户和动作,输出是结果概率,可是做决策需要的不是“他会不会买”,而是“相比什么都不做,这么做能多带来多少收益”。多出来的这部分才配叫决策增益,也就是因果效应。想通这层之后,我们决定把决策链路重做。

1.2 相关、干预与因果三个层次

我们把问题分成三个层次:相关关系、干预关系、反事实关系。相关关系只看条件概率 P(转化|发券) 和 P(转化|不发券),发券用户本来就更活跃,这个条件概率天然失衡。干预关系问的是 P(转化|do(发券)),do 表示强制所有用户都发券,因此发券不再是用户自选择的结果,这个概率才反映动作的因果效应。反事实关系则更进一步,问同一批人在另一种选择下会发生什么。

生活里最典型的例子是冰淇淋与溺水。统计数据强烈支持冰淇淋销售越好的日子溺水人数越多,但没有人会因此主张禁止冰淇淋来防止溺水。天气是共同原因:它同时推高气温、游泳人数、冰淇淋销量。观察数据中的相关关系是“被天气污染”的,而干预关系 P(溺水|do(禁止冰淇淋)) 应该等于普通日子的溺水率。AI 决策系统如果不区分这两个概率,就会做出“禁止冰淇淋”式的蠢决定。

1.3 决策系统真正需要回答的反事实问题

把问题落到用户粒度,我们想要的是每个用户 i 的两个潜在结果:Y_i(1) 表示发券后的转化或营收,Y_i(0) 表示不发券的对应值。两者之差 τ_i = Y_i(1)-Y_i(0) 才是动作对用户 i 的个体因果效应。观测数据里每个用户只能处于其中一个分支,这就是所谓“因果推断的根本问题”。

因此平均处理效应 ATE = E[τ_i] 回答“整体上要不要发券”,条件平均处理效应 CATE = E[τ_i | X_i=x] 回答“针对某类用户要不要发券”。一个成熟的决策系统,尤其是基于因果推理的AI决策系统,必须从估计转化率升级为估计处理效应,再结合动作成本做资源分配。这也是后文所有设计的起点。

2. 因果建模框架与关键概念

2.1 两种主流表述体系:结构因果模型与潜在结果框架

动手设计前,团队先统一了因果推理的两个表述体系。结构因果模型把世界描述成一张有向无环图加一组结构方程:节点是变量,边是因果关系。比如活跃度 X 会影响是否发券 T,发券 T 和活跃度 X 都会影响转化 Y,于是有图 X→T、T→Y、X→Y。干预 do(T=t) 的数学含义是切断所有指向 T 的边并赋常数 t,得到的分布 P(Y|do(T=t)) 就是因果效应。

潜在结果框架不画图,而是直接定义每个个体在每种干预下的潜在结果 Y(t)。两者可以换算:在满足一致性、可忽略性等条件下,潜在结果的平均差等于结构因果模型中的后门调整效应。工程实践中我更喜欢混用:用结构因果模型想清楚识别策略,用潜在结果框架指导估计和建模。很多团队纠结学哪套,实际做落地时两边都要会一点,图谱负责沟通,统计模型负责计算。

2.2 从业务问题到因果图的转换方法

画因果图不建议一步到位。我习惯把业务变量先分四类:处理变量 T(比如发券动作、定价、推荐位),结果变量 Y(转化、客单价、复购),混杂变量 X(同时影响 T 和 Y 的变量,比如活跃度、历史价值、季节),以及不能进入模型的对撞变量(比如“是否进入活动页”,它同时受活跃度和发券影响,如果作为控制变量会产生选择偏差)。

实际操作时,先从最简单的图开始:活跃度 → 发券 → 转化,活跃度 → 转化。然后让业务方逐一回答:还有什么变量会同时影响发券和转化?比如“用户上次购买时间”“是否最近浏览过券包”,把能想到的候选边画上。原则上控制变量宁少勿多,只控制那些确实是共同原因的变量,千万不要为了让效果更好看而随便加控制。

变量角色示例处理建议
处理 T是否发券、券面金额决策变量,需要明确干预
结果 Y转化、GMV、复购优化目标,需定义清楚
混杂 X活跃度、历史价值、季节必须控制/调整
对撞变量是否进入活动页不应纳入回归模型

2.3 因果效应识别的基本策略

识别策略解决的是:观测数据中无法直接对同一批人做两次干预,如何用已有分布表示因果效应。最可靠的是随机化,用户被随机分到处理组或对照组,处理后组间差异就是因果效应。但随机实验成本高、周期长,所以观测数据需要后门调整:在给定混杂 X 后,处理 T 和结果 Y 条件独立,此时有公式 P(Y|do(T=t)) = Σ_x P(Y|T=t,X=x)P(X=x)。直观理解是:先估计每个活跃度层的转化率,再按整体活跃度分布加权,还原“如果所有人都被强制发券”的转化率。

如果存在未观测混杂,后门调整失效,需要工具变量或前门准则。工具变量要满足:Z 对 T 有影响,但与未观测混杂独立,并且只通过 T 影响 Y。实际业务里很难找到完美的工具变量,经常只能用来做稳健性检验,不建议作为第一方案。我们最终以随机小流量数据为主,观测数据后门调整作为补充,这个组合在工程上最稳妥。

3. 系统架构设计:把因果引擎嵌进决策链路

3.1 分层架构与核心模块职责

系统整体分成五层:数据接入层、因果知识层、效应估计层、决策引擎层、评估与监控层。数据接入层负责统一采集行为、订单、策略、实验分桶等事件;因果知识层维护变量图谱,包括人工先验和算法挖掘结果;效应估计层离线训练 ATE/CATE 模型,产出可发布的估计器;决策引擎层在线接收候选动作,输出每个动作的增量、置信区间和建议;评估与监控层持续回算增量,和线上实验交叉验证。

我们最终没有把因果引擎设计成替代原来的预测模型,而是让两者并行。预测模型负责输出“不干预时的基准结果”,因果估计器负责输出“干预带来的增量”。决策引擎把增量和基准相加得到处理后的预估,但决策阈值只看增量是否覆盖成本。这种隔离设计让两个模型可以独立迭代,也避免相关性信息污染因果判断。后续在多个场景落地时,这个分层帮了大忙,业务方只需要关注决策引擎返回的增量指标。

3.2 数据管道:观测数据、干预记录与业务日志

数据管道是整个因果系统最容易翻车的地方。我们在项目一开始就强制要求三张表:观测行为表记录用户每次访问和转化事件;干预表记录谁在什么时间收到哪个策略、策略版本号、展示位;随机化表记录用户在哪些实验组、分组权重以及实验状态。干预表和随机化表的差异是天然的分析资源:随机化表告诉我们哪些对比是可信的,干预表则记录真实曝光。

还要把倾向得分也存下来。观测数据在 90 天后可能丢失原始特征,如果当初算过倾向得分 e(X)=P(T=1|X),后面做加权和重叠检查都能还原。数据的时间语义也需要统一:使用策略曝光时间 exposure_time 作为处理发生时刻,使用结果发生时间 outcome_time 作为结果时刻,训练特征必须只使用 exposure_time 之前的信息,避免穿越。这几条守则写进了团队数据开发规范,比模型算法更早落地。

3.3 决策服务接口的输入输出约定

因为因果引擎要同时服务推荐、营销、定价多条业务线,我们把在线接口设计得尽量通用。核心是传入用户、上下文和候选动作,返回每个动作的增量收益估计和置信度。

POST /decision { "user_id": "u_12345", "context": { "page": "cart_checkout", "channel": "app_push", "bucket_id": "exp_20250101_v3" }, "candidates": [ {"action_id": "no_coupon", "cost": 0}, {"action_id": "coupon_5", "cost": 5}, {"action_id": "coupon_10", "cost": 10} ] }

返回体里每个动作给出 expected_lift、ci_lower、ci_upper 和 action_rank。调用方不需要理解因果模型细节,只需按业务成本做最终裁定。为了控制在线资源,决策引擎先查该用户所属分群的预计算 CATE,再用在线特征做增量修正,整体延迟可以压在 30ms 以内。接口上线后,推荐团队和营销团队各自写策略逻辑,完全不用改动底层因果模块。

4. 因果发现与效应估计的工程落地

4.1 因果发现:从业务先验到约束算法

一开始我们试图完全用算法做因果发现。常见思路是约束类算法:从完全无向图开始,根据条件独立性检验逐步删边,再用 v 结构确定方向。这类方法在低维数据上能给出合理候选,但在高维业务数据上很不稳定:检验幂次不够、存在未观测混杂时方向容易错、输出图常常出现循环。我们的处理方式是:以业务先验图作为主结构,把算法输出当副产物,只提醒我们哪些边值得复核。

实操里有一套轻量流程:先用两三次专家研讨画出基准 DAG,每个节点控制变量不超过 20 个;然后对每个处理变量做独立性检验,看候选混杂 X 是否同时与 T、Y 相关;最后把算法给出的每一条边让人工核对。这样既保持数据驱动能力,又不至于被虚假边带偏。上线半年后,基准图只调整过 5 条边,大部分来自新增策略和产品改版,说明前期投入是值得的。

4.2 倾向得分加权与双重稳健估计

当我们决定用观测数据估计平均因果效应时,第一个可靠工具是倾向得分加权。先训练一个模型估计每个用户被发券的概率 e(X),然后对每个实际发券用户按 1/e(X) 加权,对未发券用户按 1/(1-e(X)) 加权,两组的加权平均差就是 IPW 估计量。直观解释:高活跃用户很少被分到对照组,我们要把他们的低权重调高,让对照组在活跃度结构上逼近处理组。

单纯 IPW 有一个风险:e(X) 接近 0 或 1 时权重会爆炸。我们做了三项保护:第一,倾向得分做截断,最小和最大分别限制在 0.05 和 0.95;第二,检查重叠假设,把没有对照支持的处理样本剔除;第三,改用双重稳健估计,同时用梯度提升树建立结果模型 f1(x)、f0(x),再把个体效应 f1(x)-f0(x) 作为回归目标。只要倾向得分模型和结果模型有一个正确,ATE 估计就是一致的,这在工程上非常实用,我们后续大部分观测数据评估都默认用它。

4.3 异质性处理效应:谁该被干预

决策系统最关心的是能不能区分谁该得到补贴,所以 CATE 比 ATE 更关键。我们最早落地的是 T-learner:分别用处理组数据训练一个结果模型 f1(x),对照组数据训练 f0(x),则 CATE 近似等于 f1(x)-f0(x)。它的优点是简单,缺点是两个模型各自学目标噪声,差异有时不稳定。后来又换成 S-learner:把处理变量 T 作为普通特征加入模型,预测时手动把 T 置为 1 和 0 再相减。这两种都在用,线上主要用基于树模型的效应森林,它对效应异质性更敏感。

决策层不是直接看 CATE,而是看期望收益增量。比如某用户如果发券,预期转化率增量是 0.5 个百分点,客单价 100 元,那期望收入增量约 0.5 元;如果券面成本 5 元,收益明显为负,系统就不该发券。反过来,沉睡用户可能增量达到 3.6 个百分点,期望收入增量 3.6 元,虽然还不足以覆盖 5 元成本,但配合复购预期可以再调阈值。我们把 CATE 估计和收益模型解耦,策略层只管算账,模型层只管估计增量,边界非常清楚。

4.4 反事实推理与个体决策生成

所谓反事实推理,就是回答“如果当初不发券,这个用户会不会买”。在线推理时我们无法观察到未被选择的路径,只能依赖模型预测。一个最小实现如下:

def recommend(user_features, candidates): best_action = None best_profit = 0.0 y_base = model_f0.predict(user_features) for action in candidates: y_treated = model_f1.predict(user_features, action) lift = y_treated - y_base profit = lift * expected_order_value(user_features) - action.cost if profit > best_profit: best_profit = profit best_action = action return {"best_action": best_action, "best_profit": best_profit}

这里 model_f0 是“不干预”基准模型,model_f1 是“动作生效后”的结果模型。两者可以是同一个 S-learner 在 T=0、T=1 下的输出,也可以是独立模型。必须注意:如果候选动作的成本花了但没有带来真实增量,profit 会锁定为负,因此系统宁愿不动作。这个逻辑虽然朴素,却把“相关性高但增量低”的坏动作挡在门外,也方便业务方理解每一次策略选择背后的理由。

5. 线上决策引擎的实现细节与性能优化

5.1 模型服务化与特征同步

因果估计器上线后最大的困扰不是算法,而是特征一致性。离线训练时我们用历史特征表,线上却从实时特征服务拿当前值,两边定义不一致会立刻让 CATE 失真。我们的做法是把所有特征写入统一特征注册表,每个特征有全局唯一名字和版本号;离线训练抽取与线上服务同一份特征定义,并做每日数据回放校验。

性能方面,线上把模型拆成两层:基础特征层用缓存和向量检索一次性取回用户画像、商品属性;预测层用一个轻量树模型执行。由于候选动作数量一般不超过 5 个,直接对每个动作做一次前向推理即可,单次请求新增耗时控制在 20ms 以内。我们还把高维特征降维后存入分段哈希表,用用户 id 分片,基本可以水平扩展。这套改造做完后,响应时间几乎没有成为业务瓶颈。

5.2 离线训练与线上推理的一致性保障

因果模型最常见的数据穿越错误是用了未来信息。我们曾出现过一个诡异的线上现象:模型对某用户预测增量特别高,但线下回测却很稳定。后来追查是特征表里包含“是否完成支付”,在曝光日前去特征服务会被填充默认值,离线却用了真实过去数据。从那以后,特征服务在每个用户请求时额外返回 as_of_time 字段,训练代码只允许使用 as_of_time 之前的状态,否则直接丢弃这行样本。

更新频率也要设置。倾向得分模型可以每天更新,CATE 模型每周更新一次,更新前用上一周的随机实验数据计算标准化均差,如果特征分布差异超过 0.1 就暂停发布。我们留了一个开关:一旦置信区间覆盖率下降或线上增量回算异常,可以秒级切回上一版本模型,避免极端情况影响正常业务。这套机制后来救过我们一次,新版本模型在灰度时对低活跃用户增量严重高估,回滚开关三分钟就完成了切换。

5.3 冷启动与数据稀疏时的降级方案

新产品或新策略上线时没有历史干预数据,任何因果估计都无从谈起。我们采用三层降级:最底层是业务兜底规则,比如新客默认发 3 元券;中间层是用相似策略迁移来的效应估计结果做先验,然后缓慢释放随机流量;最上层才是完整的在线因果引擎。随机探索流量大小由功效分析决定,比如预期最小增量 1 个百分点、转化率波动 15%,至少需要几千个样本才能识别,因此我们在头两周先放 5% 流量做随机对照,积累够了再切因果模型。

需要特别提醒:不要为了尽快拿到数据就把探索流量开到很大,这会把成本浪费在大量无效用户上。更好的方式是先小范围人工圈定高潜力人群,在这个人群里做严格随机,再逐步扩展人群边界。每次扩展都重新做重叠假设和样本量检查。冷启动期最容易收到“为什么只有少量用户看到新策略”的投诉,但只要解释清楚这样做能更快做对决策,大多数业务方都能接受。

6. 评估体系设计:如何验证因果效应估计得准

6.1 反事实验证:用历史策略构造校验集

因果效应没有真实标签,如何验证是整套系统最容易陷入玄学的环节。我们自己的做法是建立“黄金测试集”:从已经完成的随机实验中提取一份数据,处理组和对照组都完整。然后遮住实验分组,只用实验前的观测特征去训练或更新一段时期的因果模型,最后将模型估计出的 ATE/CATE 与该实验实际结果比对。误差控制在预设阈值内,模型才允许上线。

具体操作上,我们把历史上 12 个小型随机实验的数据保留为测试集,其中 6 个训练、6 个测试。测试时主要看两个指标:ATE 绝对误差和 CATE 排序相关性。如果模型对高 CATE 人群的排序和真实实验一致,即使绝对量低估,决策层做资源分配依然有效。这个思路后来成为每次发布前的必过关卡,也让模型迭代从“感觉对了”变成“有据可依”。

6.2 与线上 A/B 测试的配合方式

因果引擎上线不能替代 A/B 测试,而是互补。普通 A/B 只能验证平均效应,我们额外设计了分层 A/B:先由因果模型把用户分成高增量、低增量、负增量三层,再在各层内分别做随机实验。这样既验证了模型方向,也能算出各层的真实增益。低流量时用准实验补位,比如基于历史时间窗口做双重差分模型,但这些结论要弱很多,只能作为辅助证据。

上线后的前两周是蜜月期,也是最容易出假象的时期。系统会根据历史特征决策,用户发券与否已经由模型干预产生,此时直接对比发券/不发券用户的转化率完全失真。必须依赖随机桶:系统在请求时刻决定是否平分成两组,一组走因果引擎,一组走原业务规则,用最终 GMV 或复购作为大结局指标。只要随机桶的比例固定,结论就能避开选择偏差的干扰。

6.3 敏感性分析与稳健性检查

无论怎么调整,未观测混杂都不可能完全剔除。所以每个因果模型发布前还要做敏感性分析:假设存在一个未观测变量 U,它同时影响处理和结果,要强到什么程度才会让我们的结论翻转。我们计算 E-value 这类指数,结论是如果效应在 U 的某种强度下仍然存在,那么置信度较高;如果 U 只要稍微影响结果就足以消除效应,说明模型很脆弱,不建议上线。

同时我们会跑多个模型,IPW 每天更新、双重稳健每周更新、双重差分季度跑一次,三个估计结果相互对照。如果某个增量估计在不同模型间差异超过 2 个百分点,宁愿先不发策略也不强行解释。这个阈值不是论文里的标准,是我们业务经验里总结出的可操作规则,但确实帮我们挡了几次错误决策。评估这件事没有终点,每上线一个新策略,我们都会把真实反馈再送回黄金测试集,不断校准。

7. 踩过的坑与团队协作经验

7.1 因果发现算法在千万级特征上的一次翻车

年初组里一位同事希望完全自动化:把两万个特征直接喂给因果发现算法,让它自动产出因果图。任务跑了一整夜,第二天输出一张几乎全通的图,算法认为大多数变量都有边连接,根本无法解释。后来发现原因有两层:一是高维下条件独立性检验大量误判,二是特征间本来就有强相关不代表因果关系。浪费了大量算力之后,我们把策略改为先人工圈定 30 个业务变量,再降维成 8 个综合因子,最后才做候选边检测。

这个教训值得说三遍:因果发现算法是给专家审查用,不是给系统自动决策用。尤其当业务方已经知道“活跃度会影响转化”这类知识时,强行让数据重新发现一遍,还不如把知识写进因果图更可靠。现在团队内部把业务先验当成一等公民,数据挖掘结果只是建议,所有图结构变更都必须过评审。

7.2 选择偏差与自选择效应

真实业务里,用户是否参与营销活动往往由用户自己决定。我们复盘过某个清仓活动,业务方汇报参与用户转化率高出未参与用户近 30%,听起来像活动效果爆炸。但仔细看数据,参与用户中近一半本来就在近 30 天内登录过 10 次以上,属于自然要买的用户。用倾向得分加权后,真实增量只有 5% 左右,其中高活跃用户甚至接近 0。这是典型的选择偏差:活动效果被“谁更愿意参加”污染。

处理选择偏差没有银弹:最好的办法是活动上线时就设随机对照,其次是用倾向得分做加权或匹配,再次是用双重差分看活动前后两组的变化差。我们后来规定,凡是需要对外汇报策略效果的结论,必须附带对照设计描述,否则一律按相关关系处理,不许当成因果。这个规则让业务复盘质量提升了一大截,因为每一次汇报都要先讲清楚对照组是怎么设的。

7.3 业务方如何理解“因果效应”而不是“相关性”

和业务方沟通因果,最忌讳一上来就讲图模型和潜在结果。我们用了一个很朴素的词:净增量。每次策略复盘只给一张增量表,讲清楚哪些用户“本来就会买”,哪些用户“因为动作才买”。下面是我们常用的汇报模板:

用户分层处理组转化率对照组转化率净增量
高活跃15.2%14.9%0.3pp
沉睡用户8.7%5.1%3.6pp
新客6.0%5.8%0.2pp

这张表一放,业务方立刻明白高活跃用户的券是纯成本,沉睡用户才是值得倾斜资源的人。“增量”这个词的好处是它既不否定转化率数字,又把它放到正确的决策坐标里。团队内部还约定,任何报告里不准写“转化率提升了 X%”这种模糊表述,必须写“相对不干预净增量提升 X 个百分点”。刚开始大家不习惯,但坚持一个季度后,讨论质量明显提高。

7.4 最小可行闭环:从单策略到复杂生态

如果让我重来一次,我不会一开始就搭一个全家桶式因果推理平台,而是先选定一个高价值决策点,跑通最小闭环。我们的第一个闭环落在优惠券发放上,具体步骤是:一,确定决策变量为 0/5/10 元券;二,在确认页加埋点并设置 5% 随机对照流量;三,用两周数据训练倾向得分和结果模型;四,产出每个用户的 CATE 和推荐动作;五,上线分层 A/B 验证增量。整个闭环从启动到验证大概花了 6 周,比想像中快。

有了第一个可复用的模板后,定价、推荐位、资源位这些场景基本是复制粘贴,差别主要在目标和成本函数。真正限制系统速度的从来不是算法,而是数据纪律:每个策略是否留随机流量、每次干预是否记录版本、每个复盘是否区分净增量。这些约定比模型调参重要一个数量级,也是我被问到“因果推理项目从哪里开始”时永远会给出的答案。

最后分享一条个人体会:因果推理做决策系统,最大的障碍不是模型不会,而是组织常常沉溺于可解释的相关性。只要团队能接受“很多漂亮的策略效果只是自选择”,并且愿意为每个策略留出干净的小流量实验,这套系统就能真正成为决策基础设施。我现在每天最关心的事,已经不是某个模型 AUC 涨了多少,而是随机流量够不够、增量报表有没有被业务方读错、负面人群有没有及时止损。决策系统的质量,最终要由它避免的每一个错误干预来证明。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询