feat(v1): 架构与算法优化——语义缓存 2.37x、Router 去重、分类器确定性决胜

架构:
- Router:低置信度直连/专家异常两条兜底路径的收尾逻辑(回退→finalize→record)提取为
  _fallback_result 公共方法,消除三处重复收尾块

算法:
- RouterCache:语义条目写入时预计算向量范数(原每次两两比较重算)、
  语义查找单遍完成(原命中后二次 O(N) 查找)、相似度=1.0 提前终止扫描;
  微基准(3000 条目×200 查询):3986ms -> 1685ms,2.37x
- RuleClassifier:同分决胜改为按领域名字典序(与规则表排列顺序无关的确定性)、
  次高分由全排序改 O(n) 扫描

测试:新增 5 项(缓存范数一致性/提升后无残留/淘汰同步清理、决胜确定性、区分度惩罚)
pytest 25 passed(原 20 全绿 + 新增 5)
基线检查点:66b6fd8(操作前已提交,20 passed)
This commit is contained in:
tzt
2026-09-18 08:10:02 +08:00
parent 66b6fd8c3e
commit 9fdf91c2fb
6 changed files with 481 additions and 404 deletions
+36
View File
@@ -1,6 +1,42 @@
from router_system.cache import RouterCache
def test_semantic_lookup_after_many_entries():
"""多条目下语义命中正确(范数预计算 + 单遍扫描的回归)。"""
c = RouterCache(similarity_threshold=0.5)
for i in range(50):
c.put(f"完全不相关的查询主题编号{i}关于烹饪的意见", {"response": f"r{i}"})
c.put("用 Python 实现快速排序函数", {"response": "code-answer"})
level, got = c.get("用 Python 实现快速排序的函数写法") # 相似但不完全相同
assert level in ("semantic", "exact")
assert got["response"] == "code-answer"
def test_promotion_clears_semantic_state():
"""提升为精确缓存后,语义列表与范数索引无残留。"""
c = RouterCache(promote_frequency=2)
c.put("查询甲", {"response": "a"})
first = c.get("查询甲") # 相似度=1.0 计 exacthits 达阈值即提升
assert first is not None and first[0] == "exact"
second = c.get("查询甲")
assert second is not None and second[0] == "exact"
assert c.stats()["exact_size"] == 1
assert c.stats()["semantic_size"] == 0
assert len(c._sem_norms) == 0
def test_semantic_eviction_clears_norms():
"""语义缓存满员淘汰最旧条目时,向量与范数索引同步清理。"""
c = RouterCache(max_semantic=2)
c.put("查询一", {"response": "1"})
c.put("查询二", {"response": "2"})
c.put("查询三", {"response": "3"}) # 淘汰查询一
assert len(c._semantic) == 2
assert len(c._sem_vecs) == 2
assert len(c._sem_norms) == 2
assert c.get("查询一") is None
def test_exact_hit():
c = RouterCache()
result = {"response": "hello", "domain": "general"}
+63 -44
View File
@@ -1,44 +1,63 @@
"""分类器单元测试。"""
from router_system.classifier import RuleClassifier
def test_code_classification():
clf = RuleClassifier()
r = clf.classify("用 Python 写一个快速排序函数")
assert r.domain == "code"
assert r.confidence > 0.7
def test_math_classification():
clf = RuleClassifier()
r = clf.classify("求解方程 x^2 - 5x + 6 = 0")
assert r.domain == "math"
assert r.confidence > 0.7
def test_legal_classification():
clf = RuleClassifier()
r = clf.classify("劳动合同到期不续签需要支付经济补偿吗")
assert r.domain == "legal"
def test_medical_classification():
clf = RuleClassifier()
r = clf.classify("高血压患者日常饮食需要注意什么")
assert r.domain == "medical"
def test_general_low_confidence():
clf = RuleClassifier()
r = clf.classify("今天天气怎么样")
# 未命中任何领域 -> 低置信度,触发 should_fallback
assert r.domain == "general"
assert clf.should_fallback(r, 0.6) is True
def test_difficulty_estimation():
clf = RuleClassifier()
easy = clf.classify("1 + 1 = ?")
hard = clf.classify("证明费马大定理并推导其推论,给出详细步骤")
assert hard.difficulty in ("medium", "hard")
assert easy.difficulty == "easy"
"""分类器单元测试。"""
from router_system.classifier import RuleClassifier
def test_tie_break_is_deterministic():
"""同分决胜:按领域名字典序,与规则表排列顺序无关。"""
clf = RuleClassifier()
clf.rules = {"zeta": [("x", 1.0)], "alpha": [("x", 1.0)]}
r = clf.classify("x")
assert r.domain == "alpha"
def test_distinctiveness_penalty():
"""次高分占比高(语义含混)时置信度被压低;单一领域命中不受影响。"""
clf = RuleClassifier()
clf.rules = {"a": [("kw", 1.0)], "b": [("kw", 0.9)]}
r_ambiguous = clf.classify("kw")
clf_clear = RuleClassifier()
clf_clear.rules = {"a": [("kw", 1.0)], "b": [("other", 0.1)]}
r_clear = clf_clear.classify("kw")
assert r_clear.confidence > r_ambiguous.confidence
def test_code_classification():
clf = RuleClassifier()
r = clf.classify("用 Python 写一个快速排序函数")
assert r.domain == "code"
assert r.confidence > 0.7
def test_math_classification():
clf = RuleClassifier()
r = clf.classify("求解方程 x^2 - 5x + 6 = 0")
assert r.domain == "math"
assert r.confidence > 0.7
def test_legal_classification():
clf = RuleClassifier()
r = clf.classify("劳动合同到期不续签需要支付经济补偿吗")
assert r.domain == "legal"
def test_medical_classification():
clf = RuleClassifier()
r = clf.classify("高血压患者日常饮食需要注意什么")
assert r.domain == "medical"
def test_general_low_confidence():
clf = RuleClassifier()
r = clf.classify("今天天气怎么样")
# 未命中任何领域 -> 低置信度,触发 should_fallback
assert r.domain == "general"
assert clf.should_fallback(r, 0.6) is True
def test_difficulty_estimation():
clf = RuleClassifier()
easy = clf.classify("1 + 1 = ?")
hard = clf.classify("证明费马大定理并推导其推论,给出详细步骤")
assert hard.difficulty in ("medium", "hard")
assert easy.difficulty == "easy"