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:
tzt
2026-09-18 23:45:35 +08:00
parent 0767030f02
commit 8820e8da48
7 changed files with 103 additions and 41 deletions
+13 -6
View File
@@ -312,6 +312,13 @@ class AgentService:
self.run_dir = Path(run_dir)
self._runs: Dict[str, AgentRunInfo] = {}
self.max_running = 5
self._running = 0 # O(1) 运行计数(原 register 每次全量扫描 _runs
def _transition_state(self, info: AgentRunInfo, new_state: str) -> None:
"""状态迁移的单一入口:离开 running 时同步递减计数。"""
if info.state == STATE_RUNNING and new_state != STATE_RUNNING:
self._running -= 1
info.state = new_state
# ---------- 路径 ----------
def _dir(self, request_id: str) -> Path:
@@ -327,14 +334,14 @@ class AgentService:
def register(self, request_id: str, task: str, model: str, pool_id: str,
workspace: str = "", executor_model: str = "",
mode: str = "single") -> Optional[AgentRunInfo]:
running = [r for r in self._runs.values() if r.state == STATE_RUNNING]
if len(running) >= self.max_running:
if self._running >= self.max_running:
return None
info = AgentRunInfo(request_id=request_id, task=task, model=model,
pool_id=pool_id, workspace=workspace,
executor_model=executor_model, mode=mode,
started_at=time.time())
self._runs[request_id] = info
self._running += 1
self._dir(request_id).mkdir(parents=True, exist_ok=True)
self._write_status(info)
return info
@@ -413,7 +420,7 @@ class AgentService:
throttle.flush("executor")
self._apply_result(info, result)
except Exception as exc: # pragma: no cover
info.state = STATE_FAILED
self._transition_state(info, STATE_FAILED)
info.error = f"{type(exc).__name__}: {exc}"
self._append_event(info, {"type": "final", "round": info.rounds,
"reason": "error", "error": info.error})
@@ -455,14 +462,14 @@ class AgentService:
info.prompt_tokens = int(result.get("prompt_tokens", 0))
info.completion_tokens = int(result.get("completion_tokens", 0))
if result.get("reason") == "error":
info.state = STATE_FAILED
self._transition_state(info, STATE_FAILED)
info.error = result.get("error")
elif result.get("reason") in ("token_cap", "max_rounds", "max_handoffs"):
# 触顶属于护栏行为:结果仍交付,但标记部分完成信息
info.state = STATE_DONE
self._transition_state(info, STATE_DONE)
info.error = result.get("error")
else:
info.state = STATE_DONE
self._transition_state(info, STATE_DONE)
# ---------- 两级模式(D7):规划者 + 执行者 ----------
async def run_dual(self, info: AgentRunInfo, planner_chat: Any, executor_chat: Any,