# Design: session-dedup-knowledge-map ## 1. 整体架构 本 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 做粗粒度检索决策 │ └─────────────────────────────────────────────┘ ``` --- ## 2. 数据结构定义 ### 2.1 Frontmatter 新增字段 ```yaml # 新增两个字段,其余不变 covers: ["支付失败排查", "扣款无回调"] # List:业务场景标签,Planner 决策用 when_to_retrieve: "用户描述支付失败、超时时" # String:文档级检索时机,LLM 上传时生成 ``` 对应 `Frontmatter.java` 新增两个字段: - `List covers` - `String whenToRetrieve` 对应 `KnowledgeEntry.java` 新增两个字段(同上)。 ### 2.2 knowledge_domain 表(新表) ```sql CREATE TABLE knowledge_domain ( id BIGINT AUTO_INCREMENT PRIMARY KEY, domain_id VARCHAR(64) NOT NULL UNIQUE, -- category 值,如 "payment" description VARCHAR(256), -- 域描述(聚合自文档 summary) when_to_retrieve TEXT, -- 域级检索时机(LLM 生成) document_count INT DEFAULT 0, -- 该域当前文档数 updated_at DATETIME, created_at DATETIME ); ``` ### 2.3 knowledge map 结构(注入 Planner 的 YAML 文本) ```yaml available_knowledge_domains: - domain_id: "payment" description: "支付链路问题排查" when_to_retrieve: "用户问题涉及支付、退款、对账时检索;优先检索一次,勿重复" documents: - title: "支付失败排查手册" covers: ["支付超时", "扣款无回调"] - title: "退款处理指南" covers: ["退款未到账", "退款状态异常"] - domain_id: "infrastructure" ... ``` --- ## 3. 新增组件 ### 3.1 KnowledgeDomainService(新类) 职责:域级聚合与存储 ``` buildDomainSummary(category) → 读取同域所有 KnowledgeEntry(含 when_to_retrieve) → 拼装 prompt,调用 LLM → 写入 knowledge_domain 表 buildKnowledgeMap() → 读取所有 knowledge_domain 记录 → 拼装 YAML 文本(含 documents 列表) → 返回 String(供 Planner prompt 注入) onDocumentChange(category) → 调用 buildDomainSummary(category)(只重算受影响域) ``` ### 3.2 RetrievedDocTracker(新类,或内联入 LookupKnowledgeTool) 职责:session 级已召回文档追踪 ``` ConcurrentHashMap> retrieved key: sessionId value: Set isAlreadyRetrieved(sessionId, filePath) → boolean markRetrieved(sessionId, filePath) clearSession(sessionId) ← 由 SessionContextHolder.clear() 触发 ``` --- ## 4. 改动文件清单 | 文件 | 改动类型 | 说明 | |---|---|---| | `LookupResult.java` | 修改 | 新增 `message` 字段(去重提示文本) | | `Frontmatter.java` | 修改 | 新增 `covers`、`whenToRetrieve` | | `KnowledgeEntry.java` | 修改 | 新增 `covers`、`whenToRetrieve` | | `FrontmatterParser.java` | 修改 | 解析新字段 | | `DocumentManagementService.java` | 修改 | upload 时调 LLM 生成文档级字段;upload/delete 后触发域级重算 | | `KnowledgeIndexService.java` | 修改 | loadIndex 时加载域级数据;若域无记录则触发生成 | | `KnowledgeDomainService.java` | 新增 | 域聚合、LLM 调用、DB 读写、buildKnowledgeMap | | `KnowledgeDomain.java`(entity) | 新增 | knowledge_domain 表映射 | | `KnowledgeDomainRepository.java` | 新增 | JPA Repository | | `LookupKnowledgeTool.java` | 修改 | 集成 RetrievedDocTracker,检索前过滤,检索后标记 | | `SessionContextHolder.java` | 修改 | clear() 时通知 RetrievedDocTracker | | `RetrievedDocTracker.java` | 新增 | session 级去重状态管理 | | `ChatService.java` | 修改 | buildChatPlannerAgent 注入 knowledge map | | `chat-planner-prompt.md` | 修改 | 添加 knowledge map 使用规则 | | `V009__add_knowledge_domain.sql` | 新增 | Flyway 建表脚本 | --- ## 5. 关键决策记录 1. **域级 when_to_retrieve 存 DB**:避免每次重启调 LLM;文档变更时只重算受影响域 2. **文档级 when_to_retrieve 存 metadata JSON**:沿用现有 frontmatter 存储路径,无需新字段 3. **RetrievedDocTracker 独立于 SessionContextHolder**:SessionContextHolder 只持有 sessionId,Tracker 是业务状态,职责分离;clear() 时通过 Tracker.clearSession() 联动 4. **Planner 只看域级**:文档级 when_to_retrieve 留 Executor 筛选(Phase 2),MVP 不暴露给 Planner 5. **LLM 调用同步执行**:上传时同步生成,接受约 1-2s 延迟,保证数据库和 L0 索引立即一致