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:
@@ -0,0 +1,83 @@
|
||||
# Decisions: executor-action-memory-relevance
|
||||
|
||||
## 过程日志
|
||||
|
||||
### Clarify 阶段
|
||||
|
||||
**入口摘要**:ISS-002 Executor 无约束重复调用 lookup_knowledge(单会话 20+ 次),需要行动记忆 + 归一化质量等级 + prompt 约束来解决。
|
||||
|
||||
**slug**: `executor-action-memory-relevance`
|
||||
|
||||
**规模分档**: `standard`(涉及 7 个文件,跨 DTO/工具层/持久化/Prompt,有设计决策需澄清)
|
||||
|
||||
### Context 阶段
|
||||
|
||||
**devflow/index.md 使用状态**: 已命中。前序 change `session-dedup-knowledge-map`(archived)提供了 RetrievedDocTracker、KnowledgeDomainService、ISS-002 文档。
|
||||
|
||||
**相关 ADR**: 无直接 ADR,但 `session-dedup-knowledge-map` 的 decisions.md 和 evidence.md 记录了文档级去重和 knowledge map 注入的决策。
|
||||
|
||||
**不能违反的历史决策**:
|
||||
1. RetrievedDocTracker 的文档级去重必须保留
|
||||
2. knowledge map 只注入 Planner,不注入 Executor(本次讨论确认)
|
||||
3. L0/L1 原始分数不暴露给 LLM,只在归一化层内部使用(本次讨论确认)
|
||||
|
||||
**需进入 OpenSpec 的上下文点**:
|
||||
1. L1 score 是 L2 距离(值域 [0,+∞)),不是归一化分数——阈值设计需基于实际分布
|
||||
2. L0 的 category 可从 KnowledgeEntry.getCategory() 直接获取;L1 需解析 metadata JSON
|
||||
3. ReactAgent 是自主决策工具调用的 Agent,Prompt 约束是软约束
|
||||
|
||||
### Grill 阶段 — Question Pool
|
||||
|
||||
**维度:术语**
|
||||
1. [evidence-driven] `relevanceLevel` 三个等级(PRECISE/HIGHLY_RELEVANT/REFERENCE)的边界是否清晰,是否存在 LLM 误解的可能? → **已查证**:三个等级语义明确,PRECISE=唯一匹配、HIGHLY_RELEVANT=高分命中、REFERENCE=低置信度参考。LLM 理解风险低。
|
||||
|
||||
**维度:边界**
|
||||
2. [evidence-driven] L1 score 是 L2 距离(值域 [0,+∞)),当前代码无阈值判断。归一化阈值如何设计? → **已查证**:L2 距离典型范围取决于 BGE-M3 1024 维 embedding 的尺度,需从 `tool_invocation.retrieval_details` 中查询实际 `l1_scores` 分布才能定阈值。当前先以常量定义,标记为"需实测校准"。
|
||||
3. [evidence-driven] L1 结果的 category 提取需要解析 metadata JSON 字符串,当前 `SearchResult.metadata` 是 `toString()` 的结果。归一化层是否需要 L1 的 domain? → **已查证**:L1 的 domain 主要用于 RetrievedDocTracker 的域级记录。如果 L0 已命中且包含 category,可直接用 L0 的 category;如果仅 L1 命中,需解析 metadata 提取 category。当前知识库中 L0 大概率先命中,L1 domain 提取作为兜底路径。
|
||||
4. [user-interview] 归一化阈值(L1 score 分界线)在实测数据不足时,是否接受先用保守初始值 + 后续调优的策略? → **用户待确认**
|
||||
|
||||
**维度:验收**
|
||||
5. [evidence-driven] 现有 `tool_invocation` 表 `retrieval_details` JSON 中 `l1_scores` 存的是 L2 距离原始值,新增的 `relevance_level` 和 `completeness_hint` 入库后是否需要回填历史数据? → **已查证**:不需要回填历史数据,新列 nullable 即可,历史记录 relevance_level=null。
|
||||
|
||||
### Grill 结论
|
||||
|
||||
**evidence-driven 汇报**:
|
||||
- E1: relevanceLevel 三等级语义清晰,LLM 误解风险低
|
||||
- E2: L1 score 是 L2 距离,值域不固定,阈值需实测校准
|
||||
- E3: L0 category 直接可用,L1 category 需解析 metadata(兜底路径)
|
||||
- E4: 历史数据不回填,新列 nullable
|
||||
|
||||
**user-interview 已确认**:
|
||||
- Q4: 归一化阈值先用保守初始值 + 后续调优 → **用户已确认**,并建议用 Min-Max 归一化到 [0,1]
|
||||
|
||||
### Specify 阶段补充
|
||||
|
||||
**BGE-M3 L2 归一化实测验证**:
|
||||
- FullPipelineSmokeTest.embeddingBgeM3Works() 新增 L2 范数断言
|
||||
- 结果:范数=1.00000002,误差 < 0.01,测试通过
|
||||
- 结论:BGE-M3 输出为 L2 归一化单位向量,L2 距离数学硬上界 = 2.0
|
||||
- Min-Max 归一化公式:`similarity = 1 - min(l2Score, 2.0) / 2.0`
|
||||
|
||||
**Cross-artifact 对齐检查**:
|
||||
|
||||
| 对齐项 | 状态 |
|
||||
|--------|------|
|
||||
| brief 目标/范围/非目标 → proposal 覆盖 | 已对齐 |
|
||||
| proposal 范围/约束 → design 覆盖 | 已对齐 |
|
||||
| design 归一化/行动记忆/接口影响 → specs 覆盖 | 已对齐 |
|
||||
| specs 可观察行为 → tasks 覆盖 | 已对齐 |
|
||||
|
||||
**接口影响分级**:
|
||||
- RetrievedDocTracker 数据结构升级 → L2(内部接口,消费者只有 LookupKnowledgeTool)
|
||||
- LookupResult 新增 3 字段 → L2(工具返回值,无跨模块调用方)
|
||||
- tool_invocation 新增 2 列 → L2(Flyway nullable,不影响现有查询)
|
||||
- chat-executor-prompt.md 更新 → L1(Prompt 文本变更)
|
||||
|
||||
### Audit 阶段
|
||||
|
||||
**架构风险评估**(5 句以内):
|
||||
1. 归一化层嵌入 LookupKnowledgeTool 内部(静态方法),无跨模块耦合风险。
|
||||
2. RetrievedDocTracker 升级为双层结构,数据量级不变(文档数 × session 数),内存无风险。
|
||||
3. L1 metadata 解析 category 是兜底路径,如果 JSON 格式不一致可能解析失败——已有 try-catch 兜底。
|
||||
4. 归一化阈值 yml 配置化,运行时调优不需要改代码和重启——运维友好。
|
||||
5. Prompt 约束仍依赖 LLM 遵守——如果 Phase 1 效果不足,Phase 2 域级硬限制的 isDomainRetrieved 已就绪,无需额外改造。
|
||||
Reference in New Issue
Block a user