# ISS-002 Executor 无约束重复调用 lookup_knowledge **状态**:已修复 **严重程度**:中(工具层去重已拦截重复文档,但调用本身仍浪费 token 和耗时) **发现时间**:2026-07-01 **修复时间**:2026-07-01 **关联**:ISS-001(Part A 已修,Part B 注入范围不足) --- ## 现象 ISS-001 修复后,session 级去重(RetrievedDocTracker)生效,同一文档不再重复召回内容。但 Executor 在单次会话中仍调用 `lookup_knowledge` 20+ 次,大部分被去重拦截返回"已检索过"。 实测日志(session `7c517329`,2026-07-01 13:53): ``` Executor 调用 lookup_knowledge ~20 次 去重拦截 11 次: - infrastructure/mysql-connection-pool.md × 6 - api/payment-errors.md × 5 有效检索仅 2-3 次(首次命中各域时) ``` Executor 用不同的 query 变体反复查同一个域,因为 LLM 觉得"需要更多细节"。 --- ## 根本原因 **knowledge map 和检索约束只注入了 Planner prompt,未注入 Executor prompt。** 当前注入范围: | 组件 | knowledge map | 每域最多一次约束 | |------|:---:|:---:| | Planner prompt | 已注入 | 已注入 | | Executor prompt | **未注入** | **未注入** | 调用链路: ``` Supervisor → Planner:规划一次,输出"查 infrastructure 域 + api 域" Supervisor → Executor:执行步骤(ReactAgent,自主决定调用工具) Executor step 1:lookup("MySQL 连接池配置") → 命中 infrastructure 域 ✓ Executor step 2:lookup("HikariCP 参数调优") → 去重拦截 ✗ Executor step 3:lookup("连接池耗尽排查步骤") → 去重拦截 ✗ Executor step 4:lookup("支付超时排查") → 命中 api 域 ✓ Executor step 5:lookup("ERR_TIMEOUT 错误码") → 去重拦截 ✗ ...(反复用不同变体查同域) ``` Executor 看不到"每个域只查一次"的约束,也不知道已有哪些域被检索过。 --- ## 影响 - **Token 浪费**:每次去重拦截仍需走完 L0+L1 检索流程,再返回"已检索过";LLM 也要处理这个返回信息 - **耗时增加**:每次冗余调用约 400-500ms(L0+L1 检索 + 向量查询),20 次冗余调用浪费约 10s - **LLM 行为低效**:Executor 花大量 step 在重复检索上,而不是基于已有信息推理 --- ## 修法方向 ### 方案 A:Executor prompt 注入 knowledge map + 检索约束 在 `chat-executor-prompt.md` 或 `buildChatExecutorAgent()` 中: 1. 注入 knowledge map(与 Planner 相同的 YAML) 2. 添加规则:"每个域最多调用一次 lookup_knowledge;已检索过的域不要再用不同关键词重复检索" 优点:与 Planner 对齐,LLM 能理解域级边界 缺点:仍依赖 LLM 遵守指令(但比纯 Prompt 约束强,因为有 knowledge map 做锚点) ### 方案 B:工具层硬限制(session + 域级计数) 在 `RetrievedDocTracker` 中增加域级计数:`ConcurrentHashMap>`。 当某域检索次数 > 1 时,直接在 `LookupKnowledgeTool` 入口返回"该域已检索过,不允许再次调用"。 优点:100% 可靠,不依赖 LLM 缺点:需改动 RetrievedDocTracker + LookupKnowledgeTool,需要从 filePath 反查 domain ### 建议 **先做方案 A**(改动小,与已有 knowledge map 注入逻辑一致),观察效果。 如果 LLM 仍不遵守,再升级到方案 B。