feat(v2): 架构与算法优化二轮——推理机不变量外提、知识库匹配预编译、协作循环增量索引
- inference.py(/chat/legacy 热路径):kb.match 循环不变量外提(原每步全量重扫+重排序, 最坏 O(steps×rules×patterns));fired 查重 list→set - knowledge.py:Rule patterns 注册侧懒缓存小写副本(原每条规则每次匹配重复 lower); match() 文本只 lower 一次(原逐规则重复);load() 的 yaml 文件名集合提到循环外 - worker.py:本地端点生成器 httpx.AsyncClient 懒建复用(原每步新建/销毁连接, 对齐 ArchitectClient 惯用法;协作循环最多 10 次生成免重复建连) - pipeline.py(协作循环):plan_by_id O(1) 步定义查找;done 集合增量维护 (原每轮重建 progress+archive 扫描);领域只解析一次(原 _artifact_name 每步 全领域 kb.match);_deps_done 支持传入预填集合(保持旧签名兼容) - v2stats.py:回合数分布改增量聚合(sum/max/分桶计数),summary() O(n)→O(1), 不再持有无界 list(修长时运行内存增长) - gateway/agent.py + api.py:AgentService 运行计数 O(1) 化(原 register 全量扫描), 状态迁移收敛到 _transition_state 单一入口(api.py cancel/异常两处绕过点一并接入, 消除计数与状态脱节隐患);21 项 agent 测试全绿(两轮全量 230 passed 复核)
This commit is contained in:
@@ -51,13 +51,25 @@ class Rule:
|
||||
actions: List[str] = field(default_factory=list) # 保留字段:动作扩展
|
||||
subdomain: Optional[str] = None # 二级子领域(如 investing/labor/calculus)
|
||||
subdomain2: Optional[str] = None # 三级子领域(如 fund/overtime/sorting)
|
||||
_patterns_lower: Optional[tuple] = field(default=None, repr=False, compare=False)
|
||||
|
||||
def _lowered(self) -> tuple:
|
||||
"""patterns 的小写缓存(注册后规则视为不可变;懒计算一次)。"""
|
||||
if self._patterns_lower is None:
|
||||
self._patterns_lower = tuple(p.lower() for p in self.patterns)
|
||||
return self._patterns_lower
|
||||
|
||||
def matches(self, text: str) -> bool:
|
||||
"""任一 pattern 是 text 的子串即命中(大小写不敏感)。"""
|
||||
if not self.patterns:
|
||||
return False
|
||||
q = text.lower()
|
||||
return any(p.lower() in q for p in self.patterns)
|
||||
return self._match_lower(text.lower())
|
||||
|
||||
def _match_lower(self, q: str) -> bool:
|
||||
"""已 lowercase 文本的快速匹配(避免每条规则重复 lower 同一文本)。"""
|
||||
if not self.patterns:
|
||||
return False
|
||||
return any(p in q for p in self._lowered())
|
||||
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
@@ -420,12 +432,13 @@ class KnowledgeBase:
|
||||
self._facts = {d: [dict(f) for f in facts] for d, facts in BUILTIN_FACTS.items()}
|
||||
|
||||
if self.rules_dir.is_dir():
|
||||
yaml_names = {p.name for p in self.rules_dir.glob("*.yaml")} # 一次遍历,避免逐文件重扫
|
||||
for f in sorted(self.rules_dir.glob("*.yaml")):
|
||||
data = _try_load_yaml(f)
|
||||
if data is not None:
|
||||
self._load_file_data(f, data)
|
||||
for f in sorted(self.rules_dir.glob("*.json")):
|
||||
if f.name not in {p.name for p in self.rules_dir.glob("*.yaml")}:
|
||||
if f.name not in yaml_names:
|
||||
data = _try_load_json(f)
|
||||
if data is not None:
|
||||
self._load_file_data(f, data)
|
||||
@@ -461,12 +474,16 @@ class KnowledgeBase:
|
||||
|
||||
# ---- 查询 ----
|
||||
def match(self, text: str, domain: Optional[str] = None) -> List[Rule]:
|
||||
"""返回命中的规则,按优先级降序。domain 为空则全领域匹配。"""
|
||||
"""返回命中的规则,按优先级降序。domain 为空则全领域匹配。
|
||||
|
||||
文本只 lowercase 一次(原实现每条规则各 lower 一遍)。
|
||||
"""
|
||||
q = text.lower()
|
||||
hits = []
|
||||
for rule in self._rules.values():
|
||||
if domain is not None and rule.domain != domain:
|
||||
continue
|
||||
if rule.matches(text):
|
||||
if rule._match_lower(q):
|
||||
hits.append(rule)
|
||||
hits.sort(key=lambda r: r.priority, reverse=True)
|
||||
return hits
|
||||
|
||||
Reference in New Issue
Block a user