"""前向链推理机(InferenceEngine)单元测试。""" from router_system.inference import InferenceEngine, render_template from router_system.knowledge import KnowledgeBase, Rule from router_system.memory import WorkingMemory def _engine(): return InferenceEngine(KnowledgeBase()) def test_forward_chain_fires_rules(): eng = _engine() mem = WorkingMemory() eng.initialize("求解方程 x^2 - 5x + 6 = 0", "math", "medium", 0.9, mem) fired = eng.run("求解方程 x^2 - 5x + 6 = 0", "math", mem) assert fired, "数学查询应触发规则" # 优先级最高的 math-equation 最先触发 assert fired[0] == "math-equation" # 轨迹包含规则记录 assert any(t.startswith("rule:") for t in mem.trace) def test_no_match_terminates(): eng = _engine() mem = WorkingMemory() eng.initialize("今天天气怎么样", "general", "medium", 0.5, mem) fired = eng.run("今天天气怎么样", "general", mem) assert fired == [] def test_max_steps_limit(): eng = _engine() mem = WorkingMemory() eng.initialize("求解方程 x^2 - 5x + 6 = 0", "math", "medium", 0.9, mem) fired = eng.run("求解方程 x^2 - 5x + 6 = 0", "math", mem, max_steps=1) assert len(fired) == 1 def test_blackboard_facts_written(): eng = _engine() mem = WorkingMemory() eng.initialize("求解方程 x^2 - 5x + 6 = 0", "math", "hard", 0.95, mem) assert mem.get_fact("domain") == "math" assert mem.get_fact("difficulty") == "hard" assert "init:" in mem.trace[0] def test_rule_output_renders_section(): kb = KnowledgeBase() # 注入一条带 output 模板的规则 kb._rules["test-rule"] = Rule( id="test-rule", domain="general", priority=10, patterns=["测试渲染"], output="领域={facts.domain} 查询={query}", ) eng = InferenceEngine(kb) mem = WorkingMemory() eng.initialize("测试渲染一下", "general", "easy", 0.6, mem) fired = eng.run("测试渲染一下", "general", mem) assert "test-rule" in fired section = mem.section("test-rule") assert section is not None assert "领域=general" in section assert "查询=测试渲染一下" in section def test_render_missing_placeholder(): out = render_template("你好 {query} {facts.缺失字段}", "世界", {}) assert "你好 世界 [未提供]" == out