调用图里有“网关→订单→数据库”,再加上三条同一时刻变红的监控曲线,仍然不能直接得出“网关重试导致数据库锁等待”。共同的流量变化、发布操作或者采样偏差,都可能改变解释。
GraphRAG 适合帮助我们找出相关文档、路径与已知机制。要做干预或反事实,必须再给出可检验的因果假设。DoWhy 的作者把因果分析分为建模、识别、估计和反驳四个步骤,而不是把一张图送给模型就完成归因。原论文
路径是一份待核对的机制清单
先问边从哪里来:RPC 调用、代码依赖、专家确认,还是文本共现。再问边是否有时间范围和版本。一次升级把同步调用改成消息异步化以后,旧图仍可能看起来连通,却已经不适合解释新事故。
反事实还要求固定同一个个体的外生扰动。假设知道某次观测的流量背景与噪声,把重试数改成零以后,其他噪声不能重新抽样,否则比较的不再是同一次事件。若这些扰动无法从观测唯一恢复,就需要给出分布或区间,而不是一个精确到小数点的“挽回概率”。
用一组写明的方程演示,不冒充学出来的因果关系
下面明确假定X=2Z+Ux,Y=3X+Z+Uy。Z同时影响 X 与 Y,是共同原因。先由观测反推噪声,再干预 X;这个程序验证代数计算,不证明这套方程描述了真实微服务。
图中的三种问题不是三级准确率排名:观察描述共变,干预改变机制中的赋值,反事实比较同一噪声下的替代状态。GraphRAG 返回的文本需要说明支持的是哪一层。
def infer_noise(z, x, y): return {"ux": x - 2*z, "uy": y - 3*x - z} def forward(z, noise, intervention_x=None): x = 2*z + noise["ux"] if intervention_x is None else intervention_x y = 3*x + z + noise["uy"] return x, y observed = {"z": 1, "x": 5, "y": 20} u = infer_noise(**observed) assert u == {"ux": 3, "uy": 4} assert forward(observed["z"], u) == (5, 20) cf_x, cf_y = forward(observed["z"], u, intervention_x=0) assert (cf_x, cf_y) == (0, 5) # Same observation, same exogenous noise; do not resample U here. assert u == {"ux": 3, "uy": 4} print("factual Y=20; assumed-model counterfactual Y=5; noise fixed")例子跑通以后,还要验证什么
这段代码已在本地 macOS、CPython 3.9.6 下运行,实际输出为factual Y=20; assumed-model counterfactual Y=5; noise fixed。它验证的是例子中的数据约束与分支,不包含线上服务的吞吐或延迟测量。
未安装 DoWhy、运行因果发现、访问监控或调用模型。系数与观测都是教学构造。真实分析需要检查混杂、可识别性、干预定义与敏感性;若无法支持某条边,应把回答停在相关线索,而不是生成“已定位根因”的报告。
延伸阅读
- DoWhy: An End-to-End Library for Causal Inference:区分建模、识别、估计和反驳,2020 年研究而非当月新发布。
- GraphRAG Global Search:说明图谱社区报告在检索回答中的角色,不赋予其因果识别能力。