From 2a7164288f8b8da6930ad2d153c850fb3bc44556 Mon Sep 17 00:00:00 2001 From: zhuyongxin Date: Wed, 1 Jul 2026 18:28:19 +0800 Subject: [PATCH] =?UTF-8?q?chore(docs):=20=E8=A1=A5=E5=85=85=20ISS-001=20?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=E8=AE=BE=E8=AE=A1=E6=96=87=E6=A1=A3=E5=88=B0?= =?UTF-8?q?=20mvp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 mvp/architecture/session-dedup-knowledge-map.md - 更新 mvp/README.md 文档导航 - ISS-001 issue 关联架构文档 --- mvp/README.md | 1 + .../session-dedup-knowledge-map.md | 188 ++++++++++++++++++ mvp/issues/ISS-001-duplicate-retrieval.md | 1 + 3 files changed, 190 insertions(+) create mode 100644 mvp/architecture/session-dedup-knowledge-map.md diff --git a/mvp/README.md b/mvp/README.md index e52162c..7e59281 100644 --- a/mvp/README.md +++ b/mvp/README.md @@ -13,6 +13,7 @@ - [知识库检索使用指南](architecture/knowledge-retrieval-usage.md) - 文档编写和使用说明 ⭐新增 - [会话管理](architecture/session-management.md) - Redis + MySQL 会话管理 - [实施规划](architecture/implementation-plan.md) - 分阶段实施计划 +- [会话级去重与知识域地图](architecture/session-dedup-knowledge-map.md) - 文档级去重 + Planner 知识域地图注入解决 ISS-001 ⭐新增 - [证据评分与用户反馈](architecture/confidence-feedback.md) - evidence_score 规则引擎 + feedback API ⭐新增 - [行动记忆与检索归一化](architecture/action-memory-relevance.md) - Executor 行动记忆 + 归一化质量等级解决 ISS-002 ⭐新增 diff --git a/mvp/architecture/session-dedup-knowledge-map.md b/mvp/architecture/session-dedup-knowledge-map.md new file mode 100644 index 0000000..aa9e60f --- /dev/null +++ b/mvp/architecture/session-dedup-knowledge-map.md @@ -0,0 +1,188 @@ +# 会话级去重与知识域地图 + +文档级去重 + 知识域地图注入 Planner,解决 ISS-001 Executor 重复召回同一文档问题。 + +--- + +## 一、整体架构 + +本 change 包含两个独立但互补的部分: + +``` +Part A: 工具层去重 + LookupKnowledgeTool + ├── 维护 ConcurrentHashMap>(JVM 内) + ├── 每次检索前过滤已召回文档 + └── SessionContextHolder.clear() 时同步清理 + +Part B: 知识域地图 + ┌─────────────────────────────────────────────┐ + │ 文档上传 (DocumentManagementService) │ + │ → LLM 生成 doc.covers + doc.when_to_retrieve │ + │ → 存入 api_document.metadata │ + │ → 触发域级重算 (KnowledgeDomainService) │ + └─────────────────────────────────────────────┘ + ↓ + ┌─────────────────────────────────────────────┐ + │ 域级聚合 (KnowledgeDomainService) │ + │ → 读取同域所有文档的 when_to_retrieve │ + │ → LLM 生成 domain.when_to_retrieve │ + │ → 存入 knowledge_domain 表 │ + └─────────────────────────────────────────────┘ + ↓ + ┌─────────────────────────────────────────────┐ + │ 启动 (KnowledgeIndexService.loadIndex) │ + │ → 加载 knowledge_domain 表 │ + │ → 某域无记录则触发域级生成 │ + └─────────────────────────────────────────────┘ + ↓ + ┌─────────────────────────────────────────────┐ + │ Planner prompt (ChatService) │ + │ → 注入 knowledge map(域级) │ + │ → Planner 做粗粒度检索决策 │ + └─────────────────────────────────────────────┘ +``` + +--- + +## 二、Part A:工具层去重 + +### RetrievedDocTracker + +session 级已召回文档追踪组件,将去重责任从 LLM 移交到工具层。 + +```java +ConcurrentHashMap> retrieved + key: sessionId + value: Set +``` + +| 方法 | 作用 | +|------|------| +| `isAlreadyRetrieved(sessionId, filePath)` | 检查文档是否已召回 | +| `markRetrieved(sessionId, filePath)` | 记录已召回文档 | +| `clearSession(sessionId)` | 清理会话记录(SessionContextHolder.clear 触发) | + +### 去重流程 + +``` +lookup_knowledge(query) + → L0 检索 → 命中一批文档 + → 遍历结果,过滤 isAlreadyRetrieved=true 的文档 + → 剩余文档作为 primary/supplement 返回 + → 实际返回的文档调用 markRetrieved +``` + +--- + +## 三、Part B:知识域地图 + +### Frontmatter 新增字段 + +文档上传时 LLM 自动生成以下两个字段: + +```yaml +covers: ["支付失败排查", "扣款无回调"] # 业务场景标签 +when_to_retrieve: "用户描述支付失败、超时时" # 文档级检索时机 +``` + +### knowledge_domain 表 + +```sql +CREATE TABLE knowledge_domain ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + domain_id VARCHAR(64) NOT NULL UNIQUE, + description VARCHAR(256), + when_to_retrieve TEXT, + document_count INT DEFAULT 0, + updated_at DATETIME, + created_at DATETIME +); +``` + +### Knowledge Map(注入 Planner 的 YAML) + +```yaml +available_knowledge_domains: + - domain_id: "payment" + description: "支付链路问题排查" + when_to_retrieve: "用户问题涉及支付、退款、对账时检索;优先检索一次,勿重复" + documents: + - title: "支付失败排查手册" + covers: ["支付超时", "扣款无回调"] + - title: "退款处理指南" + covers: ["退款未到账", "退款状态异常"] + - domain_id: "infrastructure" + ... +``` + +### 注入链路 + +``` +文档上传/删除 + → KnowledgeDomainService.onDocumentChange(category) + → 读取同域所有文档的 when_to_retrieve + → LLM 聚合为 domain.when_to_retrieve + → 写入 knowledge_domain 表 + +应用启动 + → KnowledgeIndexService.loadIndex() + → 加载 knowledge_domain → 无记录则触发聚合 + → ChatService.buildChatPlannerAgent() 注入 prompt + +Planner prompt 中包含知识域地图 + → Planner 做粗粒度检索决策("查 payment 域") + → Executor 收到步骤后执行具体检索 +``` + +--- + +## 四、关键设计决策 + +| 决策 | 方案 | 原因 | +|------|------|------| +| 域级 when_to_retrieve 存 DB | 持久化 | 避免每次重启调 LLM,文档变更时只重算受影响域 | +| 文档级 when_to_retrieve 存 metadata JSON | 沿用现有路径 | 无需新增数据库字段 | +| RetrievedDocTracker 独立于 SessionContextHolder | 职责分离 | SessionContextHolder 只持有 sessionId,Tracker 是业务状态 | +| Planner 只看域级 | 分层决策 | 文档级 when_to_retrieve 留 Executor 筛选(Phase 2) | +| LLM 调用同步执行 | 上传时即时生成 | 接受约 1-2s 延迟,保证数据库和 L0 索引立即一致 | + +--- + +## 五、Agent 边界 + +``` +Planner 角色:知道"有什么域" + └─ 知识域地图:选定要检索的域(一次规划) + +Executor 角色:知道"做了什么" + └─ 行动记忆:域级 + 文档级去重(ISS-002 升级为双层记忆) +``` + +Part B(知识域地图)只注入 Planner prompt,**不注入 Executor prompt**。Executor 只通过 RetrievedDocTracker 知道自己已检索了哪些文档,不需要知道全局域有哪些。 + +--- + +## 六、数据库变更 + +### V009 + +```sql +CREATE TABLE knowledge_domain ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + domain_id VARCHAR(64) NOT NULL UNIQUE, + description VARCHAR(256), + when_to_retrieve TEXT, + document_count INT DEFAULT 0, + updated_at DATETIME, + created_at DATETIME +); +``` + +--- + +## 七、参考资料 + +- **架构文档**:`mvp/architecture/knowledge-retrieval-architecture.md` +- **使用指南**:`mvp/architecture/knowledge-retrieval-usage.md` +- **OpenSpec**:`openspec/changes/archive/2026-06-30-session-dedup-knowledge-map/` diff --git a/mvp/issues/ISS-001-duplicate-retrieval.md b/mvp/issues/ISS-001-duplicate-retrieval.md index 74b6fc0..4ff23c6 100644 --- a/mvp/issues/ISS-001-duplicate-retrieval.md +++ b/mvp/issues/ISS-001-duplicate-retrieval.md @@ -4,6 +4,7 @@ **严重程度**:中(影响 token 消耗和上下文质量,不影响功能正确性) **发现时间**:2026-06-30 **修复版本**:session-dedup-knowledge-map +**架构文档**:[会话级去重与知识域地图](../architecture/session-dedup-knowledge-map.md) ---