首页 / 第八章
08专家系统
专家系统是人工智能从实验室走向产业的第一个成功范式:它把人类专家的经验沉淀为知识库, 用推理机模拟专家的问题求解过程。本章构建三个可运行的系统—— 动物识别、目标驱动的假设验证、带可信度的医疗分诊——并实现"为什么"的解释能力。
8.1 专家系统概述
◈ 定义
专家系统(Expert System)是一种在特定领域内,运用领域专家的知识与推理能力, 解决原本需要人类专家才能解决的复杂问题的智能计算机程序系统。
专家系统的特点
- 知识与推理分离:知识库与推理机相互独立,改知识不必改程序;
- 透明性:能解释自己的推理过程(回答"为什么 Why""怎么得出的 How");
- 启发性:不仅能用逻辑知识,还能用经验性、不确定的启发知识;
- 高性能与灵活性:在狭窄领域达到专家水平,知识可不断扩充。
| 对比项 | 传统程序 | 专家系统 |
|---|---|---|
| 处理对象 | 数据 | 知识 |
| 求解方式 | 按固定算法 | 启发式推理 + 搜索 |
| 知识与控制 | 混在一起 | 知识库与推理机分离 |
| 结果特征 | 精确、唯一 | 可能不精确、可解释、多假设 |
| 解释能力 | 无 | 有 Why / How 解释 |
里程碑式的系统
- DENDRAL(1965):根据质谱数据推断化学分子结构,第一个专家系统;
- MYCIN(1972):细菌感染诊断与抗生素处方,可信度模型的源头;
- XCON/R1(1980):DEC 公司计算机配置系统,每年节省数千万美元,开启专家系统产业;
- PROSPECTOR:矿产勘探,曾成功预测钼矿。
8.2 专家系统的结构
一个完整的专家系统通常由六部分组成:
知识库
存放领域知识(事实、规则),是专家能力的来源,与推理机分离。
综合数据库
又称工作存储器,存放当前问题的事实与推理中间结论。
推理机
调度知识进行推理的程序:匹配、冲突消解、执行(正向/反向/混合)。
解释机构
记录推理路径,回答用户"为什么问这个""结论怎么来的"。
知识获取机构
把专家知识转化为知识库内容(人工或半自动机器学习)。
人机接口
用户、领域专家与系统交互的界面。
8.3 专家系统的开发过程
- 需求分析与领域选择:选择边界清晰、专家知识可形式化、确有高价值的狭窄领域;
- 知识获取:通过访谈、案例分析从专家处提炼事实与规则(最困难的瓶颈环节);
- 知识表示与知识库设计:选定产生式、框架等表示法,设计规则结构;
- 推理机与原型实现:确定推理方向、冲突消解、不确定处理;
- 测试评估:用真实案例验证准确率与解释合理性,反复修订知识库;
- 维护与扩充:知识随业务持续更新。
8.4 实战一:正向推理动物识别专家系统
动物识别是经典教学案例。系统根据观察到的特征(毛发、食性、颜色斑纹……), 经 15 条产生式规则逐步推出动物类别,并给出完整推理链解释(How)。
"""动物识别专家系统:正向推理 + 冲突消解 + 推理链解释"""
class Rule:
def __init__(self, rid, conditions, conclusion, desc):
self.id = rid
self.conditions = set(conditions)
self.conclusion = conclusion
self.desc = desc
class AnimalExpertSystem:
def __init__(self):
self.facts = set()
self.rules = []
self.trace = [] # 推理记录:(规则, 结论)
def load_knowledge(self):
R = [
Rule("R1", ["有毛发"], "哺乳动物", "有毛发的是哺乳动物"),
Rule("R2", ["有奶"], "哺乳动物", "有奶的是哺乳动物"),
Rule("R3", ["有羽毛"], "鸟类", "有羽毛的是鸟"),
Rule("R4", ["会飞", "会下蛋"], "鸟类", "会飞且会下蛋的是鸟"),
Rule("R5", ["吃肉"], "食肉动物", "吃肉的是食肉动物"),
Rule("R6", ["有犬齿", "有爪", "眼盯前方"], "食肉动物", "肉食性齿爪特征"),
Rule("R7", ["哺乳动物", "有蹄"], "有蹄类动物", "有蹄的哺乳动物"),
Rule("R8", ["哺乳动物", "反刍"], "有蹄类动物", "反刍的哺乳动物"),
Rule("R9", ["哺乳动物", "食肉动物", "黄褐色", "有暗斑点"], "金钱豹", "金钱豹识别规则"),
Rule("R10", ["哺乳动物", "食肉动物", "黄褐色", "有黑色条纹"], "老虎", "老虎识别规则"),
Rule("R11", ["有蹄类动物", "长脖子", "长腿", "有暗斑点"], "长颈鹿", "长颈鹿识别规则"),
Rule("R12", ["有蹄类动物", "有黑色条纹"], "斑马", "斑马识别规则"),
Rule("R13", ["鸟类", "长脖子", "长腿", "不会飞", "黑白二色"], "鸵鸟", "鸵鸟识别规则"),
Rule("R14", ["鸟类", "会游泳", "不会飞", "黑白二色"], "企鹅", "企鹅识别规则"),
Rule("R15", ["鸟类", "善飞"], "信天翁", "信天翁识别规则"),
]
self.rules = R
return self
def run(self, observations):
"""正向推理:数据驱动,直到无新事实。"""
self.facts = set(observations)
fired = set()
changed = True
while changed:
changed = False
candidates = [r for r in self.rules
if r.id not in fired and r.conditions <= self.facts]
if candidates:
rule = sorted(candidates, key=lambda r: r.id)[0] # 编号优先的冲突消解
self.facts.add(rule.conclusion)
fired.add(rule.id)
self.trace.append(rule)
changed = True
def how(self, target):
"""解释目标结论是如何得到的。"""
print(f"\n【How 解释】结论「{target}」的推理过程:")
chain = [r for r in self.trace if r.conclusion == target]
if not chain:
print(" 该结论未被推出(属于初始事实或证据不足)。")
return
r = chain[0]
print(f" 由规则 {r.id}:{r.desc}")
print(f" 因为满足条件:{sorted(r.conditions)}")
for cond in r.conditions:
src = [x for x in self.trace if x.conclusion == cond]
if src:
print(f" 其中「{cond}」由规则 {src[0].id} 推出:{src[0].desc}")
else:
print(f" 其中「{cond}」是你提供的观察事实")
if __name__ == "__main__":
es = AnimalExpertSystem().load_knowledge()
obs = ["有毛发", "吃肉", "黄褐色", "有黑色条纹"]
print("观察到的特征:", obs)
es.run(obs)
animals = {"金钱豹", "老虎", "长颈鹿", "斑马", "鸵鸟", "企鹅", "信天翁"}
found = es.facts & animals
print("识别结果:", found if found else "特征不足,无法识别具体动物")
if found:
es.how(next(iter(found)))
观察到的特征: ['有毛发', '吃肉', '黄褐色', '有黑色条纹']
识别结果: {'老虎'}
【How 解释】结论「老虎」的推理过程:
由规则 R10:老虎识别规则
因为满足条件:['哺乳动物', '食肉动物', '黄褐色', '有黑色条纹']
其中「哺乳动物」由规则 R1 推出:有毛发的是哺乳动物
其中「食肉动物」由规则 R5 推出:吃肉的是食肉动物
其中「黄褐色」是你提供的观察事实
其中「有黑色条纹」是你提供的观察事实
解释器把推理链完整回放给用户——这正是专家系统区别于"黑箱"模型的重要价值, 在医疗、金融等需要审计的场景尤为关键。
8.5 实战二:反向推理(目标驱动)专家系统
诊断类任务往往先有假设("是不是老虎?""是不是肺炎?"), 再去找证据。反向推理从假设目标出发,匹配结论为该目标的规则,递归验证其前提; 无法由规则推出的前提就向用户提问,并能回答"你为什么问这个(Why)"。
"""反向推理专家系统:假设-验证 + Why 解释(答案预置,便于演示)"""
class BackwardExpert:
def __init__(self, rules, user_answers):
# rules: [(前提集合, 结论, 规则号)]
self.rules = rules
self.user_answers = user_answers # 模拟用户对提问的回答 {事实: True/False}
self.known = {} # 已确认事实缓存
self.questions = []
def prove(self, goal, reason=None):
"""尝试证明 goal 为真;reason 记录'为什么需要它',用于 Why 解释。"""
if goal in self.known:
return self.known[goal]
why = f"(为了验证「{reason}」)" if reason else ""
# 1) 寻找结论=goal 的规则,逐条尝试
for conds, concl, rid in self.rules:
if concl != goal:
continue
if all(self.prove(c, goal) for c in conds):
self.known[goal] = True
print(f"✓ 规则 {rid} 成立:{sorted(conds)} => 「{goal}」")
return True
# 2) 没有可用规则,向用户询问
answer = self.ask(goal, why)
self.known[goal] = answer
return answer
def ask(self, fact, why):
self.questions.append(fact)
ans = self.user_answers.get(fact, False)
print(f"提问:是否观察到「{fact}」?{why} -> 用户回答:{'是' if ans else '否'}")
return ans
if __name__ == "__main__":
rules = [
({"有毛发"}, "哺乳动物", "R1"),
({"有奶"}, "哺乳动物", "R2"),
({"吃肉"}, "食肉动物", "R5"),
({"哺乳动物", "食肉动物", "黄褐色", "有黑色条纹"}, "老虎", "R10"),
({"哺乳动物", "食肉动物", "黄褐色", "有暗斑点"}, "金钱豹", "R9"),
]
# 用户只观察到了这些特征(其余问题回答"否")
answers = {"有毛发": True, "吃肉": True, "黄褐色": True, "有黑色条纹": True}
es = BackwardExpert(rules, answers)
hypothesis = "老虎"
print(f"提出假设:该动物是「{hypothesis}」,开始反向求证……\n")
result = es.prove(hypothesis)
print(f"\n假设「{hypothesis}」{'成立 ✔' if result else '不成立 ✘'}")
print(f"系统共向用户确认了 {len(es.questions)} 个原始特征问题")
提出假设:该动物是「老虎」,开始反向求证…… 提问:是否观察到「有毛发」?(为了验证「老虎」) -> 用户回答:是 ✓ 规则 R1 成立:['有毛发'] => 「哺乳动物」 提问:是否观察到「吃肉」?(为了验证「老虎」) -> 用户回答:是 ✓ 规则 R5 成立:['吃肉'] => 「食肉动物」 提问:是否观察到「黄褐色」?(为了验证「老虎」) -> 用户回答:是 提问:是否观察到「有黑色条纹」?(为了验证「老虎」) -> 用户回答:是 ✓ 规则 R10 成立:['哺乳动物', '食肉动物', '黄褐色', '有黑色条纹'] => 「老虎」 假设「老虎」成立 ✔ 系统共向用户确认了 4 个原始特征问题
反向推理只询问与当前假设相关的问题,不收集无关信息,提问目的性强, 非常适合医疗诊断、故障排查。实践中常采用正反向混合:先用少量事实正向触发候选假设, 再对候选逐一反向求证。
8.6 实战三:带可信度的医疗分诊系统
真实症状与诊断之间不是非黑即白。把第五章的可信度模型嵌入专家系统: 规则带强度 CF、症状带观察可信度,推理后输出带置信度排序的多个诊断与建议, 这才接近 MYCIN 的实际形态。
"""不确定专家系统:CF 模型 + 多假设排序 + 解释(教学演示,非真实医疗建议)"""
def cf_and(a, b):
return min(a, b)
def cf_combine(cf1, cf2):
if cf1 >= 0 and cf2 >= 0:
return cf1 + cf2 - cf1 * cf2
if cf1 < 0 and cf2 < 0:
return cf1 + cf2 + cf1 * cf2
return (cf1 + cf2) / (1 - min(abs(cf1), abs(cf2)))
class MedicalExpert:
def __init__(self):
# (前提症状集合, 结论, 规则强度 CF, 解释)
self.rules = [
({"高烧", "咽痛", "无咳嗽"}, "普通感冒", 0.45, "高热咽痛但少咳"),
({"低烧", "鼻塞", "打喷嚏"}, "普通感冒", 0.55, "典型上呼吸道卡他症状"),
({"高烧", "肌肉酸痛", "突发寒战"}, "流感", 0.80, "流感样症状群"),
({"咳嗽", "高烧", "呼吸困难"}, "肺炎", 0.75, "下呼吸道受累征象"),
({"咳嗽", "持续两周以上", "午后低热"}, "肺结核", 0.70, "慢性消耗性表现"),
]
def diagnose(self, symptoms_cf):
"""symptoms_cf: {症状: 观察可信度 0~1}"""
results = {}
evidence = {}
for conds, disease, rule_cf, note in self.rules:
if not conds <= set(symptoms_cf):
continue
e_cf = cf_and(*[symptoms_cf[c] for c in conds])
cf = rule_cf * e_cf # 不确定性传递
evidence.setdefault(disease, []).append((cf, conds, note, rule_cf))
results[disease] = (cf_combine(results[disease], cf)
if disease in results else cf)
print("症状输入:", symptoms_cf, "\n")
ranked = sorted(results.items(), key=lambda kv: -kv[1])
for i, (disease, cf) in enumerate(ranked, 1):
level = ("高度可能" if cf >= 0.7 else "可能"
if cf >= 0.4 else "不能排除")
print(f"{i}. {disease}:CF = {cf:.2f}({level})")
for c, conds, note, rc in evidence[disease]:
print(f" 依据 {sorted(conds)},规则强度 {rc},"
f"本次贡献 {c:.2f}({note})")
return ranked
if __name__ == "__main__":
es = MedicalExpert()
patient = {"高烧": 0.9, "肌肉酸痛": 0.8, "突发寒战": 0.7,
"咳嗽": 0.6, "呼吸困难": 0.5}
es.diagnose(patient)
print("\n建议:系统输出为辅助参考,确诊需结合化验与影像检查。")
症状输入: {'高烧': 0.9, '肌肉酸痛': 0.8, '突发寒战': 0.7, '咳嗽': 0.6, '呼吸困难': 0.5}
1. 流感:CF = 0.56(可能)
依据 ['突发寒战', '肌肉酸痛', '高烧'],规则强度 0.8,本次贡献 0.56(流感样症状群)
2. 肺炎:CF = 0.38(不能排除)
依据 ['呼吸困难', '咳嗽', '高烧'],规则强度 0.75,本次贡献 0.38(下呼吸道受累征象)
建议:系统输出为辅助参考,确诊需结合化验与影像检查。
8.7 专家系统开发工具
- 语言工具:早期专用语言 LISP、Prolog(逻辑推理天然适合);现代多用 Python / Java;
- 外壳(Shell):抽去知识库后留下的推理机+解释器框架,填入新知识即可造新系统,如 EMYCIN("Empty MYCIN")、CLIPS、Jess;
- Python 生态:
pyknow/experta(CLIPS 风格规则引擎)、python-rule-engine、Drools(JVM);本章的手写引擎已涵盖其核心原理; - 现代形态:规则引擎与机器学习结合(规则保证可解释与合规、模型处理感知类任务), 以及检索增强生成(RAG)型智能体——用大模型做推理机、用知识库做事实来源,是专家系统在 AI 时代的复兴。
⚠ 专家系统的局限
知识获取瓶颈、规则间冲突与维护困难("知识工程悖论")、缺乏学习能力、处理不了知识库之外的情形。 这些局限正是机器学习与数据驱动方法兴起的原因,而二者结合是当前的主流方向。
本章小结
- 专家系统 = 知识库 + 综合数据库 + 推理机 + 解释器 + 知识获取 + 人机接口,核心特征是知识与推理分离、可解释。
- 正向推理数据驱动,适合预测与监控;反向推理目标驱动、按需提问,适合诊断与排查。
- 冲突消解可按规则优先级、专一性、新鲜度等策略进行。
- 把可信度模型嵌入规则,即得到能输出多假设置信排序的不确定专家系统(MYCIN 范式)。
- 专家系统擅长可解释、高价值的狭窄领域,但受知识获取瓶颈限制;与机器学习/大模型融合是现代发展方向。