feat(knowledge): Executor 行动记忆 + 归一化质量等级解决 ISS-002 重复检索

- RetrievedDocTracker 升级为域级+文档级双层记录(Map<sessionId, Map<domain, Set<filePath>>>)
- LookupKnowledgeTool 新增 Min-Max 归一化层(BGE-M3 L2 距离→[0,1] similarity)
- 三等级 relevanceLevel:PRECISE / HIGHLY_RELEVANT / REFERENCE + completenessHint 兜底信号
- LookupResult 新增 relevanceLevel、completenessHint、retrievedDomainsThisSession
- Executor prompt 重写:4 条检索约束 + 合法出口不查全不追责,重复检索才惩罚
- 入库可观测性:V010 迁移 + retrieval_details JSON 扩展
- 归档 executor-action-memory-relevance change
This commit is contained in:
zhuyongxin
2026-07-01 18:24:41 +08:00
parent e4f37cb9e6
commit e438df4355
21 changed files with 1076 additions and 88 deletions
@@ -0,0 +1,110 @@
# Functional Spec: executor-action-memory-relevance
## FS-1: L2 距离归一化
### 需求
LookupKnowledgeTool 内部将 L1 的 L2 距离归一化为 [0,1] 区间的 similarity 值,基于 BGE-M3 输出为 L2 归一化单位向量(已实测验证,范数=1.00000002)。
### 可观察行为
- 归一化公式:`similarity = 1 - min(l2Score, maxL2Distance) / maxL2Distance`
- `maxL2Distance` 默认 2.0,可通过 `retrieval.normalization.max-l2-distance` 覆盖
- 归一化阈值可通过 `retrieval.normalization.highly-relevant-threshold` 和 `retrieval.normalization.reference-threshold` 配置
- 归一化计算在 LookupKnowledgeTool 内部完成,不暴露原始分数给 LLM
### 验收标准
- [ ] L2 score=0 → similarity=1.0
- [ ] L2 score=1.0 → similarity=0.5
- [ ] L2 score=2.0 → similarity=0.0
- [ ] L2 score=3.0(超出上界)→ similarity=0.0(min 函数截断)
- [ ] 配置项可通过 yml 覆盖默认值
## FS-2: 归一化质量等级判定
### 需求
基于 L0 匹配数和归一化后的 L1 similarity,输出三等级 relevanceLevel + completenessHint。
### 可观察行为
- L0 唯一匹配 → PRECISE + "知识库中不存在比上述结果更精准的文档"
- L0 命中 + L1 similarity ≥ 0.75 → HIGHLY_RELEVANT + "当前结果已高度相关,继续检索不太可能找到更精准的文档"
- 仅 L1 similarity ≥ 0.75 → HIGHLY_RELEVANT + 对应 hint
- L0 多匹配 + L1 similarity [0.5, 0.75) → REFERENCE + "当前结果为相关参考,如需更精准信息请明确缺少的具体维度"
- 仅 L1 similarity [0.5, 0.75) → REFERENCE + 对应 hint
- L1 similarity < 0.5 → 不视为有效结果
- 无 L0 且无 L1 → found=false
### 验收标准
- [ ] L0 matchCount=1 → relevanceLevel=PRECISE
- [ ] L0 matchCount=2, L1 similarity=0.8 → relevanceLevel=HIGHLY_RELEVANT
- [ ] L0 matchCount=0, L1 similarity=0.8 → relevanceLevel=HIGHLY_RELEVANT
- [ ] L0 matchCount=3, L1 similarity=0.6 → relevanceLevel=REFERENCE
- [ ] L0 matchCount=0, L1 similarity=0.4 → found=false 或 supplement 被过滤
- [ ] 每个 relevanceLevel 对应正确的 completenessHint
## FS-3: 域级行动记忆
### 需求
RetrievedDocTracker 升级为域级 + 文档级双层记录,支持查询当前会话已检索的域列表。
### 可观察行为
- `markRetrieved(sessionId, domain, filePath)` 一次记录两层
- `isDocRetrieved(sessionId, filePath)` 返回文档级去重结果
- `isDomainRetrieved(sessionId, domain)` 返回域级检查结果
- `getRetrievedDomains(sessionId)` 返回已检索域列表
- `clearSession(sessionId)` 清理所有记录
- 现有 `isAlreadyRetrieved(sessionId, filePath)` 语义不变(内部委托给 isDocRetrieved)
### 验收标准
- [ ] markRetrieved("s1", "infrastructure", "a.md") 后,isDocRetrieved("s1", "a.md")=true
- [ ] markRetrieved("s1", "infrastructure", "a.md") 后,isDomainRetrieved("s1", "infrastructure")=true
- [ ] markRetrieved("s1", "infrastructure", "a.md") 后,getRetrievedDomains("s1")=["infrastructure"]
- [ ] markRetrieved("s1", "api", "b.md") 后,getRetrievedDomains("s1")=["infrastructure","api"]
- [ ] clearSession("s1") 后,所有方法返回空/false
- [ ] 线程安全:ConcurrentHashMap + ConcurrentHashMap 内层
## FS-4: LookupResult 返回值扩展
### 需求
LookupResult 新增 relevanceLevel、completenessHint、retrievedDomainsThisSession 三个字段,让 LLM 获得行动记忆和质量信号。
### 可观察行为
- 每次 lookup_knowledge 返回值包含这三个新字段
- PrimaryResult 和 SupplementResult 不变,不暴露原始分数
- 去重拦截时,返回值仍包含 retrievedDomainsThisSession(让 LLM 知道已检索了哪些域)
### 验收标准
- [ ] 正常检索返回时,LookupResult 包含 relevanceLevel + completenessHint + retrievedDomainsThisSession
- [ ] 文档级去重拦截时,LookupResult.message 包含去重提示,retrievedDomainsThisSession 不为 null
- [ ] PrimaryResult 和 SupplementResult 无新增分数字段
## FS-5: Executor Prompt 检索约束
### 需求
重写 chat-executor-prompt.md 的检索规则,从"必须调用工具"改为"基于行动记忆和质量信号判断是否需要检索"。
### 可观察行为
- Prompt 不包含 knowledge map
- Prompt 包含 4 条检索约束(判断重复、重复了该怎么办、合法出口、利用质量信号)
- 原有规则"所有需要外部信息的地方,都必须调用对应的工具"被替换
### 验收标准
- [ ] Executor prompt 不包含 knowledge map 内容
- [ ] Executor prompt 包含"禁止换关键词重新检索"约束
- [ ] Executor prompt 包含"不查全不会被追责"合法出口
- [ ] Executor prompt 包含 relevanceLevel 行为指导
## FS-6: 入库可观测性
### 需求
tool_invocation 表新增 relevance_level 和 dedup_reason 列,retrieval_details JSON 扩展。
### 可观察行为
- 每次 lookup_knowledge 调用后,tool_invocation 记录包含 relevance_level 和 dedup_reason
- retrieval_details JSON 包含 l1_top_similarity(归一化后值)、relevance_level、completeness_hint、retrieved_domains、dedup_reason
- 历史数据新列为 null,不影响现有查询
### 验收标准
- [ ] V010 迁移脚本成功执行
- [ ] 新增 relevance_level 列 VARCHAR(20) nullable
- [ ] 新增 dedup_reason 列 VARCHAR(32) nullable
- [ ] saveToolInvocation() 写入新字段
- [ ] SQL 可查询归一化等级分布:`SELECT relevance_level, COUNT(*) FROM tool_invocation WHERE tool_name='lookup_knowledge' GROUP BY relevance_level`