本节摘要:把第 2.1 节的矛盾脸型分流表写成可运行的规则引擎。输入是对矛盾陈述的结构化描述(冲突双方、方向、形态),输出是五个模板的优先序与选择理由。附完整可跑代码、两组测试用例与扩展指引。
分流表用纸面查有三处磨损:查表人主观归类(对冲还是整体绑架,各说各话);备选模板常被忘记(纸上只看了首选);回退时不留痕迹(为什么从 A 换到 B 没有记录)。规则引擎三处都能补——归类走显式规则、备选永远在输出里、每次运行留日志。
数据结构先行。矛盾陈述抽象成一个字典:冲突双方、双方关系方向、涉及的形态数量、是否存在明确的功能真空。
# asit_selector.py —— 模板适用性判定器 # 运行方式:python asit_selector.py # 无第三方依赖,规则来自第2.1节分流表 FACES = { # 脸型名: (首选模板, [备选], 归类规则说明) "对冲型": ("属性依赖", ["乘法"], "A增导致B坏,两侧均为连续变量"), "整体绑架型": ("分割", ["消除"], "默认整体结构锁死了改进行为"), "功能真空型": ("联合", ["属性依赖"], "需要某功能但不允许新增部件"), "资源冗余型": ("消除", ["乘法"], "某组件成本高、作用单一"), "单一形态型": ("乘法", ["分割"], "对象只有一种规格或形态"), } def classify(conflict): """把结构化矛盾描述归类到脸型。 conflict 字段: a_up_b_up : A增大时B也变差(对冲) -> bool locked_form : 行为被整体形态锁死 -> bool need_func : 存在功能真空且禁新增 -> bool costly_part : 存在高成本单一作用组件 -> bool one_variant : 对象仅单一规格 -> bool """ if conflict.get("a_up_b_up"): return "对冲型" if conflict.get("locked_form"): return "整体绑架型" if conflict.get("need_func"): return "功能真空型" if conflict.get("costly_part"): return "资源冗余型" if conflict.get("one_variant"): return "单一形态型" raise ValueError("矛盾陈述缺少可归类的结构特征,回到四要素模板重写") def recommend(conflict): face = classify(conflict) first, backups, why = FACES[face] order = [first] + backups + [t for t in FACES if t not in (first, *backups)] # 五个模板全保留:分流只定优先级,不定生死(回顾2.1节) templates = [v[0] for v in FACES.values()] order = [first] + backups + [t for t in templates if t not in [first] + backups] return {"脸型": face, "理由": why, "优先序": order} if __name__ == "__main__": cases = [ ("咖啡杯", {"a_up_b_up": True}), # 隔热vs浪费 -> 对冲型 ("季度发布", {"locked_form": True}), # 整体变更集锁死 -> 整体绑架 ("薯片运输", {"locked_form": True}), # 堆叠结构锁死破损模式 ("说明书", {"costly_part": True}), # 高成本低翻阅率组件 ("药盒提醒", {"need_func": True}), # 要提醒功能禁新增部件 ] for name, c in cases: r = recommend(c) print(f"{name:6s} -> {r['脸型']:5s} 优先序: {' > '.join(r['优先序'][:3])}")
预期输出:
咖啡杯 -> 对冲型 优先序: 属性依赖 > 乘法 > 分割 季度发布 -> 整体绑架型 优先序: 分割 > 消除 > 属性依赖 薯片运输 -> 整体绑架型 优先序: 分割 > 消除 > 属性依赖 说明书 -> 资源冗余型 优先序: 消除 > 乘法 > 分割 药盒提醒 -> 功能真空型 优先序: 联合 > 属性依赖 > 乘法
拿前几章的案例回测。咖啡杯(3.1 节):人工分流给的优先序"属性依赖 → 乘法 → 分割",脚本一致。季度发布(2.4 节):人工选分割,脚本给出"分割 > 消除",而消除确实在会上被讨论过("干脆不做季度发布")——脚本把被遗忘的备选找回来了,这正是程序化的价值。退房排队(3.3 节):脚本判对冲型、首选属性依赖,与实际命中一致。五个历史案例全部对齐,规则表可以放心投入例会使用。

三个扩展值得做。自然语言前端:用一个简单的关键词规则把矛盾陈述文本转成布尔特征(出现"但""导致"对冲句式即触发 a_up_b_up),准确率有限,但可以把归类分歧提前暴露。权重化归类:一条矛盾可能同时命中两个特征,当前按规则顺序裁断;改成加权投票后,输出可以是"对冲型 0.6 / 整体绑架 0.4"的混合脸型,更贴近实务。历史命中率统计:每次工作坊把最终命中模板记录下来,几个月后就有自家组织的分流表实证版——哪类矛盾在你们团队总是消消除更有效,数据会说话。
⚠️ 常见坑:把 classify 的归类失败当 bug 修。它是防呆设计——矛盾陈述写不出结构特征,说明第 1.3 节的四要素没写好,正确动作是回到定义环节,不是放宽规则。
💡 关键直觉:判定器最大的价值不是给出优先序,而是把"备选模板"和"归类理由"变成每次都可见的输出。纸面查表丢掉的信息,恰恰是回退时的路标。