优化: dag拓扑O(V+E)+前端findToolCall反向遍历

- FR-D1 dag.rs topological_layers + executor.rs run 建 adjacency 索引, O(V·E)→O(V+E)(14测试全绿, 含executor3测)
- FR-R5 useAiEvents findToolCall 正向 O(n²) 改反向遍历(命中最近, 放弃Map索引防陈旧引用)
- AR-6 核查确认已于 f82dd8b 落地(Low失败emit AiToolCallCompleted), 零改动
This commit is contained in:
2026-06-14 22:56:06 +08:00
parent 4a95f6a1e2
commit 4b5f096d1c
3 changed files with 57 additions and 17 deletions

View File

@@ -57,6 +57,16 @@ impl DagExecutor {
tracing::info!("DAG 执行开始,共 {} 层", layers.len());
// 预建入边索引target → 直接前驱列表O(E) 一次构建)
// 避免在内层按节点循环中调用 dag.predecessors()(每次 O(E) 全表扫描,整体 O(V·E))。
let mut adjacency_in: HashMap<NodeId, Vec<NodeId>> = HashMap::new();
for edge in &dag.edges {
adjacency_in
.entry(edge.target.clone())
.or_default()
.push(edge.source.clone());
}
for (layer_idx, layer) in layers.iter().enumerate() {
tracing::info!("执行第 {} 层,共 {} 个节点", layer_idx, layer.len());
@@ -76,11 +86,13 @@ impl DagExecutor {
self.state_machine.set_running(node_id.clone())?;
// 构建节点上下文
// 构建节点上下文:通过入边索引 O(入度) 取前驱,而非 O(E) 全表扫描
let mut inputs = HashMap::new();
for pred_id in dag.predecessors(node_id) {
if let Some(out) = outputs.get(&pred_id) {
inputs.insert(pred_id, out.clone());
if let Some(preds) = adjacency_in.get(node_id) {
for pred_id in preds {
if let Some(out) = outputs.get(pred_id) {
inputs.insert(pred_id.clone(), out.clone());
}
}
}