文章目录
- 前言
- 一、什么是专家系统?
- 二、专家系统的历史与地位
- 三、专家系统的典型架构与组件
- 四、知识表示方式
- 五、推理策略:前向链与后向链
- 六、示例
-
- [1. 目标](#1. 目标)
- [2. 代码](#2. 代码)
- 说明
- 七、优点与局限
前言
随着人工智能技术多元化发展,专家系统(Expert Systems)作为早期符号AI的重要分支,仍然在许多规则密集型、因果可解释性强的场景中保持价值。
一、什么是专家系统?
专家系统是一类模拟人类专家在特定领域决策过程的软件系统。其典型目标是将"领域知识"编码为可执行形式,使系统能在特定问题上给出建议或判断。与机器学习依赖大量数据不同,专家系统强调显式知识表示 和可解释的推理过程。
关键特点:
- 知识可解释、来源通常是专家或领域文档。
- 适合规则明确、决策路径能被表达为规则或模型的领域(如诊断、配置、故障排查、法律咨询辅助等)。
- 推理过程透明,可以给出"为什么这样结论"的解释。
二、专家系统的历史与地位
专家系统兴起于20世纪70--80年代(代表系统:MYCIN、DENDRAL),推动了早期AI工程化。1990年代后,统计学习与神经网络兴起,但专家系统在需要强可解释性、规则确定性的领域仍有应用,例如医疗诊断辅助、设备故障定位、合规审核、配置管理等。
三、专家系统的典型架构与组件
-
知识库(Knowledge Base)
存储领域知识,常见形式:规则(if-then)、事实(事实集合)、框架(frame)、语义网络等。
-
推理机 / 推理引擎(Inference Engine)
执行知识的应用,常见推理方法:前向链(forward chaining,数据驱动)、后向链(backward chaining,目标驱动)。
-
工作记忆 / 事实库(Working Memory / Fact Base)
存储当前已知事实,推理机读取并修改。
-
解释器 / 解释子系统(Explanation Subsystem)
能够说明某条结论是如何由哪些规则与事实推导出来,提升可解释性与信任。
-
知识获取接口(Knowledge Acquisition)
与专家交互,将领域知识编码进知识库。是专家系统工程中最困难的环节(知识获取瓶颈)。
-
用户接口(User Interface)
与用户交互、展示推荐、接受问题与事实输入。
四、知识表示方式
-
产生式规则(if condition then action) :最常见,易于理解与维护。
例:
IF 症状 = 发烧 AND 咳嗽 THEN 可能 = 呼吸道感染 -
事实 / 断言(facts/assertions) :例如
age(张三, 35)、has_symptom(病人, fever)。 -
框架(Frame) 与 对象模型:用于表示对象及其属性和默认值。
-
语义网络 / 本体(ontology):用于表示实体及其关系,便于复杂语义检索。
设计准则:简洁、可扩展、能被推理机高效匹配。
五、推理策略:前向链与后向链
-
前向链(Forward chaining):从已知事实出发,应用规则产生新事实,直到无法再推导或达到目标。适用于数据驱动的场景(如传感器告警推理)。
-
后向链(Backward chaining):从目标(要证明的命题)倒推需要哪些事实或子目标,常用于决策支持和问答系统(例如Prolog的查询机制)。
实现时常见问题:冲突解决(多个规则同时可触发时如何选择),循环检测(避免无限推导),优先级与权重控制,事实撤销/回溯策略。
六、示例
1. 目标
实现一个"简易医疗诊断"专家系统原型。用户输入一组症状,系统运用规则推导可能的诊断,并能输出推理路径(哪些规则与事实导致结论)。
2. 代码
python
"""
simple_expert.py
一个简化的前向链规则引擎实现,包含解释追踪功能。
"""
from typing import Any, Dict, List, Tuple, Callable, Set
import pprint
# 事实用简单的 key->value 形式或 set of tuples 表示
# 规则使用字典表示:{"name": str, "conditions": List[callable], "action": callable, "priority": int}
# 为了易用,这里条件函数接受 facts 并返回 bool,action 接受 facts 并可能添加新事实
class SimpleEngine:
def __init__(self):
self.facts: Set[Tuple[str, Any]] = set() # 例如: ("has_symptom", "fever")
self.rules: List[Dict] = []
self.explanation: List[str] = [] # 记录触发的规则与原因
def assert_fact(self, key: str, value: Any):
fact = (key, value)
if fact not in self.facts:
self.facts.add(fact)
# For tracing:
self.explanation.append(f"断言事实: {fact}")
def add_rule(self, name: str, conditions: List[Callable[['SimpleEngine'], bool]],
action: Callable[['SimpleEngine'], bool], priority: int = 0):
self.rules.append({
"name": name, "conditions": conditions, "action": action, "priority": priority
})
# 定义规则后保持按优先级排序(高优先级先触发)
self.rules.sort(key=lambda r: r["priority"], reverse=True)
def _conditions_met(self, rule: Dict) -> bool:
return all(cond(self) for cond in rule["conditions"])
def run(self, max_cycles: int = 100):
cycle = 0
fired_any = True
while fired_any and cycle < max_cycles:
fired_any = False
for rule in self.rules:
if self._conditions_met(rule):
fired_any = True
self.explanation.append(f"规则触发: {rule['name']}")
changed = rule["action"](self) # action 返回 True 表示添加了新事实
if changed:
self.explanation.append(f"规则 {rule['name']} 导致事实变更")
else:
self.explanation.append(f"规则 {rule['name']} 未引入新事实(已存在或无新增)")
# 简化处理:一次触发后重新开始规则扫描(避免饥饿、保证优先级效果)
break
cycle += 1
if cycle >= max_cycles:
self.explanation.append("达到最大推理循环次数,终止。")
def has_fact(self, key: str, value: Any) -> bool:
return (key, value) in self.facts
def pretty_facts(self):
return sorted(list(self.facts))
def pretty_explanation(self):
return "\n".join(self.explanation)
# -------------------------
# 以下定义领域:简化医疗诊断
# -------------------------
def make_medical_engine():
engine = SimpleEngine()
# 条件辅助
def has_sym(sym):
return lambda eng: eng.has_fact("symptom", sym)
def assert_diagnosis(diagnosis):
def action(eng: SimpleEngine) -> bool:
if not eng.has_fact("diagnosis", diagnosis):
eng.assert_fact("diagnosis", diagnosis)
return True
return False
return action
# 规则示例:发烧 + 咳嗽 -> 可能呼吸道感染
engine.add_rule(
name="r_resp_infect",
conditions=[has_sym("fever"), has_sym("cough")],
action=assert_diagnosis("respiratory_infection"),
priority=10
)
# 规则:发烧 + 头痛 -> 可能流感
engine.add_rule(
name="r_flu",
conditions=[has_sym("fever"), has_sym("headache")],
action=assert_diagnosis("influenza"),
priority=8
)
# 规则:咳嗽但无发烧 -> 可能过敏或轻微炎症
engine.add_rule(
name="r_allergy",
conditions=[has_sym("cough"), lambda eng: not eng.has_fact("symptom", "fever")],
action=assert_diagnosis("allergy_or_mild_inflammation"),
priority=5
)
# 规则:如果诊断为呼吸道感染且有呼吸困难 -> 标记为需要紧急处理
engine.add_rule(
name="r_emergency",
conditions=[lambda eng: eng.has_fact("diagnosis", "respiratory_infection"),
has_sym("shortness_of_breath")],
action=lambda eng: (eng.assert_fact("action", "seek_emergency_care") or True),
priority=20
)
return engine
# -------------------------
# 演示
# -------------------------
if __name__ == "__main__":
e = make_medical_engine()
# 输入事实(来自用户或问诊)
e.assert_fact("symptom", "fever")
e.assert_fact("symptom", "cough")
# 运行推理
e.run()
print("事实集:")
pprint.pprint(e.pretty_facts())
print("\n推理说明:")
print(e.pretty_explanation())
说明
SimpleEngine管理事实(self.facts)和规则(self.rules),并记录self.explanation用于输出推理过程。- 规则以
conditions(一组布尔函数)与action(修改事实的函数)形式表示;优先级控制规则触发顺序。 - 推理采用循环扫描规则、触发第一个满足条件的规则、执行其 action、记录解释、然后重新扫描(简单而易理解的冲突解决)。
- 示例领域为"简化医疗诊断",展示如何把症状断言进事实库并由规则推导诊断与动作(例如"需要就医")。
七、优点与局限
优点:
- 强可解释性,推理链明确;
- 业务规则可直接表达并由领域专家维护;
- 在规则明确的领域效率高、开发周期短。
局限:
- 知识获取与维护昂贵(需要领域专家持续投入);
- 难以处理高维、噪声大或隐含模式的任务(这些适合统计/深度学习方法);
- 难以扩展到极大规模规则集合(需配合高效匹配算法与工程化手段)。