Files
projectAIpopular/tests/test_rules_external.py
T
tzt 0dad895aac feat(v1): T-R2 采纳 llmrouter「规则文档即配置」——分类规则外置 config/routes.json
- classifier.load_domain_rules():支持 .json(必有)/.yaml(pyyaml 可选,与
  config.py 同一可选依赖纪律);文件按 domain 整域覆盖内置 DOMAIN_RULES
  (与 v2 知识库'文件按 id 覆盖'同一惯例);缺失/格式非法/条目非法整体
  安全回退内置(llmrouter 失败安全思想,规则文档编辑错误不打垮路由)
- build_classifier:cfg.rules_file 显式指定,未指定时约定路径 config/routes.json
  存在即自动加载(约定优于配置,ROUTES.md 精髓:改文档即改行为,可 review 可版本化)
- 新增 tests/test_rules_external.py 5 项;全量 38 passed(33+5)
2026-09-19 09:24:56 +08:00

54 lines
2.3 KiB
Python

"""分类规则外置单元测试(T-R2,采纳 llmrouter「规则文档即配置」设计)。"""
import json
from router_system.classifier import (DOMAIN_RULES, RuleClassifier, build_classifier,
load_domain_rules)
def test_load_missing_file_returns_none(tmp_path):
"""文件缺失:返回 None(调用方回退内置),不抛异常。"""
assert load_domain_rules(tmp_path / "nope.json") is None
def test_external_rules_override_domain(tmp_path):
"""外置文件按 domain 覆盖内置:改写 code 规则即改变路由行为。"""
f = tmp_path / "routes.json"
f.write_text(json.dumps({"code": [["速排", 2.0]]}, ensure_ascii=False),
encoding="utf-8")
rules = load_domain_rules(f)
assert rules is not None and rules["code"] == [("速排", 2.0)]
clf = RuleClassifier()
clf.rules = {**DOMAIN_RULES, **rules}
r = clf.classify("讲讲速排的思路")
assert r.domain == "code"
def test_build_classifier_merges_over_builtin(tmp_path):
"""build_classifier 合并语义:文件只写 legal,其余领域保持内置。"""
f = tmp_path / "routes.json"
f.write_text(json.dumps({"legal": [["劳动合同", 3.0]]}, ensure_ascii=False),
encoding="utf-8")
clf = build_classifier({"type": "rule", "rules_file": str(f)})
assert clf.rules["legal"] == [("劳动合同", 3.0)]
assert clf.rules["code"] == DOMAIN_RULES["code"] # 未覆盖领域保持内置
r = clf.classify("劳动合同到期不续签需要支付经济补偿吗")
assert r.domain == "legal"
def test_malformed_file_falls_back_to_builtin(tmp_path):
"""格式非法:整体回退内置(失败安全,编辑错误不打垮路由)。"""
f = tmp_path / "routes.json"
f.write_text('{"code": [["坏数据", "不是数字"]]}', encoding="utf-8")
assert load_domain_rules(f) is None
clf = build_classifier({"type": "rule", "rules_file": str(f)})
assert clf.rules == DOMAIN_RULES
r = clf.classify("用 Python 写一个快速排序函数")
assert r.domain == "code"
def test_explicit_rules_file_missing_uses_builtin(tmp_path):
"""显式路径不存在:静默回退内置,分类行为不变。"""
clf = build_classifier({"type": "rule", "rules_file": str(tmp_path / "no.json")})
assert clf.rules == DOMAIN_RULES